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.
This commit is contained in:
MAJigsaw77
2025-04-17 12:22:56 +03:00
committed by KarimAkra
parent 3fcc2cc5bc
commit c7906edc1e
6 changed files with 205 additions and 298 deletions
+21 -26
View File
@@ -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<Float>, point:FlxPoint, ?offset:FlxPoint):Bool
static function isPointInPolygon(vertices:Array<Float>, 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<Float>, color:FlxColor):Void
{
gfx.lineStyle(2, color, 0.75);
+158 -230
View File
@@ -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<FunkinHintAlphaStyle, Array<Float>> = [INVISIBLE_TILL_PRESS => [0.3, 0.00001], VISIBLE_TILL_PRESS => [0.5, 0.35]];
static final HINT_ALPHA_STYLE:Map<FunkinHintAlphaStyle, Array<Float>> = [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<FunkinSprite>;
/**
* 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<FlxTween>;
var followTarget:Null<FunkinSprite>;
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<Array<Float>> = 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<Array<Float>> = 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<FunkinSprite>;
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<FunkinHint>
@@ -343,18 +264,18 @@ class FunkinHitbox extends FlxTypedSpriteGroup<FunkinHint>
/**
* The list of tracked inputs for the hitbox.
*/
@:noCompletion
var trackedInputs:Array<FlxActionInput> = [];
/**
* Creates a new `FunkinHitbox` object.
*/
public function new(?schemeOverride:String = null, ?directionsOverride:Array<NoteDirection> = null, ?colorsOverride:Array<FlxColor> = null):Void
public function new(?schemeOverride:String, ?showGradint:Bool = true, ?directionsOverride:Array<NoteDirection>, ?colorsOverride:Array<FlxColor>):Void
{
super();
final hintsColors:Array<FlxColor> = (colorsOverride == null || colorsOverride.length == 0) ? [0xFFC34B9A, 0xFF00FFFF, 0xFF12FB06, 0xFFF9393F] : colorsOverride;
final hintsNoteDirections:Array<NoteDirection> = (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<FunkinHint>
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<FunkinHint>
{
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<FunkinHint>
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<FunkinHint>
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<FunkinHint>
ControlsHandler.setupHitbox(PlayerSettings.player1.controls, this, trackedInputs);
}
public function getFirstHintByDirection(direction:NoteDirection):Null<FunkinHint>
{
var result:Null<FunkinHint> = 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<FunkinHint>
* @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<FunkinHint>
* @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<FunkinHint>
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<FunkinHint>
* @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<FunkinHint>
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<FunkinHint>
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<FunkinHint>
* @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<FunkinHint>
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<FunkinHint>
* @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<FunkinHint>
* @param facing The side the triangle faces
* @return array of vertices
*/
@:noCompletion
function getTriangleVertices(width:Int, height:Int, facing:NoteDirection):Array<Float>
{
if (facing == UP) facing = DOWN;
@@ -685,17 +624,6 @@ class FunkinHitbox extends FlxTypedSpriteGroup<FunkinHint>
}
}
public function getFirstHintByDirection(direction:NoteDirection):Null<FunkinHint>
{
var result:Null<FunkinHint> = null;
forEachOfType(FunkinHint, function(hint:FunkinHint):Void {
@:privateAccess
if (hint.noteDirection == direction) result = hint;
});
return result;
}
/**
* Cleans up memory used by the `FunkinHitbox`.
*/
@@ -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
@@ -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];
}
}
@@ -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);
}
@@ -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);