From c7906edc1ebd96d05ec5a66f6fa444ebd110c85f Mon Sep 17 00:00:00 2001 From: MAJigsaw77 <77043862+MAJigsaw77@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:32:04 +0200 Subject: [PATCH] Some things * Fixed some other checkstyle issues. * The controls schemes options menu now shows the hitboxes without a gradient to look better. * Attempted to rewrite the tweeing system on the FunkinHint, needs more looking. --- source/funkin/mobile/ui/FunkinButton.hx | 47 +-- source/funkin/mobile/ui/FunkinHitbox.hx | 388 +++++++----------- .../mobile/ui/options/ControlsSchemeMenu.hx | 45 +- .../ui/options/objects/HitboxOptionButton.hx | 13 +- .../ui/options/objects/HitboxShowcase.hx | 8 +- .../ui/options/objects/SchemeMenuButton.hx | 2 +- 6 files changed, 205 insertions(+), 298 deletions(-) diff --git a/source/funkin/mobile/ui/FunkinButton.hx b/source/funkin/mobile/ui/FunkinButton.hx index 2da8d2ec8..7036d2ffa 100644 --- a/source/funkin/mobile/ui/FunkinButton.hx +++ b/source/funkin/mobile/ui/FunkinButton.hx @@ -147,7 +147,6 @@ class FunkinButton extends FunkinSprite implements IFlxInput ignoreDrawDebug = true; #end scrollFactor.set(); - input = new FlxInput(0); } @@ -286,19 +285,18 @@ class FunkinButton extends FunkinSprite implements IFlxInput return isPointInPolygon(polygon, pos, getScreenPosition(_point, camera)); } - @:noCompletion - static function isPointInPolygon(polygon:Array, point:FlxPoint, ?offset:FlxPoint):Bool + static function isPointInPolygon(vertices:Array, point:FlxPoint, ?offset:FlxPoint):Bool { if (offset == null) offset = FlxPoint.weak(); var inside:Bool = false; - final numsPoints:Int = Math.floor(polygon.length / 2); + final numsPoints:Int = Math.floor(vertices.length / 2); for (i in 0...numsPoints) { - final vertex1:FlxPoint = FlxPoint.weak(polygon[i * 2] + offset.x, polygon[i * 2 + 1] + offset.y); - final vertex2:FlxPoint = FlxPoint.weak(polygon[(i + 1) % numsPoints * 2] + offset.x, polygon[(i + 1) % numsPoints * 2 + 1] + offset.y); + final vertex1:FlxPoint = FlxPoint.weak(vertices[i * 2] + offset.x, vertices[i * 2 + 1] + offset.y); + final vertex2:FlxPoint = FlxPoint.weak(vertices[(i + 1) % numsPoints * 2] + offset.x, vertices[(i + 1) % numsPoints * 2 + 1] + offset.y); if (checkRayIntersection(vertex1, vertex2, point)) { @@ -312,7 +310,6 @@ class FunkinButton extends FunkinSprite implements IFlxInput return inside; } - @:noCompletion static inline function checkRayIntersection(vertex1:FlxPoint, vertex2:FlxPoint, point:FlxPoint):Bool { final result:Bool = (vertex1.y > point.y) != (vertex2.y > point.y) @@ -329,17 +326,17 @@ class FunkinButton extends FunkinSprite implements IFlxInput return !(status != FunkinButtonStatus.NORMAL && (!check || (currentInput != null && currentInput.justReleased))); } - function updateStatus(input:IFlxInput):Void + function updateStatus(newInput:IFlxInput):Void { - if (input.justPressed) + if (newInput.justPressed) { - currentInput = input; + currentInput = newInput; onDownHandler(); } else if (status == FunkinButtonStatus.NORMAL && !isBackButton) { - if (input.pressed) + if (newInput.pressed) { onDownHandler(); } @@ -386,19 +383,7 @@ class FunkinButton extends FunkinSprite implements IFlxInput #if FLX_DEBUG public override function drawDebugOnCamera(camera:FlxCamera):Void { - if (isCircle) - { - if (!camera.visible || !camera.exists || !isOnScreen(camera)) return; - - getScreenPosition(_point, camera); - - final gfx:Graphics = beginDrawDebug(camera); - - drawDebugCircleColor(gfx, getDebugBoundingBoxColor(allowCollisions)); - - endDrawDebug(camera); - } - else if (polygon != null && polygon.length >= 6 && polygon.length % 2 == 0) + if (polygon != null && polygon.length >= 6 && polygon.length % 2 == 0) { if (!camera.visible || !camera.exists || !isOnScreen(camera)) return; @@ -410,20 +395,30 @@ class FunkinButton extends FunkinSprite implements IFlxInput endDrawDebug(camera); } + else if (radius > 0) + { + if (!camera.visible || !camera.exists || !isOnScreen(camera)) return; + + getScreenPosition(_point, camera); + + final gfx:Graphics = beginDrawDebug(camera); + + drawDebugCircleColor(gfx, getDebugBoundingBoxColor(allowCollisions)); + + endDrawDebug(camera); + } else { super.drawDebugOnCamera(camera); } } - @:noCompletion function drawDebugCircleColor(gfx:Graphics, color:FlxColor):Void { gfx.lineStyle(2, color, 0.75); gfx.drawCircle(radius, radius, radius); } - @:noCompletion function drawDebugPolygonColor(gfx:Graphics, vertices:Array, color:FlxColor):Void { gfx.lineStyle(2, color, 0.75); diff --git a/source/funkin/mobile/ui/FunkinHitbox.hx b/source/funkin/mobile/ui/FunkinHitbox.hx index 7c9bce18a..d8a2e32d9 100644 --- a/source/funkin/mobile/ui/FunkinHitbox.hx +++ b/source/funkin/mobile/ui/FunkinHitbox.hx @@ -4,7 +4,6 @@ import flixel.FlxG; import flixel.graphics.FlxGraphic; import flixel.group.FlxSpriteGroup; import flixel.input.actions.FlxActionInput; -import flixel.math.FlxPoint; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.util.FlxColor; @@ -13,13 +12,11 @@ import flixel.util.FlxSignal; import funkin.graphics.shaders.HSVShader; import funkin.graphics.FunkinSprite; import funkin.mobile.input.ControlsHandler; -import funkin.mobile.ui.FunkinButton; import funkin.play.notes.NoteDirection; import openfl.display.BitmapData; import openfl.display.Shape; import openfl.geom.Matrix; import openfl.Vector; -import flixel.math.FlxMath; import funkin.data.notestyle.NoteStyleRegistry; import funkin.play.notes.notestyle.NoteStyle; import funkin.data.animation.AnimationData; @@ -43,41 +40,34 @@ class FunkinHint extends FunkinButton * Each style is represented as a key with an associated array of two alpha values: * - The first value corresponds to the alpha when the hint is pressed. * - The second value corresponds to the alpha when the hint is not pressed. - * - * Available styles: - * - `'invisible_till_press'`: The hint is invisible until pressed, then becomes visible. - * Alpha values: [0.3, 0.00001] - * - `'visible_till_press'`: The hint is visible until pressed, and then becomes less visible. - * Alpha values: [0.3, 0.15] */ - @:noCompletion - static final HINT_ALPHA_STYLE:Map> = [INVISIBLE_TILL_PRESS => [0.3, 0.00001], VISIBLE_TILL_PRESS => [0.5, 0.35]]; + static final HINT_ALPHA_STYLE:Map> = [INVISIBLE_TILL_PRESS => [0.3, 0.00001], VISIBLE_TILL_PRESS => [0.35, 0.5]]; /** * The direction of the note associated with the button. */ - @:noCompletion var noteDirection:NoteDirection; /** * The label associated with the button, represented as a `FunkinSprite`. * It is displayed on top of the button. */ - @:noCompletion var label:Null; /** * The HSV shader used to adjust the hue and saturation of the button. */ - @:noCompletion var hsvShader:HSVShader; /** * The tween used to animate the alpha changes of the button. */ - @:noCompletion var alphaTween:Null; + var followTarget:Null; + + var followTargetSize:Bool = false; + public var isPixel:Bool = false; /** @@ -98,149 +88,61 @@ class FunkinHint extends FunkinButton { this.label = new FunkinSprite(x, y); this.label.loadGraphic(label); - - final hintAlpha:Null> = HINT_ALPHA_STYLE.get(INVISIBLE_TILL_PRESS); - - if (hintAlpha != null) this.label.alpha = hintAlpha[0]; } hsvShader = new HSVShader(); hsvShader.hue = 1.0; hsvShader.saturation = 1.0; hsvShader.value = 1.0; - shader = hsvShader; } /** * Initializes alpha tween animations for the button. * - * Sets up handlers for `onDown`, `onUp`, and `onOut` events to modify the button's - * `alpha` property using tweens. Cancels any existing tween when an event occurs - * and creates a new tween to transition the `alpha` property accordingly: - * - `onDown`: Transitions `alpha` to `HINT_ALPHA_DOWN`. - * - `onUp` and `onOut`: Transitions `alpha` to `HINT_ALPHA_UP`. - * - * Uses `FlxEase.circInOut` easing for smooth transitions. + * @param style The alpha style to use. */ public function initTween(style:FunkinHintAlphaStyle):Void { final hintAlpha:Null> = HINT_ALPHA_STYLE.get(style); - if (hintAlpha == null) return; + if (hintAlpha == null || hintAlpha.length < 2) return; - switch (style) + function createTween(targetAlpha:Float, transitionTime:Float, isPressed:Bool):Void { - case INVISIBLE_TILL_PRESS: - onDown.add(function():Void { - if (alphaTween != null) alphaTween.cancel(); + if (alphaTween != null) alphaTween.cancel(); - alphaTween = FlxTween.tween(this, {alpha: hintAlpha[0]}, hintAlpha[1], - { - ease: FlxEase.circInOut, - onUpdate: function(twn:FlxTween):Void { - if (label != null) label.alpha = hintAlpha[0] - (hintAlpha[0] * twn.percent); - } - }); - }); - onUp.add(function():Void { - if (alphaTween != null) alphaTween.cancel(); - - alphaTween = FlxTween.tween(this, {alpha: hintAlpha[1]}, hintAlpha[0], - { - ease: FlxEase.circInOut, - onUpdate: function(twn:FlxTween):Void { - if (label != null) label.alpha = hintAlpha[0] * twn.percent; - } - }); - }); - onOut.add(function():Void { - if (alphaTween != null) alphaTween.cancel(); - - alphaTween = FlxTween.tween(this, {alpha: hintAlpha[1]}, hintAlpha[0], - { - ease: FlxEase.circInOut, - onUpdate: function(twn:FlxTween):Void { - if (label != null) label.alpha = hintAlpha[0] * twn.percent; - } - }); - }); - - alpha = hintAlpha[1]; - case VISIBLE_TILL_PRESS: - onDown.add(function():Void { - if (alphaTween != null) alphaTween.cancel(); - - alphaTween = FlxTween.tween(this, {alpha: hintAlpha[0]}, hintAlpha[1], - { - ease: FlxEase.circInOut, - onUpdate: function(twn:FlxTween):Void { - if (label != null) label.alpha = hintAlpha[0] - (hintAlpha[0] * twn.percent); - } - }); - }); - onUp.add(function():Void { - if (alphaTween != null) alphaTween.cancel(); - - alphaTween = FlxTween.tween(this, {alpha: hintAlpha[1]}, hintAlpha[0], - { - ease: FlxEase.circInOut, - onUpdate: function(twn:FlxTween):Void { - if (label != null) label.alpha = hintAlpha[0] * twn.percent; - } - }); - }); - onOut.add(function():Void { - if (alphaTween != null) alphaTween.cancel(); - - alphaTween = FlxTween.tween(this, {alpha: hintAlpha[1]}, hintAlpha[0], - { - ease: FlxEase.circInOut, - onUpdate: function(twn:FlxTween):Void { - if (label != null) label.alpha = hintAlpha[0] * twn.percent; - } - }); - }); - - alpha = hintAlpha[1]; + if (label != null) + { + alphaTween = FlxTween.tween(this, {alpha: targetAlpha}, transitionTime, + { + ease: FlxEase.circInOut, + onUpdate: function(tween:FlxTween):Void { + label.alpha = isPressed ? targetAlpha - (targetAlpha * tween.percent) : transitionTime * tween.percent; + } + }); + } + else + { + alphaTween = FlxTween.tween(this, {alpha: targetAlpha}, transitionTime, {ease: FlxEase.circInOut}); + } } + + onDown.add(createTween.bind(hintAlpha[0], hintAlpha[1], true)); + onUp.add(createTween.bind(hintAlpha[1], hintAlpha[0], false)); + onOut.add(createTween.bind(hintAlpha[1], hintAlpha[0], false)); + + alpha = hintAlpha[1]; + + if (label != null && hintAlpha != null) label.alpha = hintAlpha[0]; } - var followTarget:Null; - var followTargetSize:Bool = false; - - public function follow(sprite:FunkinSprite, followTargetSize:Bool = true) + public function follow(sprite:FunkinSprite, followTargetSize:Bool = true):Void { this.followTargetSize = followTargetSize; followTarget = sprite; } - override function update(elapsed:Float) - { - super.update(elapsed); - - if (followTarget != null) - { - var widthMultiplier:Float = isPixel ? 1.1 : 1.35; - var heightMultiplier:Float = 4; - var xOffset:Float = isPixel ? 43.265 : 0; - var yOffset:Float = isPixel ? 57.65 : 0; - - // TODO: THIS feels off when playing on regular notes but it's fine for pixel notes? Hard to explain needs more testing - if (followTargetSize) - { - var scaledWidth = followTarget.width * widthMultiplier + (isPixel ? 93.05 : 0); - var scaledHeight = followTarget.height * heightMultiplier + (isPixel ? 118 : 0); - setSize(scaledWidth, scaledHeight); - } - - var newX = (followTarget.x - (followTarget.width * ((widthMultiplier - 1) / 2))) - xOffset; - var newY = (followTarget.y - 80) - yOffset; - - setPosition(newX, newY); - } - } - /** * Desaturates the button, setting its saturation to 0.2. */ @@ -259,6 +161,28 @@ class FunkinHint extends FunkinButton hsvShader.hue = hue; } + public override function update(elapsed:Float):Void + { + super.update(elapsed); + + if (followTarget != null) + { + final widthMultiplier:Float = isPixel ? 1.1 : 1.35; + final heightMultiplier:Float = 4; + + final xOffset:Float = isPixel ? 43.265 : 0; + final yOffset:Float = isPixel ? 57.65 : 0; + + // TODO: THIS feels off when playing on regular notes but it's fine for pixel notes? Hard to explain needs more testing + if (followTargetSize) + { + setSize(followTarget.width * widthMultiplier + (isPixel ? 93.05 : 0), followTarget.height * heightMultiplier + (isPixel ? 118 : 0)); + } + + setPosition((followTarget.x - (followTarget.width * ((widthMultiplier - 1) / 2))) - xOffset, (followTarget.y - 80) - yOffset); + } + } + public override function draw():Void { super.draw(); @@ -291,20 +215,18 @@ class FunkinHint extends FunkinButton super.destroy(); } - @:noCompletion - override function set_x(Value:Float):Float + override function set_x(v:Float):Float { - super.set_x(Value); + super.set_x(v); if (label != null) label.x = x; return x; } - @:noCompletion - override function set_y(Value:Float):Float + override function set_y(v:Float):Float { - super.set_y(Value); + super.set_y(v); if (label != null) label.y = y; @@ -314,16 +236,15 @@ class FunkinHint extends FunkinButton enum abstract FunkinHitboxControlSchemes(String) from String to String { - final FourLanes = 'Four Lanes'; - final DoubleThumbTriangle = 'Double Thumb Triangle'; - final DoubleThumbSquare = 'Double Thumb Square'; - final DoubleThumbDPad = 'Double Thumb DPad'; - final Arrows = 'Arrows'; + var FourLanes = 'Four Lanes'; + var DoubleThumbTriangle = 'Double Thumb Triangle'; + var DoubleThumbSquare = 'Double Thumb Square'; + var DoubleThumbDPad = 'Double Thumb DPad'; + var Arrows = 'Arrows'; } /** - * The `FunkinHitbox` class represents a zone with four buttons, designed to be easily customizable in layout. - * It extends `FlxTypedSpriteGroup` with `FunkinHint` as the type parameter. + * This class represents a zone with four buttons, designed to be easily customizable in layout. */ @:nullSafety class FunkinHitbox extends FlxTypedSpriteGroup @@ -343,18 +264,18 @@ class FunkinHitbox extends FlxTypedSpriteGroup /** * The list of tracked inputs for the hitbox. */ - @:noCompletion var trackedInputs:Array = []; /** * Creates a new `FunkinHitbox` object. */ - public function new(?schemeOverride:String = null, ?directionsOverride:Array = null, ?colorsOverride:Array = null):Void + public function new(?schemeOverride:String, ?showGradint:Bool = true, ?directionsOverride:Array, ?colorsOverride:Array):Void { super(); final hintsColors:Array = (colorsOverride == null || colorsOverride.length == 0) ? [0xFFC34B9A, 0xFF00FFFF, 0xFF12FB06, 0xFFF9393F] : colorsOverride; final hintsNoteDirections:Array = (directionsOverride == null || directionsOverride.length == 0) ? [NoteDirection.LEFT, NoteDirection.DOWN, NoteDirection.UP, NoteDirection.RIGHT] : directionsOverride; + #if mobile final controlsScheme:String = (schemeOverride == null || schemeOverride.length == 0) ? Preferences.controlsScheme : schemeOverride; @@ -365,8 +286,10 @@ class FunkinHitbox extends FlxTypedSpriteGroup final hintHeight:Int = FlxG.height; for (i in 0...hintsNoteDirections.length) + { add(createHintLane(i * hintWidth, 0, hintsNoteDirections[i % hintsNoteDirections.length], hintWidth, hintHeight, - hintsColors[i % hintsColors.length])); + hintsColors[i % hintsColors.length], true, showGradint)); + } case FunkinHitboxControlSchemes.DoubleThumbTriangle: final screenHalf:Int = Math.floor(FlxG.width / 2); @@ -374,10 +297,12 @@ class FunkinHitbox extends FlxTypedSpriteGroup { final xOffset:Int = (i == 1) ? screenHalf : 0; - add(createHintTriangle(xOffset, 0, hintsNoteDirections[0], Math.floor(FlxG.width / 4), FlxG.height, hintsColors[0])); - add(createHintTriangle(xOffset, FlxG.height / 2, hintsNoteDirections[1], Math.floor(FlxG.width / 2), Math.floor(FlxG.height / 2), hintsColors[1])); - add(createHintTriangle(xOffset, 0, hintsNoteDirections[2], Math.floor(FlxG.width / 2), Math.floor(FlxG.height / 2), hintsColors[2])); - add(createHintTriangle(xOffset + Math.floor(FlxG.width / 4), 0, hintsNoteDirections[3], Math.floor(FlxG.width / 4), FlxG.height, hintsColors[3])); + add(createHintTriangle(xOffset, 0, hintsNoteDirections[0], Math.floor(FlxG.width / 4), FlxG.height, hintsColors[0], showGradint)); + add(createHintTriangle(xOffset, FlxG.height / 2, hintsNoteDirections[1], Math.floor(FlxG.width / 2), Math.floor(FlxG.height / 2), hintsColors[1], + showGradint)); + add(createHintTriangle(xOffset, 0, hintsNoteDirections[2], Math.floor(FlxG.width / 2), Math.floor(FlxG.height / 2), hintsColors[2], showGradint)); + add(createHintTriangle(xOffset + Math.floor(FlxG.width / 4), 0, hintsNoteDirections[3], Math.floor(FlxG.width / 4), FlxG.height, hintsColors[3], + showGradint)); } case FunkinHitboxControlSchemes.DoubleThumbSquare: final screenHalf:Int = Math.floor(FlxG.width / 2); @@ -394,11 +319,16 @@ class FunkinHitbox extends FlxTypedSpriteGroup for (j in 0...hintsNoteDirections.length) { - if (j == 1 || j == 2) add(createHintLane(xOffset + hintWidth, (j == 1) ? boxHeight : 0, hintsNoteDirections[j], boxWidth, boxHeight, - hintsColors[j % hintsColors.length], false)); + if (j == 1 || j == 2) + { + add(createHintLane(xOffset + hintWidth, (j == 1) ? boxHeight : 0, hintsNoteDirections[j], boxWidth, boxHeight, + hintsColors[j % hintsColors.length], false, showGradint)); + } else + { add(createHintLane(xOffset + (j == 0 ? 0 : hintWidth + boxWidth), 0, hintsNoteDirections[j], hintWidth, hintHeight, - hintsColors[j % hintsColors.length], false)); + hintsColors[j % hintsColors.length], false, showGradint)); + } } } case FunkinHitboxControlSchemes.DoubleThumbDPad: @@ -425,8 +355,10 @@ class FunkinHitbox extends FlxTypedSpriteGroup final yPos:Int = Math.floor(FlxG.height - hintHeight * 2 - 24); for (i in 0...hintsNoteDirections.length) + { add(createHintTransparentNote(xPos + i * hintWidth + noteSpacing * i, yPos, hintsNoteDirections[i % hintsNoteDirections.length], hintWidth, hintHeight)); + } } #end @@ -435,6 +367,17 @@ class FunkinHitbox extends FlxTypedSpriteGroup ControlsHandler.setupHitbox(PlayerSettings.player1.controls, this, trackedInputs); } + public function getFirstHintByDirection(direction:NoteDirection):Null + { + var result:Null = null; + forEachOfType(FunkinHint, function(hint:FunkinHint):Void { + @:privateAccess + if (hint.noteDirection == direction) result = hint; + }); + + return result; + } + /** * Creates a new `FunkinHint` lane button along side a graphic label with specified properties. * @@ -447,20 +390,68 @@ class FunkinHitbox extends FlxTypedSpriteGroup * @param color The color of the button. * @return A new `FunkinHint` object. */ - @:noCompletion - function createHintLane(x:Float, y:Float, noteDirection:NoteDirection, width:Int, height:Int, color:FlxColor = 0xFFFFFFFF, label:Bool = true):FunkinHint + function createHintLane(x:Float, y:Float, noteDirection:NoteDirection, width:Int, height:Int, color:FlxColor = 0xFFFFFFFF, label:Bool = true, + gradient:Bool = true):FunkinHint { final hint:FunkinHint = new FunkinHint(x, y, noteDirection, label ? createHintLaneLabelGraphic(width, height, Math.floor(height * 0.035), color) : null); - hint.loadGraphic(createHintLaneGraphic(width, height, color)); - hint.onDown.add(() -> onHintDown.dispatch(hint)); - hint.onUp.add(() -> onHintUp.dispatch(hint)); - hint.onOut.add(() -> onHintUp.dispatch(hint)); + hint.loadGraphic(createHintLaneGraphic(width, height, color, gradient)); + hint.onDown.add(onHintDown.dispatch.bind(hint)); + hint.onUp.add(onHintUp.dispatch.bind(hint)); + hint.onOut.add(onHintUp.dispatch.bind(hint)); hint.initTween(INVISIBLE_TILL_PRESS); return hint; } /** - * Creates a new `FunkinHint`representing a transparent note corresponding to the note from the scene. + * Creates a new `FunkinHint` triangle button with specified properties. + * + * @param x The x position of the triangle button. + * @param y The y position of the triangle button. + * @param noteDirection The direction of the note the button represents (e.g. left, right). + * @param size The size of the triangle (base length). + * @param upright A boolean indicating if the triangle is upright (true) or inverted (false). + * @param id The unique ID of the triangle button. + * @param color The color of the triangle button (default is white). + * @return A new `FunkinHint` triangle object. + */ + function createHintTriangle(x:Float, y:Float, noteDirection:NoteDirection, width:Int, height:Int, color:FlxColor = 0xFFFFFFFF, + gradient:Bool = true):FunkinHint + { + final hint:FunkinHint = new FunkinHint(x, y, noteDirection, null); + hint.loadGraphic(createHintTriangleGraphic(width, height, noteDirection, color, gradient)); + hint.onDown.add(onHintDown.dispatch.bind(hint)); + hint.onUp.add(onHintUp.dispatch.bind(hint)); + hint.onOut.add(onHintUp.dispatch.bind(hint)); + hint.initTween(INVISIBLE_TILL_PRESS); + hint.polygon = getTriangleVertices(width, height, noteDirection); + return hint; + } + + /** + * Creates a new `FunkinHint` circular button with specified properties. + * + * @param x The x position of the circular button. + * @param y The y position of the circular button. + * @param noteDirection The direction of the note the button represents (e.g., left, right). + * @param radius The radius of the circular button. + * @param color The color of the circular button (default is white). + * @return A new `FunkinHint` circular object. + */ + function createHintCircle(x:Float, y:Float, noteDirection:NoteDirection, radius:Float, color:FlxColor = 0xFFFFFFFF):FunkinHint + { + final hint:FunkinHint = new FunkinHint(x, y, noteDirection, null); + hint.loadGraphic(createHintCircleGraphic(radius, color)); + hint.limitToBounds = false; + hint.radius = radius; + hint.onDown.add(onHintDown.dispatch.bind(hint)); + hint.onUp.add(onHintUp.dispatch.bind(hint)); + hint.onOut.add(onHintUp.dispatch.bind(hint)); + hint.initTween(VISIBLE_TILL_PRESS); + return hint; + } + + /** + * Creates a new `FunkinHint` representing a transparent note corresponding to the note from the scene. * @param x The x position of the button. * @param y The y position of the button. * @param noteDirection The direction of the note the button represents (e.g. left, right). @@ -468,15 +459,14 @@ class FunkinHitbox extends FlxTypedSpriteGroup * @param height The height of the button. * @return A new `FunkinHint` object. */ - @:noCompletion function createHintTransparentNote(x:Float, y:Float, noteDirection:NoteDirection, width:Int, height:Int):FunkinHint { final hint:FunkinHint = new FunkinHint(x, y, noteDirection, null); hint.alpha = 0; hint.setSize(width, height); - hint.onDown.add(() -> onHintDown.dispatch(hint)); - hint.onUp.add(() -> onHintUp.dispatch(hint)); - hint.onOut.add(() -> onHintUp.dispatch(hint)); + hint.onDown.add(onHintDown.dispatch.bind(hint)); + hint.onUp.add(onHintUp.dispatch.bind(hint)); + hint.onOut.add(onHintUp.dispatch.bind(hint)); var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchDefault(); @:privateAccess @@ -510,56 +500,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup return hint; } - /** - * Creates a new `FunkinHint` triangle button with specified properties. - * - * @param x The x position of the triangle button. - * @param y The y position of the triangle button. - * @param noteDirection The direction of the note the button represents (e.g. left, right). - * @param size The size of the triangle (base length). - * @param upright A boolean indicating if the triangle is upright (true) or inverted (false). - * @param id The unique ID of the triangle button. - * @param color The color of the triangle button (default is white). - * @return A new `FunkinHint` triangle object. - */ - @:noCompletion - function createHintTriangle(x:Float, y:Float, noteDirection:NoteDirection, width:Int, height:Int, color:FlxColor = 0xFFFFFFFF):FunkinHint - { - final hint:FunkinHint = new FunkinHint(x, y, noteDirection, null); - hint.polygon = getTriangleVertices(width, height, noteDirection); - hint.loadGraphic(createHintTriangleGraphic(width, height, noteDirection, color)); - hint.onDown.add(() -> onHintDown.dispatch(hint)); - hint.onUp.add(() -> onHintUp.dispatch(hint)); - hint.onOut.add(() -> onHintUp.dispatch(hint)); - hint.initTween(INVISIBLE_TILL_PRESS); - return hint; - } - - /** - * Creates a new `FunkinHint` circular button with specified properties. - * - * @param x The x position of the circular button. - * @param y The y position of the circular button. - * @param noteDirection The direction of the note the button represents (e.g., left, right). - * @param radius The radius of the circular button. - * @param color The color of the circular button (default is white). - * @return A new `FunkinHint` circular object. - */ - @:noCompletion - function createHintCircle(x:Float, y:Float, noteDirection:NoteDirection, radius:Float, color:FlxColor = 0xFFFFFFFF):FunkinHint - { - final hint:FunkinHint = new FunkinHint(x, y, noteDirection, null); - hint.loadGraphic(createHintCircleGraphic(radius, color)); - hint.limitToBounds = false; - hint.isCircle = true; - hint.radius = radius; - hint.onDown.add(() -> onHintDown.dispatch(hint)); - hint.onUp.add(() -> onHintUp.dispatch(hint)); - hint.onOut.add(() -> onHintUp.dispatch(hint)); - hint.initTween(VISIBLE_TILL_PRESS); - return hint; - } - /** * Creates a lane graphic for a hint button. * @@ -568,7 +508,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup * @param baseColor The base color of the graphic. * @return A `FlxGraphic` object representing the button graphic. */ - @:noCompletion function createHintLaneGraphic(width:Int, height:Int, baseColor:FlxColor = 0xFFFFFFFF, gradient:Bool = true):FlxGraphic { final shape:Shape = new Shape(); @@ -580,7 +519,9 @@ class FunkinHitbox extends FlxTypedSpriteGroup shape.graphics.beginGradientFill(RADIAL, [baseColor.to24Bit(), baseColor.to24Bit()], [0, 1], [60, 255], matrix, PAD, RGB, 0); } else + { shape.graphics.beginFill(baseColor.to24Bit(), baseColor.alphaFloat); + } shape.graphics.drawRect(0, 0, width, height); shape.graphics.endFill(); @@ -590,7 +531,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup return FlxGraphic.fromBitmapData(graphicData, false, null, false); } - @:noCompletion function createHintLaneLabelGraphic(width:Int, height:Int, labelHeight:Int, baseColor:FlxColor = 0xFFFFFFFF):FlxGraphic { final shape:Shape = new Shape(); @@ -620,7 +560,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup * @param baseColor The base color of the triangle graphic (default is white). * @return A `FlxGraphic` object representing the triangle button graphic. */ - @:noCompletion function createHintTriangleGraphic(width:Int, height:Int, facing:NoteDirection, baseColor:FlxColor = 0xFFFFFFFF, gradient:Bool = true):FlxGraphic { final shape:Shape = new Shape(); @@ -632,7 +571,9 @@ class FunkinHitbox extends FlxTypedSpriteGroup shape.graphics.beginGradientFill(RADIAL, [baseColor.to24Bit(), baseColor.to24Bit()], [0, 1], [60, 255], matrix, PAD, RGB, 0); } else + { shape.graphics.beginFill(baseColor.to24Bit(), baseColor.alphaFloat); + } shape.graphics.drawRect(width / 2, height / 2, width / 2, height / 2); shape.graphics.drawTriangles(Vector.ofArray(getTriangleVertices(width, height, facing)), Vector.ofArray([0, 1, 2])); @@ -650,7 +591,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup * @param baseColor The base color of the circle graphic (default is white). * @return A `FlxGraphic` object representing the circular button graphic. */ - @:noCompletion function createHintCircleGraphic(radius:Float, baseColor:FlxColor = 0xFFFFFFFF):FlxGraphic { final shape:Shape = new Shape(); @@ -670,7 +610,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup * @param facing The side the triangle faces * @return array of vertices */ - @:noCompletion function getTriangleVertices(width:Int, height:Int, facing:NoteDirection):Array { if (facing == UP) facing = DOWN; @@ -685,17 +624,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup } } - public function getFirstHintByDirection(direction:NoteDirection):Null - { - var result:Null = null; - forEachOfType(FunkinHint, function(hint:FunkinHint):Void { - @:privateAccess - if (hint.noteDirection == direction) result = hint; - }); - - return result; - } - /** * Cleans up memory used by the `FunkinHitbox`. */ diff --git a/source/funkin/mobile/ui/options/ControlsSchemeMenu.hx b/source/funkin/mobile/ui/options/ControlsSchemeMenu.hx index 4c553d8f6..c9f86e9bf 100644 --- a/source/funkin/mobile/ui/options/ControlsSchemeMenu.hx +++ b/source/funkin/mobile/ui/options/ControlsSchemeMenu.hx @@ -147,16 +147,17 @@ class ControlsSchemeMenu extends MusicBeatSubState if (camControls != null) FlxG.cameras.remove(camControls); camControls = new FunkinCamera('camControls'); - FlxG.cameras.add(camControls, false); camControls.bgColor = 0x0; + FlxG.cameras.add(camControls, false); camButtons = new FunkinCamera('camButtons'); - FlxG.cameras.add(camButtons, false); camButtons.bgColor = 0x0; + FlxG.cameras.add(camButtons, false); camHitboxes = new FunkinCamera('camHitboxes'); - FlxG.cameras.add(camHitboxes, false); + camHitboxes.setScale(0.5, 0.5); camHitboxes.bgColor = 0x0; + FlxG.cameras.add(camHitboxes, false); } /** @@ -169,24 +170,23 @@ class ControlsSchemeMenu extends MusicBeatSubState for (i in 0...availableSchemes.length) { - final hitboxShowcase:HitboxShowcase = new HitboxShowcase(Math.floor(FlxG.width * -0.16 + (1500 * i)), 0, i, currentIndex, availableSchemes[i], - onSelectHitbox); - hitboxShowcases.add(hitboxShowcase); + final hitboxShowcase:HitboxShowcase = new HitboxShowcase(Math.floor(FlxG.width * -0.16 + (1500 * (i * FullScreenScaleMode.windowScale.x))), 0, i, + currentIndex, availableSchemes[i], onSelectHitbox); switch (availableSchemes[i]) { case FunkinHitbox.FunkinHitboxControlSchemes.Arrows: - hitboxShowcases.members[i].createOption("Downscroll", Preferences.downscroll, function(value:Bool) { + hitboxShowcase.createOption("Downscroll", Preferences.downscroll, function(value:Bool) { Preferences.downscroll = value; }); } + + hitboxShowcases.add(hitboxShowcase); } hitboxShowcases.cameras = [camHitboxes]; add(hitboxShowcases); - camHitboxes.setScale(0.5, 0.5); - itemNavHitbox = new FunkinSprite(FlxG.width * 0.295).makeSolidColor(Std.int(FlxG.width * 0.25), Std.int(FlxG.height * 0.25), FlxColor.GREEN); itemNavHitbox.cameras = [camButtons]; itemNavHitbox.updateHitbox(); @@ -298,17 +298,14 @@ class ControlsSchemeMenu extends MusicBeatSubState */ function setSelection(index:Int):Void { - currentIndex = index; + final newIndex:Int = Math.floor(FlxMath.bound(index, 0, hitboxShowcases.length - 1)); - if (currentIndex < 0) + if (currentIndex != newIndex) { - currentIndex = 0; - return; + currentIndex = newIndex; } - - if (currentIndex >= hitboxShowcases.length) + else { - currentIndex = hitboxShowcases.length - 1; return; } @@ -353,14 +350,12 @@ class ControlsSchemeMenu extends MusicBeatSubState if (TouchUtil.justPressed && TouchUtil.overlapsComplex(itemNavHitbox)) { hitboxShowcases.members[currentIndex].onPress(); - currentButton.busy = true; - return; - } - if (TouchUtil.justPressed && TouchUtil.overlapsComplex(optionNavHitbox) && hitboxShowcases.members[currentIndex].checkbox != null) + currentButton.busy = true; + } + else if (TouchUtil.justPressed && TouchUtil.overlapsComplex(optionNavHitbox) && hitboxShowcases.members[currentIndex].checkbox != null) { hitboxShowcases.members[currentIndex].checkbox.text.callback(); - return; } } @@ -380,13 +375,11 @@ class ControlsSchemeMenu extends MusicBeatSubState if (TouchUtil.pressed && dragDistance != 0) { - final showcasesTargetX:Float = originX + dragDistance * 10; - hitboxShowcases.x = MathUtil.smoothLerp(hitboxShowcases.x, showcasesTargetX, elapsed, 0.5); - - final minShowcasesX:Float = -1500 * availableSchemes.length; - hitboxShowcases.x = FlxMath.bound(hitboxShowcases.x, minShowcasesX, 400); + hitboxShowcases.x = FlxMath.bound(MathUtil.smoothLerp(hitboxShowcases.x, originX + dragDistance * 10, elapsed, 0.5), -1500 * availableSchemes.length, + 400); final targetIndex:Int = Math.round(hitboxShowcases.x / -1500); + if (currentIndex != targetIndex) setSelection(targetIndex); } else diff --git a/source/funkin/mobile/ui/options/objects/HitboxOptionButton.hx b/source/funkin/mobile/ui/options/objects/HitboxOptionButton.hx index 518609e17..fd21d7342 100644 --- a/source/funkin/mobile/ui/options/objects/HitboxOptionButton.hx +++ b/source/funkin/mobile/ui/options/objects/HitboxOptionButton.hx @@ -1,11 +1,9 @@ package funkin.mobile.ui.options.objects; -import flixel.FlxG; import flixel.group.FlxSpriteGroup; import funkin.ui.TextMenuList.TextMenuItem; import funkin.ui.options.items.CheckboxPreferenceItem; import funkin.ui.AtlasText.AtlasFont; -import funkin.graphics.FunkinCamera; /** * Represents an option button for the hitbox showcase. @@ -26,19 +24,20 @@ class HitboxOptionButton extends FlxSpriteGroup /** * Creates a new HitboxShowcase instance. * + * @param name Option's name. * @param xPos The x position of the object. * @param yPos The y position of the object. * @param defaultValue Option's default value. * @param onClick A callback function that will be triggered when the object is clicked. */ - public function new(?xPos:Float = 0, ?yPos:Float = 0, defaultValue:Bool, onClick:Bool->Void):Void + public function new(name:String = "", ?xPos:Float = 0, ?yPos:Float = 0, defaultValue:Bool, onClick:Bool->Void):Void { super(xPos, yPos); checkbox = new CheckboxPreferenceItem(0, 0, defaultValue); add(checkbox); - text = new TextMenuItem(checkbox.x + checkbox.width, checkbox.y + 30, "Downscroll", AtlasFont.BOLD, function() { + text = new TextMenuItem(checkbox.x + checkbox.width, checkbox.y + 30, name, AtlasFont.BOLD, function() { final value:Bool = !checkbox.currentValue; onClick(value); checkbox.currentValue = value; @@ -46,11 +45,5 @@ class HitboxOptionButton extends FlxSpriteGroup add(text); setSize(500, 500); - - final optionCamera:FunkinCamera = new FunkinCamera('optionCamera'); - FlxG.cameras.add(optionCamera, false); - optionCamera.bgColor = 0x0; - - cameras = [optionCamera]; } } diff --git a/source/funkin/mobile/ui/options/objects/HitboxShowcase.hx b/source/funkin/mobile/ui/options/objects/HitboxShowcase.hx index 7058ada93..0240d53ea 100644 --- a/source/funkin/mobile/ui/options/objects/HitboxShowcase.hx +++ b/source/funkin/mobile/ui/options/objects/HitboxShowcase.hx @@ -85,11 +85,9 @@ class HitboxShowcase extends FlxSpriteGroup bg.screenCenter(); add(bg); - final hitbox:FunkinHitbox = new FunkinHitbox(controlsScheme); + final hitbox:FunkinHitbox = new FunkinHitbox(controlsScheme, false); hitbox.forEachAlive(function(hint:FunkinHint):Void { - hint.alpha = 0.3; - @:privateAccess - if (hint.label != null) hint.label.alpha = 0.3; + if (controlsScheme != FunkinHitbox.FunkinHitboxControlSchemes.FourLanes) hint.alpha = 0.3; }); hitbox.active = false; add(hitbox); @@ -105,7 +103,7 @@ class HitboxShowcase extends FlxSpriteGroup { if (checkbox != null) return; - checkbox = new HitboxOptionButton(width / 2 - width / 4, height + 50, defaultValue, callback); + checkbox = new HitboxOptionButton(name, width / 2 - width / 4, height + 50, defaultValue, callback); add(checkbox); } diff --git a/source/funkin/mobile/ui/options/objects/SchemeMenuButton.hx b/source/funkin/mobile/ui/options/objects/SchemeMenuButton.hx index 208a82ac4..039dea987 100644 --- a/source/funkin/mobile/ui/options/objects/SchemeMenuButton.hx +++ b/source/funkin/mobile/ui/options/objects/SchemeMenuButton.hx @@ -44,7 +44,7 @@ class SchemeMenuButton extends FlxSpriteGroup * @param labelText The text displayed on the button. * @param onClick An optional callback function that will be triggered when the button is clicked. */ - public function new(?xPos:Float = 0, ?yPos:Float = 0, labelText:String, ?onClick:Void->Void = null):Void + public function new(?xPos:Float = 0, ?yPos:Float = 0, labelText:String, ?onClick:Void->Void):Void { super(xPos, yPos);