diff --git a/flixel/FlxCamera.hx b/flixel/FlxCamera.hx index 3f423694e5..118b3a601f 100644 --- a/flixel/FlxCamera.hx +++ b/flixel/FlxCamera.hx @@ -1182,7 +1182,7 @@ class FlxCamera extends FlxBasic if (deadzone == null) { target.getMidpoint(_point); - _point.addPoint(targetOffset); + _point.add(targetOffset); _scrollTarget.set(_point.x - width * 0.5, _point.y - height * 0.5); } else diff --git a/flixel/FlxSprite.hx b/flixel/FlxSprite.hx index e643d5da6e..cb402cfb9d 100644 --- a/flixel/FlxSprite.hx +++ b/flixel/FlxSprite.hx @@ -833,11 +833,11 @@ class FlxSprite extends FlxObject @:noCompletion function drawSimple(camera:FlxCamera):Void { - getScreenPosition(_point, camera).subtractPoint(offset); + getScreenPosition(_point, camera).subtract(offset); if (isPixelPerfectRender(camera)) _point.floor(); - _point.copyToFlash(_flashPoint); + _point.copyTo(_flashPoint); camera.copyPixels(_frame, framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing); } @@ -856,7 +856,7 @@ class FlxSprite extends FlxObject _matrix.rotateWithTrig(_cosAngle, _sinAngle); } - getScreenPosition(_point, camera).subtractPoint(offset); + getScreenPosition(_point, camera).subtract(offset); _point.add(origin.x, origin.y); _matrix.translate(_point.x, _point.y); @@ -1122,11 +1122,11 @@ class FlxSprite extends FlxObject result.subtract(worldPoint.x, worldPoint.y); result.negate(); - result.addPoint(offset); - result.subtractPoint(origin); + result.add(offset); + result.subtract(origin); result.scale(1 / scale.x, 1 / scale.y); result.degrees -= angle; - result.addPoint(origin); + result.add(origin); worldPoint.putWeak(); @@ -1148,11 +1148,11 @@ class FlxSprite extends FlxObject result.subtract(screenPoint.x, screenPoint.y); result.negate(); - result.addPoint(offset); - result.subtractPoint(origin); + result.add(offset); + result.subtract(origin); result.scale(1 / scale.x, 1 / scale.y); result.degrees -= angle; - result.addPoint(origin); + result.add(origin); screenPoint.putWeak(); diff --git a/flixel/graphics/frames/FlxAtlasFrames.hx b/flixel/graphics/frames/FlxAtlasFrames.hx index 58c12c1043..91fe6baf39 100644 --- a/flixel/graphics/frames/FlxAtlasFrames.hx +++ b/flixel/graphics/frames/FlxAtlasFrames.hx @@ -423,7 +423,7 @@ class FlxAtlasFrames extends FlxFramesCollection override public function addBorder(border:FlxPoint):FlxAtlasFrames { - var resultBorder = FlxPoint.weak().addPoint(this.border).addPoint(border); + var resultBorder = FlxPoint.weak().add(this.border).add(border); var atlasFrames = FlxAtlasFrames.findFrame(parent, resultBorder); if (atlasFrames != null) return atlasFrames; diff --git a/flixel/graphics/frames/FlxBitmapFont.hx b/flixel/graphics/frames/FlxBitmapFont.hx index ed06a3b71a..6ba8b53785 100644 --- a/flixel/graphics/frames/FlxBitmapFont.hx +++ b/flixel/graphics/frames/FlxBitmapFont.hx @@ -466,7 +466,7 @@ class FlxBitmapFont extends FlxFramesCollection final h:Float = charFrame.sourceSize.y + (offset != null && offset.y > 0 ? offset.y : 0); charFrame.sourceSize.set(w, h); if (offset != null) - charFrame.offset.addPoint(offset);//calls putWeak + charFrame.offset.add(offset);//calls putWeak charFrame.name = charName; pushFrame(charFrame, true); charMap.set(charCode, charFrame); @@ -536,7 +536,7 @@ class FlxBitmapFont extends FlxFramesCollection override public function addBorder(border:FlxPoint):FlxBitmapFont { - var resultBorder:FlxPoint = FlxPoint.weak().addPoint(this.border).addPoint(border); + var resultBorder:FlxPoint = FlxPoint.weak().add(this.border).add(border); var font:FlxBitmapFont = FlxBitmapFont.findFont(frame, resultBorder); if (font != null) diff --git a/flixel/graphics/frames/FlxFrame.hx b/flixel/graphics/frames/FlxFrame.hx index 8cc7e3c201..afd594f8fe 100644 --- a/flixel/graphics/frames/FlxFrame.hx +++ b/flixel/graphics/frames/FlxFrame.hx @@ -349,7 +349,7 @@ class FlxFrame implements IFlxDestroyable if (angle == FlxFrameAngle.ANGLE_0) { - offset.copyToFlash(_point); + offset.copyTo(_point); if (point != null) _point.offset(point.x, point.y); @@ -521,7 +521,7 @@ class FlxFrame implements IFlxDestroyable else { frameToFill.type = FlxFrameType.REGULAR; - frameToFill.offset.set(frameRect.x, frameRect.y).subtract(rect.x, rect.y).addPoint(offset); + frameToFill.offset.set(frameRect.x, frameRect.y).subtract(rect.x, rect.y).add(offset); final p1 = FlxPoint.weak(frameRect.x, frameRect.y); final p2 = FlxPoint.weak(frameRect.right, frameRect.bottom); @@ -623,7 +623,7 @@ class FlxFrame implements IFlxDestroyable else { clippedFrame.type = FlxFrameType.REGULAR; - clippedFrame.offset.set(frameRect.x, frameRect.y).addPoint(offset); + clippedFrame.offset.set(frameRect.x, frameRect.y).add(offset); var p1 = FlxPoint.weak(frameRect.x, frameRect.y); var p2 = FlxPoint.weak(frameRect.right, frameRect.bottom); diff --git a/flixel/graphics/frames/FlxImageFrame.hx b/flixel/graphics/frames/FlxImageFrame.hx index 6f3fc3c423..76be77a9d0 100644 --- a/flixel/graphics/frames/FlxImageFrame.hx +++ b/flixel/graphics/frames/FlxImageFrame.hx @@ -242,7 +242,7 @@ class FlxImageFrame extends FlxFramesCollection override public function addBorder(border:FlxPoint):FlxImageFrame { - var resultBorder:FlxPoint = FlxPoint.weak().addPoint(this.border).addPoint(border); + var resultBorder:FlxPoint = FlxPoint.weak().add(this.border).add(border); var imageFrame:FlxImageFrame = FlxImageFrame.findFrame(parent, frame.frame, resultBorder); if (imageFrame != null) diff --git a/flixel/graphics/frames/FlxTileFrames.hx b/flixel/graphics/frames/FlxTileFrames.hx index ae209f74b2..745a3fc227 100644 --- a/flixel/graphics/frames/FlxTileFrames.hx +++ b/flixel/graphics/frames/FlxTileFrames.hx @@ -514,7 +514,7 @@ class FlxTileFrames extends FlxFramesCollection override public function addBorder(border:FlxPoint):FlxTileFrames { - var resultBorder:FlxPoint = FlxPoint.get().addPoint(this.border).addPoint(border); + var resultBorder:FlxPoint = FlxPoint.get().add(this.border).add(border); var resultSize:FlxPoint = FlxPoint.get().copyFrom(tileSize).subtract(2 * border.x, 2 * border.y); var tileFrames:FlxTileFrames = FlxTileFrames.findFrame(parent, resultSize, region, atlasFrame, tileSpacing, resultBorder); if (tileFrames != null) diff --git a/flixel/input/actions/FlxActionInputAnalog.hx b/flixel/input/actions/FlxActionInputAnalog.hx index 1dff292005..7ced145bea 100644 --- a/flixel/input/actions/FlxActionInputAnalog.hx +++ b/flixel/input/actions/FlxActionInputAnalog.hx @@ -20,6 +20,15 @@ enum abstract FlxAnalogState(Int) from Int var STOPPED = cast FlxInputState.RELEASED; // is 0 var MOVED = cast FlxInputState.PRESSED; // is !0 var JUST_MOVED = cast FlxInputState.JUST_PRESSED; // became !0 on this frame + + public var moved(get, never):Bool; + inline function get_moved() return this == MOVED || justMoved; + public var justMoved(get, never):Bool; + inline function get_justMoved() return this == JUST_MOVED; + public var justStopped(get, never):Bool; + inline function get_justStopped() return this == JUST_STOPPED; + public var stopped(get, never):Bool; + inline function get_stopped() return this == STOPPED || justStopped; } /** diff --git a/flixel/math/FlxMath.hx b/flixel/math/FlxMath.hx index f4f7f1ef49..55fe7aa2cf 100644 --- a/flixel/math/FlxMath.hx +++ b/flixel/math/FlxMath.hx @@ -108,6 +108,18 @@ class FlxMath { return a + ratio * (b - a); } + + /** + * Adjusts the given lerp to account for the time that has passed + * + * @param lerp The ratio to lerp in 1/60th of a second + * @param elapsed The amount of time that has actually passed + * @since 6.0.0 + */ + public static function getElapsedLerp(lerp:Float, elapsed:Float):Float + { + return 1.0 - Math.pow(1.0 - lerp, elapsed * 60); + } /** * Checks if number is in defined range. A null bound means that side is unbounded. diff --git a/flixel/math/FlxPoint.hx b/flixel/math/FlxPoint.hx index db82a66419..3a2157aedc 100644 --- a/flixel/math/FlxPoint.hx +++ b/flixel/math/FlxPoint.hx @@ -322,7 +322,7 @@ import openfl.geom.Point; * @param y Amount to add to y * @return This point. */ - public inline function add(x:Float = 0, y:Float = 0):FlxPoint + public overload extern inline function add(x:Float = 0, y:Float = 0):FlxPoint { this.x += x; this.y += y; @@ -331,16 +331,44 @@ import openfl.geom.Point; /** * Adds the coordinates of another point to the coordinates of this point. + * @since 6.0.0 * * @param point The point to add to this point * @return This point. */ - public inline function addPoint(point:FlxPoint):FlxPoint + public overload inline extern function add(point:FlxPoint):FlxPoint { add(point.x, point.y); point.putWeak(); return this; } + + /** + * Adds the coordinates of another point to the coordinates of this point. + * @since 6.0.0 + * + * @param p Any Point. + * @return A reference to the altered point parameter. + */ + public overload inline extern function add(p:Point):FlxPoint + { + x += p.x; + y += p.y; + + return this; + } + + /** + * Adds the coordinates of another point to the coordinates of this point. + * + * @param point The point to add to this point + * @return This point. + */ + // @:deprecated("addPoint is deprecated, use add(point), instead")// 6.0.0 + public inline function addPoint(point:FlxPoint):FlxPoint + { + return add(point); + } /** * Subtracts from the coordinates of this point. @@ -349,7 +377,7 @@ import openfl.geom.Point; * @param y Amount to subtract from y * @return This point. */ - public inline function subtract(x:Float = 0, y:Float = 0):FlxPoint + public overload inline extern function subtract(x:Float = 0, y:Float = 0):FlxPoint { this.x -= x; this.y -= y; @@ -358,10 +386,38 @@ import openfl.geom.Point; /** * Subtracts the coordinates of another point from the coordinates of this point. + * @since 6.0.0 + * + * @param point The point to subtract from this point + * @return This point. + */ + public overload inline extern function subtract(point:FlxPoint):FlxPoint + { + subtract(point.x, point.y); + point.putWeak(); + return this; + } + + /** + * Subtracts the coordinates of another point from the coordinates of this point. + * @since 6.0.0 * * @param point The point to subtract from this point * @return This point. */ + public overload inline extern function subtract(point:Point):FlxPoint + { + subtract(point.x, point.y); + return this; + } + + /** + * Subtracts the coordinates of another point from the coordinates of this point. + * + * @param point The point to subtract from this point + * @return This point. + */ + // @:deprecated("subtractPoint is deprecated, use subtract(point), instead")// 6.0.0 public inline function subtractPoint(point:FlxPoint):FlxPoint { subtract(point.x, point.y); @@ -372,26 +428,51 @@ import openfl.geom.Point; /** * Scale this point. * - * @param x - scale x coefficient - * @param y - scale y coefficient, if omitted, x is used - * @return scaled point + * @param x The x scale coefficient + * @param y The y scale coefficient + * @return this point */ - public inline function scale(x:Float, ?y:Float):FlxPoint + public overload inline extern function scale(x:Float, y:Float):FlxPoint { - if (y == null) - y = x; - this.x *= x; this.y *= y; return this; } + + /** + * Scale this point. + * @since 6.0.0 + * + * @param amount The scale coefficient + * @return this point + */ + public overload inline extern function scale(amount:Float):FlxPoint + { + this.x *= amount; + this.y *= amount; + return this; + } + + /** + * Scale this point by another point. + * @since 6.0.0 + * + * @param point The x and y scale coefficient + * @return this point + */ + public overload inline extern function scale(point:Point):FlxPoint + { + scale(point.x, point.y); + return this; + } /** * Scale this point by another point. * - * @param point - The x and y scale coefficient + * @param point The x and y scale coefficient * @return scaled point */ + // @:deprecated("scalePoint is deprecated, use scale(point), instead")// 6.0.0 public inline function scalePoint(point:FlxPoint):FlxPoint { scale(point.x, point.y); @@ -438,19 +519,32 @@ import openfl.geom.Point; * @param p Any FlxPoint. * @return A reference to itself. */ - public inline function copyFrom(p:FlxPoint):FlxPoint + public overload inline extern function copyFrom(p:FlxPoint):FlxPoint { set(p.x, p.y); p.putWeak(); return this; } + /** + * Helper function, just copies the values from the specified Flash point. + * @since 6.0.0 + * + * @param p Any Point. + * @return A reference to itself. + */ + public overload inline extern function copyFrom(p:Point):FlxPoint + { + return this.set(p.x, p.y); + } + /** * Helper function, just copies the values from the specified Flash point. * * @param p Any Point. * @return A reference to itself. */ + // @:deprecated("copyFromFlash is deprecated, use copyFrom, instead")// 6.0.0 public inline function copyFromFlash(p:Point):FlxPoint { return this.set(p.x, p.y); @@ -462,7 +556,7 @@ import openfl.geom.Point; * @param p optional point to copy this point to * @return copy of this point */ - public inline function copyTo(?p:FlxPoint):FlxPoint + public overload inline extern function copyTo(?p:FlxPoint):FlxPoint { if (p == null) { @@ -473,22 +567,30 @@ import openfl.geom.Point; /** * Helper function, just copies the values from this point to the specified Flash point. + * @since 6.0.0 * * @param p Any Point. * @return A reference to the altered point parameter. */ - public inline function copyToFlash(?p:Point):Point + public overload inline extern function copyTo(p:Point):Point { - if (p == null) - { - p = new Point(); - } - p.x = x; p.y = y; return p; } + /** + * Helper function, just copies the values from this point to the specified Flash point. + * + * @param p Any Point. + * @return A reference to the altered point parameter. + */ + // @:deprecated("copyToFlash is deprecated, use copyTo, instead")// 6.0.0 + public inline function copyToFlash(?p:Point):Point + { + return copyTo(p != null ? p : new Point()); + } + /** * Helper function, just increases the values of the specified Flash point by the values of this point. * @@ -610,12 +712,47 @@ import openfl.geom.Point; * @param point A FlxPoint object to calculate the distance to. * @return The distance between the two points as a Float. */ - public function distanceTo(point:FlxPoint):Float + public overload inline extern function distanceTo(point:FlxPoint):Float + { + final result = distanceTo(point.x, point.y); + point.putWeak(); + return result; + } + + /** + * Calculate the distance to another position + * @since 6.0.0 + * + * @return The distance between the two positions as a Float. + */ + public overload inline extern function distanceTo(x:Float, y:Float):Float + { + return Math.sqrt(distanceSquaredTo(x, y)); + } + + /** + * Calculate the squared distance to another point. + * @since 6.0.0 + * + * @param point A FlxPoint object to calculate the distance to. + * @return The distance between the two points as a Float. + */ + public overload inline extern function distanceSquaredTo(point:FlxPoint):Float { - var dx:Float = x - point.x; - var dy:Float = y - point.y; + final result = distanceSquaredTo(point.x, point.y); point.putWeak(); - return FlxMath.vectorLength(dx, dy); + return result; + } + + /** + * Calculate the distance to another position + * @since 6.0.0 + * + * @return The distance between the two positions as a Float. + */ + public overload inline extern function distanceSquaredTo(x:Float, y:Float):Float + { + return (this.x - x) * (this.x - x) + (this.y - y) + (this.y - y); } /** @@ -1181,21 +1318,36 @@ import openfl.geom.Point; /** * The distance between points + * @since 6.0.0 */ - public inline function dist(p:FlxPoint):Float + public overload inline extern function dist(x:Float, y:Float):Float { - return Math.sqrt(distSquared(p)); + return distanceTo(x, y); } + /** + * The distance between points + */ + public overload inline extern function dist(p:FlxPoint):Float + { + return distanceTo(p); + } + /** * The squared distance between points */ - public inline function distSquared(p:FlxPoint):Float + public overload inline extern function distSquared(p:FlxPoint):Float { - var dx:Float = p.x - x; - var dy:Float = p.y - y; - p.putWeak(); - return dx * dx + dy * dy; + return distanceSquaredTo(p); + } + + /** + * The squared distance between positions + * @since 6.0.0 + */ + public overload inline extern function distSquared(x:Float, y:Float):Float + { + return distanceSquaredTo(x, y); } /** @@ -1510,6 +1662,62 @@ class FlxBasePoint implements IFlxPooled } } +/** + * A point that, once set, cannot be changed. Useful for objects + * that want to expose a readonly `x` and `y` value + * @since 6.0.0 + */ +@:forward +@:forward.new +abstract FlxReadOnlyPoint(FlxPoint) from FlxPoint +{ + public var x(get, never):Float; + public var y(get, never):Float; + + /** Length of the point */ + public var length(get, never):Float; + + /** The angle formed by the point with the horizontal axis (in degrees) */ + public var degrees(get, never):Float; + + /** The angle formed by the point with the horizontal axis (in radians) */ + public var radians(get, never):Float; + + inline function get_x():Float return this.x; + inline function get_y():Float return this.y; + inline function get_length():Float return this.length; + inline function get_radians():Float return this.radians; + inline function get_degrees():Float return this.degrees; + + // hide underlying mutators + inline function set(x = 0, y = 0):FlxReadOnlyPoint return this.set(x, y); + inline function add(x = 0, y = 0):FlxReadOnlyPoint return this.add(x, y); + inline function addPoint(point):FlxReadOnlyPoint return this.add(point); + inline function subtract(x = 0, y = 0):FlxReadOnlyPoint return this.subtract(x, y); + inline function subtractPoint(point):FlxReadOnlyPoint return this.subtract(point); + inline function scale(x = 0, y = 0):FlxReadOnlyPoint return this.scale(x, y); + inline function scalePoint(point):FlxReadOnlyPoint return this.scale(point); + inline function copyFrom(point):FlxReadOnlyPoint return this.copyFrom(point); + inline function copyFromFlash(point):FlxReadOnlyPoint return this.copyFrom(point); + inline function floor():FlxReadOnlyPoint return this.floor(); + inline function ceil():FlxReadOnlyPoint return this.ceil(); + inline function round():FlxReadOnlyPoint return this.round(); + inline function rotate(pivot, degrees):FlxReadOnlyPoint return this.pivotDegrees(pivot, degrees); + inline function pivotRadians(pivot, radians):FlxReadOnlyPoint return this.pivotRadians(pivot, radians); + inline function pivotDegrees(pivot, degrees):FlxReadOnlyPoint return this.pivotDegrees(pivot, degrees); + inline function transform(matrix):FlxReadOnlyPoint return this.transform(matrix); + inline function zero():FlxReadOnlyPoint return this.zero(); + inline function normalize():FlxReadOnlyPoint return this.normalize(); + inline function rotateByRadians(rads):FlxReadOnlyPoint return this.rotateByRadians(rads); + inline function rotateByDegrees(degs):FlxReadOnlyPoint return this.rotateByDegrees(degs); + inline function rotateWithTrig(sin, cos):FlxReadOnlyPoint return this.rotateWithTrig(sin, cos); + inline function setPolarRadians(length, radians):FlxReadOnlyPoint return this.setPolarRadians(length, radians); + inline function setPolarDegrees(length, degrees):FlxReadOnlyPoint return this.setPolarDegrees(length, degrees); + inline function negate():FlxReadOnlyPoint return this.negate(); + inline function truncate(max):FlxReadOnlyPoint return this.truncate(max); + inline function bounce(normal, coeff = 1.0):FlxReadOnlyPoint return this.bounce(normal, coeff); + inline function bounceWithFriction(normal, coeff = 1.0, friction = 0.0):FlxReadOnlyPoint return this.bounce(normal, coeff); +} /** * A FlxPoint that calls a function when set_x(), set_y() or set() is called. Used in FlxSpriteGroup. diff --git a/flixel/path/FlxPath.hx b/flixel/path/FlxPath.hx index bebfc54d21..6cfcb3316e 100644 --- a/flixel/path/FlxPath.hx +++ b/flixel/path/FlxPath.hx @@ -71,7 +71,7 @@ private class AnchorTools case TOP_LEFT: result; case CUSTOM(offset): - result.addPoint(offset); + result.add(offset); } } } @@ -399,7 +399,7 @@ class FlxPath extends FlxBasePath } else { - var velocity = object.velocity.copyFrom(node).subtractPoint(_point); + var velocity = object.velocity.copyFrom(node).subtract(_point); velocity.length = speed; angle = velocity.degrees; } diff --git a/flixel/system/debug/log/BitmapLog.hx b/flixel/system/debug/log/BitmapLog.hx index a973d35c06..e08feb6c4a 100644 --- a/flixel/system/debug/log/BitmapLog.hx +++ b/flixel/system/debug/log/BitmapLog.hx @@ -153,7 +153,7 @@ class BitmapLog extends Window if (_middleMouseDown) { var delta = FlxPoint.get(mouseX, mouseY); - _curMouseOffset.addPoint(delta.subtractPoint(_lastMousePos)); + _curMouseOffset.add(delta.subtract(_lastMousePos)); refreshCanvas(); _lastMousePos.set(mouseX, mouseY); } @@ -309,7 +309,7 @@ class BitmapLog extends Window _point.x = (_canvas.width / 2) - (_curBitmap.width * zoom / 2); _point.y = (_canvas.height / 2) - (_curBitmap.height * zoom / 2); - _point.addPoint(_curMouseOffset); + _point.add(_curMouseOffset); _matrix.identity(); _matrix.scale(zoom, zoom); diff --git a/flixel/text/FlxText.hx b/flixel/text/FlxText.hx index ea999e4e84..5b3a797f8b 100644 --- a/flixel/text/FlxText.hx +++ b/flixel/text/FlxText.hx @@ -1031,11 +1031,11 @@ class FlxText extends FlxSprite override function drawSimple(camera:FlxCamera):Void { // same as super but checks _graphicOffset - getScreenPosition(_point, camera).subtractPoint(offset).subtractPoint(_graphicOffset); + getScreenPosition(_point, camera).subtract(offset).subtract(_graphicOffset); if (isPixelPerfectRender(camera)) _point.floor(); - _point.copyToFlash(_flashPoint); + _point.copyTo(_flashPoint); camera.copyPixels(_frame, framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing); } @@ -1054,7 +1054,7 @@ class FlxText extends FlxSprite } // same as super but checks _graphicOffset - getScreenPosition(_point, camera).subtractPoint(offset).subtractPoint(_graphicOffset); + getScreenPosition(_point, camera).subtract(offset).subtract(_graphicOffset); _point.add(origin.x, origin.y); _matrix.translate(_point.x, _point.y); diff --git a/flixel/tile/FlxBaseTilemap.hx b/flixel/tile/FlxBaseTilemap.hx index ce637a0e5c..4858ac21b3 100644 --- a/flixel/tile/FlxBaseTilemap.hx +++ b/flixel/tile/FlxBaseTilemap.hx @@ -1603,7 +1603,7 @@ class FlxBaseTilemap extends FlxObject if (camera == null) camera = getDefaultCamera(); - worldPoint.subtractPoint(camera.scroll); + worldPoint.subtract(camera.scroll); worldPoint.putWeak(); } diff --git a/flixel/tile/FlxTilemap.hx b/flixel/tile/FlxTilemap.hx index 05d90ca10a..cee1fe130b 100644 --- a/flixel/tile/FlxTilemap.hx +++ b/flixel/tile/FlxTilemap.hx @@ -673,7 +673,7 @@ class FlxTypedTilemap extends FlxBaseTilemap if (buffer.isDirty(this, camera)) drawTilemap(buffer, camera); - getScreenPosition(_point, camera).subtractPoint(offset).add(buffer.x, buffer.y).copyToFlash(_flashPoint); + getScreenPosition(_point, camera).subtract(offset).add(buffer.x, buffer.y).copyTo(_flashPoint); buffer.draw(camera, _flashPoint, scale.x, scale.y); } else @@ -1232,7 +1232,7 @@ class FlxTypedTilemap extends FlxBaseTilemap } else { - getScreenPosition(_point, camera).subtractPoint(offset).copyToFlash(_helperPoint); + getScreenPosition(_point, camera).subtractPoint(offset).copyTo(_helperPoint); _helperPoint.x = isPixelPerfectRender(camera) ? Math.floor(_helperPoint.x) : _helperPoint.x; _helperPoint.y = isPixelPerfectRender(camera) ? Math.floor(_helperPoint.y) : _helperPoint.y; diff --git a/flixel/ui/FlxAnalog.hx b/flixel/ui/FlxAnalog.hx index c2888b234a..98c96b15ed 100644 --- a/flixel/ui/FlxAnalog.hx +++ b/flixel/ui/FlxAnalog.hx @@ -2,7 +2,7 @@ package flixel.ui; import flixel.FlxG; import flixel.FlxSprite; -import flixel.group.FlxSpriteGroup; +import flixel.group.FlxSpriteContainer; import flixel.input.touch.FlxTouch; import flixel.math.FlxAngle; import flixel.math.FlxMath; @@ -16,7 +16,8 @@ import flixel.util.FlxDestroyUtil; * * @author Ka Wing Chin */ -class FlxAnalog extends FlxSpriteGroup +@:deprecated("FlxAnalog is deprecated, use FlxVirtualStick or FlxVirtualPad, instead") +class FlxAnalog extends FlxSpriteContainer { /** * Shows the current state of the button. diff --git a/flixel/ui/FlxBar.hx b/flixel/ui/FlxBar.hx index 11997a8c72..dcc0ac13d1 100644 --- a/flixel/ui/FlxBar.hx +++ b/flixel/ui/FlxBar.hx @@ -880,7 +880,7 @@ class FlxBar extends FlxSprite _matrix.rotateWithTrig(_cosAngle, _sinAngle); } - getScreenPosition(_point, camera).subtractPoint(offset); + getScreenPosition(_point, camera).subtract(offset); _point.add(origin.x, origin.y); _matrix.translate(_point.x, _point.y); diff --git a/flixel/ui/FlxButton.hx b/flixel/ui/FlxButton.hx index 8c404a7319..d30f35318b 100644 --- a/flixel/ui/FlxButton.hx +++ b/flixel/ui/FlxButton.hx @@ -31,6 +31,22 @@ enum abstract FlxButtonState(Int) to Int /** The button is not interactible */ var DISABLED = 3; + + public function toInt() + { + return this; + } + + public function toString() + { + return switch (cast this:FlxButtonState) + { + case NORMAL: "normal"; + case HIGHLIGHT: "highlight"; + case PRESSED: "pressed"; + case DISABLED: "disabled"; + } + } } /** @@ -108,9 +124,9 @@ class FlxButton extends FlxTypedButton { if (Text != null) { - label = new FlxText(x + labelOffsets[FlxButtonState.NORMAL].x, y + labelOffsets[FlxButtonState.NORMAL].y, 80, Text); + label = new FlxText(x + labelOffsets[FlxButtonState.NORMAL.toInt()].x, y + labelOffsets[FlxButtonState.NORMAL.toInt()].y, 80, Text); label.setFormat(null, 8, 0x333333, "center"); - label.alpha = labelAlphas[status]; + label.alpha = labelAlphas[status.toInt()]; label.drawFrame(true); } } @@ -162,6 +178,7 @@ class FlxTypedButton extends FlxSprite implements IFlxInput * What animation should be played for each status. * Default is ["normal", "highlight", "pressed"]. */ + @:deprecated("statusAnimations is deprecated, use status.toString(), instead") public var statusAnimations:Array = ["normal", "highlight", "pressed", "disabled"]; /** @@ -230,7 +247,7 @@ class FlxTypedButton extends FlxSprite implements IFlxInput */ var currentInput:IFlxInput; - var lastStatus = -1; + var lastStatus:FlxButtonState = cast -1; /** * Creates a new `FlxTypedButton` object with a gray background. @@ -260,8 +277,7 @@ class FlxTypedButton extends FlxSprite implements IFlxInput #end #if FLX_NO_MOUSE // no need for highlight frame without mouse input - statusAnimations[HIGHLIGHT] = "normal"; - labelAlphas[HIGHLIGHT] = 1; + labelAlphas[HIGHLIGHT.toInt()] = 1; #end input = new FlxInput(0); @@ -271,10 +287,10 @@ class FlxTypedButton extends FlxSprite implements IFlxInput { super.graphicLoaded(); - setupAnimation("normal", NORMAL); - setupAnimation("highlight", HIGHLIGHT); - setupAnimation("pressed", PRESSED); - setupAnimation("disabled", DISABLED); + setupAnimation("normal", NORMAL.toInt()); + setupAnimation("highlight", (#if FLX_MOUSE HIGHLIGHT #else NORMAL #end).toInt()); + setupAnimation("pressed", PRESSED.toInt()); + setupAnimation("disabled", DISABLED.toInt()); } function loadDefaultGraphic():Void @@ -342,7 +358,7 @@ class FlxTypedButton extends FlxSprite implements IFlxInput function updateStatusAnimation():Void { - animation.play(statusAnimations[status]); + animation.play(status.toString()); } /** @@ -472,7 +488,7 @@ class FlxTypedButton extends FlxSprite implements IFlxInput function checkInput(pointer:FlxPointer, input:IFlxInput, justPressedPosition:FlxPoint, camera:FlxCamera):Bool { if (maxInputMovement != Math.POSITIVE_INFINITY - && justPressedPosition.distanceTo(pointer.getViewPosition(FlxPoint.weak())) > maxInputMovement + && justPressedPosition.distanceTo(pointer.getViewPosition(camera, FlxPoint.weak())) > maxInputMovement && input == currentInput) { currentInput = null; @@ -514,16 +530,16 @@ class FlxTypedButton extends FlxSprite implements IFlxInput { if (_spriteLabel != null) // Label positioning { - _spriteLabel.x = (pixelPerfectPosition ? Math.floor(x) : x) + labelOffsets[status].x; - _spriteLabel.y = (pixelPerfectPosition ? Math.floor(y) : y) + labelOffsets[status].y; + _spriteLabel.x = (pixelPerfectPosition ? Math.floor(x) : x) + labelOffsets[status.toInt()].x; + _spriteLabel.y = (pixelPerfectPosition ? Math.floor(y) : y) + labelOffsets[status.toInt()].y; } } function updateLabelAlpha() { - if (_spriteLabel != null && labelAlphas.length > (status : Int)) + if (_spriteLabel != null && labelAlphas.length > status.toInt()) { - _spriteLabel.alpha = alpha * labelAlphas[status]; + _spriteLabel.alpha = alpha * labelAlphas[status.toInt()]; } } diff --git a/flixel/ui/FlxVirtualPad.hx b/flixel/ui/FlxVirtualPad.hx index d313bc5059..37b0a5cbce 100644 --- a/flixel/ui/FlxVirtualPad.hx +++ b/flixel/ui/FlxVirtualPad.hx @@ -1,11 +1,14 @@ package flixel.ui; +import flixel.ui.FlxAnalog; import flixel.FlxG; import flixel.graphics.frames.FlxTileFrames; -import flixel.group.FlxSpriteGroup; +import flixel.group.FlxSpriteContainer; import flixel.math.FlxPoint; import flixel.system.FlxAssets; +import flixel.util.FlxColor; import flixel.util.FlxDestroyUtil; +import flixel.util.FlxSpriteUtil; /** * A gamepad which contains 4 directional buttons and 4 action buttons. @@ -13,137 +16,202 @@ import flixel.util.FlxDestroyUtil; * * @author Ka Wing Chin */ -class FlxVirtualPad extends FlxSpriteGroup +class FlxVirtualPad extends FlxSpriteContainer { - public var buttonA:FlxButton; - public var buttonB:FlxButton; - public var buttonC:FlxButton; - public var buttonY:FlxButton; - public var buttonX:FlxButton; - public var buttonLeft:FlxButton; - public var buttonUp:FlxButton; - public var buttonRight:FlxButton; - public var buttonDown:FlxButton; - /** * Group of directions buttons. */ - public var dPad:FlxSpriteGroup; - + public final dPad:Null; + /** * Group of action buttons. */ - public var actions:FlxSpriteGroup; - + public final actions:FlxVirtualActionButtons; + + /** + * An Analog directional input + */ + public final stick:Null; + + @:deprecated("buttonA is deprecated, use getButton(A), instead") + public var buttonA(get, never):Null; + inline function get_buttonA() return actions.getButton(A); + + @:deprecated("buttonB is deprecated, use getButton(B), instead") + public var buttonB(get, never):Null; + inline function get_buttonB() return actions.getButton(B); + + @:deprecated("buttonC is deprecated, use getButton(C), instead") + public var buttonC(get, never):Null; + inline function get_buttonC() return actions.getButton(C); + + @:deprecated("buttonY is deprecated, use getButton(Y), instead") + public var buttonY(get, never):Null; + inline function get_buttonY() return actions.getButton(Y); + + @:deprecated("buttonX is deprecated, use getButton(X), instead") + public var buttonX(get, never):Null; + inline function get_buttonX() return actions.getButton(X); + + @:deprecated("buttonLeft is deprecated, use getButton(LEFT), instead") + public var buttonLeft(get, never):Null; + inline function get_buttonLeft() return dPad.getButton(LEFT); + + @:deprecated("buttonUp is deprecated, use getButton(UP), instead") + public var buttonUp(get, never):Null; + inline function get_buttonUp() return dPad.getButton(UP); + + @:deprecated("buttonRight is deprecated, use getButton(RIGHT), instead") + public var buttonRight(get, never):Null; + inline function get_buttonRight() return dPad.getButton(RIGHT); + + @:deprecated("buttonDown is deprecated, use getButton(DOWN), instead") + public var buttonDown(get, never):Null; + inline function get_buttonDown() return dPad.getButton(DOWN); + /** * Create a gamepad which contains 4 directional buttons and 4 action buttons. * * @param DPadMode The D-Pad mode. `FULL` for example. * @param ActionMode The action buttons mode. `A_B_C` for example. */ - public function new(?DPad:FlxDPadMode, ?Action:FlxActionMode) + public function new(dPadMode = FlxDPadMode.FULL, actionMode = FlxActionMode.A_B_C) { super(); scrollFactor.set(); + + add(actions = new FlxVirtualActionButtons(0, 0, actionMode)); + actions.x = FlxG.width - actions.width; + + switch dPadMode + { + case ANALOG: + add(stick = new FlxVirtualStick()); + stick.y = height - stick.height; + default: + add(dPad = new FlxVirtualDPadButtons(0, 0, dPadMode)); + dPad.y = height - dPad.height; + } + actions.y = height - actions.height; + + y = FlxG.height - height; + + #if FLX_DEBUG + this.ignoreDrawDebug = true; + #end + } + + public function getButton(id:FlxVirtualInputID) + { + return switch id + { + case A | B | C | X | Y: actions.getButton(id); + case UP | DOWN | LEFT | RIGHT if (dPad == null): null; + case UP | DOWN | LEFT | RIGHT: dPad.getButton(id); + case STICK: null; + } + } +} - if (DPad == null) - DPad = FULL; - if (Action == null) - Action = A_B_C; - - dPad = new FlxSpriteGroup(); - dPad.scrollFactor.set(); - - actions = new FlxSpriteGroup(); - actions.scrollFactor.set(); +class FlxVirtualPadButtons extends FlxTypedSpriteContainer +{ + final buttons = new Map(); + + public function new (x = 0.0, y = 0.0) + { + super(x, y); + scrollFactor.set(); + + #if FLX_DEBUG + this.ignoreDrawDebug = true; + #end + } + + override public function destroy():Void + { + super.destroy(); + + buttons.clear(); + } + + public function addButton(x = 0.0, y = 0.0, id, ?onClick) + { + return buttons[id] = add(new FlxVirtualPadButton(x, y, id, onClick)); + } + + public function getButton(id) + { + return buttons[id]; + } +} - switch (DPad) +class FlxVirtualDPadButtons extends FlxVirtualPadButtons +{ + public function new (x = 0.0, y = 0.0, mode:FlxDPadMode) + { + super(x, y); + switch (mode) { case UP_DOWN: - dPad.add(add(buttonUp = createButton(0, FlxG.height - 85, 44, 45, "up"))); - dPad.add(add(buttonDown = createButton(0, FlxG.height - 45, 44, 45, "down"))); + addButton( 0, 0, UP ); + addButton( 0, 40, DOWN ); case LEFT_RIGHT: - dPad.add(add(buttonLeft = createButton(0, FlxG.height - 45, 44, 45, "left"))); - dPad.add(add(buttonRight = createButton(42, FlxG.height - 45, 44, 45, "right"))); + addButton( 0, 0, LEFT ); + addButton(42, 0, RIGHT); case UP_LEFT_RIGHT: - dPad.add(add(buttonUp = createButton(35, FlxG.height - 81, 44, 45, "up"))); - dPad.add(add(buttonLeft = createButton(0, FlxG.height - 45, 44, 45, "left"))); - dPad.add(add(buttonRight = createButton(69, FlxG.height - 45, 44, 45, "right"))); + addButton(35, 0, UP ); + addButton( 0, 36, LEFT ); + addButton(69, 36, RIGHT); case FULL: - dPad.add(add(buttonUp = createButton(35, FlxG.height - 116, 44, 45, "up"))); - dPad.add(add(buttonLeft = createButton(0, FlxG.height - 81, 44, 45, "left"))); - dPad.add(add(buttonRight = createButton(69, FlxG.height - 81, 44, 45, "right"))); - dPad.add(add(buttonDown = createButton(35, FlxG.height - 45, 44, 45, "down"))); + addButton(35, 0, UP ); + addButton( 0, 35, LEFT ); + addButton(69, 35, RIGHT); + addButton(35, 71, DOWN ); + case ANALOG: throw "Unexpected mode: ANALOG"; case NONE: // do nothing } + } +} - switch (Action) +class FlxVirtualActionButtons extends FlxVirtualPadButtons +{ + public function new (x = 0.0, y = 0.0, mode:FlxActionMode) + { + super(x, y); + switch (mode) { case A: - actions.add(add(buttonA = createButton(FlxG.width - 44, FlxG.height - 45, 44, 45, "a"))); + addButton( 0, 0, A); case A_B: - actions.add(add(buttonA = createButton(FlxG.width - 44, FlxG.height - 45, 44, 45, "a"))); - actions.add(add(buttonB = createButton(FlxG.width - 86, FlxG.height - 45, 44, 45, "b"))); + addButton(42, 0, A); + addButton( 0, 0, B); case A_B_C: - actions.add(add(buttonA = createButton(FlxG.width - 128, FlxG.height - 45, 44, 45, "a"))); - actions.add(add(buttonB = createButton(FlxG.width - 86, FlxG.height - 45, 44, 45, "b"))); - actions.add(add(buttonC = createButton(FlxG.width - 44, FlxG.height - 45, 44, 45, "c"))); + addButton( 0, 0, A); + addButton(42, 0, B); + addButton(84, 0, C); case A_B_X_Y: - actions.add(add(buttonY = createButton(FlxG.width - 86, FlxG.height - 85, 44, 45, "y"))); - actions.add(add(buttonX = createButton(FlxG.width - 44, FlxG.height - 85, 44, 45, "x"))); - actions.add(add(buttonB = createButton(FlxG.width - 86, FlxG.height - 45, 44, 45, "b"))); - actions.add(add(buttonA = createButton(FlxG.width - 44, FlxG.height - 45, 44, 45, "a"))); + addButton( 0, 0, Y); + addButton(42, 0, X); + addButton( 0, 40, B); + addButton(42, 40, A); case NONE: // do nothing } } +} - override public function destroy():Void - { - super.destroy(); - - dPad = FlxDestroyUtil.destroy(dPad); - actions = FlxDestroyUtil.destroy(actions); - - dPad = null; - actions = null; - buttonA = null; - buttonB = null; - buttonC = null; - buttonY = null; - buttonX = null; - buttonLeft = null; - buttonUp = null; - buttonDown = null; - buttonRight = null; - } - - /** - * @param X The x-position of the button. - * @param Y The y-position of the button. - * @param Width The width of the button. - * @param Height The height of the button. - * @param Graphic The image of the button. It must contains 3 frames (`NORMAL`, `HIGHLIGHT`, `PRESSED`). - * @param Callback The callback for the button. - * @return The button - */ - public function createButton(X:Float, Y:Float, Width:Int, Height:Int, Graphic:String, ?OnClick:Void->Void):FlxButton +@:forward +abstract FlxVirtualPadButton(FlxButton) to FlxButton +{ + public function new(x = 0.0, y = 0.0, id:FlxVirtualInputID, ?onClick) { - var button = new FlxButton(X, Y); - var frame = FlxAssets.getVirtualInputFrames().getByName(Graphic); - button.frames = FlxTileFrames.fromFrame(frame, FlxPoint.get(Width, Height)); - button.resetSizeFromFrame(); - button.solid = false; - button.immovable = true; - button.scrollFactor.set(); + this = new FlxButton(x, y, null, onClick); + this.frames = id.getFrames(); + this.resetSizeFromFrame(); + this.moves = true; #if FLX_DEBUG - button.ignoreDrawDebug = true; + this.ignoreDrawDebug = true; #end - - if (OnClick != null) - button.onDown.callback = OnClick; - - return button; } } @@ -154,6 +222,7 @@ enum FlxDPadMode LEFT_RIGHT; UP_LEFT_RIGHT; FULL; + ANALOG; } enum FlxActionMode @@ -164,3 +233,41 @@ enum FlxActionMode A_B_C; A_B_X_Y; } + +@:using(flixel.ui.FlxVirtualPad.FlxVirtualInputIDTools) +enum FlxVirtualInputID +{ + UP; + DOWN; + LEFT; + RIGHT; + A; + B; + C; + X; + Y; + STICK; +} + +private class FlxVirtualInputIDTools +{ + public static function getFrames(id:FlxVirtualInputID) + { + final name = switch id + { + case UP: "up"; + case DOWN: "down"; + case LEFT: "left"; + case RIGHT: "right"; + case A: "a"; + case B: "b"; + case C: "c"; + case X: "x"; + case Y: "y"; + case STICK: "stick"; + } + + final frame = FlxAssets.getVirtualInputFrames().getByName(name); + return FlxTileFrames.fromFrame(frame, FlxPoint.get(44, 45)); + } +} \ No newline at end of file diff --git a/flixel/ui/FlxVirtualStick.hx b/flixel/ui/FlxVirtualStick.hx new file mode 100644 index 0000000000..c278f654e1 --- /dev/null +++ b/flixel/ui/FlxVirtualStick.hx @@ -0,0 +1,293 @@ +package flixel.ui; + +import flixel.util.FlxColor; +import flixel.FlxG; +import flixel.FlxSprite; +import flixel.group.FlxSpriteContainer; +import flixel.input.FlxPointer; +import flixel.input.actions.FlxActionInputAnalog; +import flixel.input.touch.FlxTouch; +import flixel.math.FlxAngle; +import flixel.math.FlxMath; +import flixel.math.FlxPoint; +import flixel.math.FlxRect; +import flixel.system.FlxAssets; +import flixel.ui.FlxButton; +import flixel.util.FlxDestroyUtil; +import flixel.util.FlxSignal; + +/** + * A virtual thumbstick - useful for input on mobile devices. + */ +class FlxVirtualStick extends FlxSpriteContainer +{ + /** The current state of the button */ + public final value:FlxReadOnlyPoint = FlxPoint.get(); + + /** The top of the joystick, the part that moves */ + public final thumb:CircleSprite; + + /** The background of the joystick, also known as the base */ + public final base:CircleSprite; + + /** The radius in which the stick can move */ + public final radius:Float; + + /** Used to smooth the thumb's motion. Should be between 0 and 1.0. */ + public var lerp:Float = 0.25; + + /** The minimum absolute value, to consider this input active */ + public var deadzone = 0.1; + + public final onJustMove = new FlxSignal(); + public final onJustStop = new FlxSignal(); + public final onMove = new FlxSignal(); + + public var xStatus(default, null) = FlxAnalogState.STOPPED; + public var yStatus(default, null) = FlxAnalogState.STOPPED; + public var status(default, null) = FlxAnalogState.STOPPED; + + /** Used to track press events */ + final button:InvisibleCircleButton; + + var dragging = false; + + /** + * Create a virtual thumbstick - useful for input on mobile devices. + * + * @param x The location in screen space. + * @param y The location in screen space. + * @param radius The radius where the thumb can move. If 0, half the base's width will be used. + * @param baseGraphic The graphic you want to display as base of the joystick. + * @param thumbGraphic The graphic you want to display as thumb of the joystick. + */ + public function new(x = 0.0, y = 0.0, radius = 0.0, ?baseGraphic:FlxGraphicAsset, ?thumbGraphic:FlxGraphicAsset) + { + super(x, y); + + add(base = new CircleSprite(0, 0, baseGraphic, "base")); + add(thumb = new CircleSprite(0, 0, thumbGraphic, "thumb")); + + if (radius <= 0) + radius = base.radius; + this.radius = radius; + + base.x += radius; + base.y += radius; + thumb.x += radius; + thumb.y += radius; + + add(button = new InvisibleCircleButton(0, 0, this.radius)); + + moves = false; + solid = false; + + FlxG.watch.addFunction("stick.state", ()->button.status.toString()); + FlxG.watch.addFunction("base.x|y", ()->'${base.x} | ${base.y}'); + FlxG.watch.addFunction("thumb.x|y", ()->'${thumb.x} | ${thumb.y}'); + } + + override function destroy() + { + super.destroy(); + + thumb.destroy(); + base.destroy(); + + onJustMove.removeAll(); + onJustStop.removeAll(); + onMove.removeAll(); + } + + override function update(elapsed:Float) + { + super.update(elapsed); + + updateValue(cast value); + + final adjustedLerp = FlxMath.getElapsedLerp(lerp, elapsed); + final newX = x + radius - thumb.radius + value.x * radius; + final newY = y + radius - thumb.radius + value.y * radius; + thumb.x += (newX - thumb.x) * adjustedLerp; + thumb.y += (newY - thumb.y) * adjustedLerp; + } + + function updateValue(pos:FlxPoint) + { + final oldX = value.x; + final oldY = value.y; + + if (button.justPressed) + dragging = true; + else if (button.released && dragging) + dragging = false; + + final pos:FlxPoint = cast value; + if (dragging) + { + button.calcDeltaToPointer(getCameras()[0], pos); + pos.scale(1 / radius); + if (pos.lengthSquared > 1.0) + pos.normalize(); + + if (pos.x < deadzone && pos.x > -deadzone) + pos.x = 0; + + if (pos.y < deadzone && pos.y > -deadzone) + pos.y = 0; + } + else + pos.zero(); + + xStatus = getStatus(oldX, value.x); + yStatus = getStatus(oldY, value.y); + + if ((yStatus.justMoved && xStatus == STOPPED) || (xStatus.justMoved && yStatus == STOPPED)) + { + status = JUST_MOVED; + onJustMove.dispatch(); + onMove.dispatch(); + } + else if ((yStatus.justStopped && xStatus.stopped) || (xStatus.justStopped && yStatus.stopped)) + { + status = JUST_STOPPED; + onJustStop.dispatch(); + } + else if (xStatus.moved || yStatus.moved) + { + status = MOVED; + onMove.dispatch(); + } + else + { + status = STOPPED; + } + } + + function getStatus(prev:Float, curr:Float) + { + return if (prev == 0 && curr != 0) + JUST_MOVED; + else if (prev != 0 && curr != 0) + MOVED; + else if (prev != 0 && curr == 0) + JUST_STOPPED; + else if (prev == 0 && curr == 0) + STOPPED; + else + throw 'Unexpected case - prev: $prev, curr:$curr';// not possible + } +} + +@:forward +@:forward.new +abstract CircleSprite(FlxSprite) to FlxSprite +{ + public var radius(get, never):Float; + public var radiusSquared(get, never):Float; + + public function new (centerX = 0.0, centerY = 0.0, graphic, ?backupId:String) + { + this = new FlxSprite(centerX, centerY, graphic); + if (graphic == null) + { + this.frames = FlxAssets.getVirtualInputFrames(); + this.animation.frameName = backupId; + this.resetSizeFromFrame(); + } + this.x -= radius; + this.y -= radius; + this.moves = false; + + #if FLX_DEBUG + // this.ignoreDrawDebug = true; + #end + } + + inline function get_radius() return this.frameWidth * 0.5; + inline function get_radiusSquared() return radius * radius; +} + +/** + * Special button that covers the virtual stick and tracks mouse and touch + */ +class InvisibleCircleButton extends FlxTypedButton +{ + public var radius(get, never):Float; + public var lastPointer(default, null):Null; + + inline function get_radius():Float return frameWidth * 0.5; + + public function new (x = 0.0, y = 0.0, radius:Float, ?onClick) + { + super(x, y, onClick); + final size = Math.ceil(radius * 2); + loadGraphic(FlxG.bitmap.create(size, size * 4, FlxColor.WHITE), true, size, size); + } + + override function draw() + { + #if FLX_DEBUG + if (FlxG.debugger.drawDebug) + drawDebug(); + #end + } + + override function checkInput(pointer, input, justPressedPosition, camera):Bool + { + if (super.checkInput(pointer, input, justPressedPosition, camera)) + { + lastPointer = pointer; + return true; + } + + return false; + } + + override function updateButton() + { + if (currentInput != null) + { + if (currentInput.justReleased) + onUpHandler(); + return; + } + + super.updateButton(); + } + + override function onUpHandler() + { + super.onUpHandler(); + lastPointer = null; + } + + override function overlapsPoint(point:FlxPoint, inScreenSpace = false, ?camera:FlxCamera):Bool + { + if (!inScreenSpace) + return point.distanceSquaredTo(x + radius, y + radius) < radius * radius; + + if (camera == null) + camera = getCameras()[0]; + + return calcDeltaTo(point, camera, _point).lengthSquared < radius * radius; + } + + public function calcDeltaTo(point:FlxPoint, camera:FlxCamera, ?result:FlxPoint) + { + if (result == null) + result = FlxPoint.get(); + + final xPos = point.x - camera.scroll.x - radius; + final yPos = point.y - camera.scroll.y - radius; + getScreenPosition(result, camera); + point.putWeak(); + return result.subtract(xPos, yPos).negate(); + } + + public function calcDeltaToPointer(camera:FlxCamera, ?result:FlxPoint) + { + final point = lastPointer.getViewPosition(camera, FlxPoint.weak()); + return calcDeltaTo(point, camera, result); + } +} \ No newline at end of file diff --git a/flixel/util/FlxSpriteUtil.hx b/flixel/util/FlxSpriteUtil.hx index 1a13991f9d..4e6de54a46 100644 --- a/flixel/util/FlxSpriteUtil.hx +++ b/flixel/util/FlxSpriteUtil.hx @@ -456,8 +456,8 @@ class FlxSpriteUtil * This function draws a circle on a FlxSprite at position X,Y with the specified color. * * @param sprite The FlxSprite to manipulate - * @param X X coordinate of the circle's center (automatically centered on the sprite if -1) - * @param Y Y coordinate of the circle's center (automatically centered on the sprite if -1) + * @param X X coordinate of the circle's center (automatically centered on the bitmap if -1) + * @param Y Y coordinate of the circle's center (automatically centered on the bitmap if -1) * @param Radius Radius of the circle (makes sure the circle fully fits on the sprite's graphic if < 1, assuming and and y are centered) * @param FillColor The ARGB color to fill this circle with. FlxColor.TRANSPARENT (0x0) means no fill. * @param lineStyle A LineStyle typedef containing the params of Graphics.lineStyle() @@ -469,14 +469,10 @@ class FlxSpriteUtil { if (X == -1 || Y == -1) { - var midPoint = sprite.getGraphicMidpoint(); - if (X == -1) - X = midPoint.x - sprite.x; + X = sprite.frameWidth / 2; if (Y == -1) - Y = midPoint.y - sprite.y; - - midPoint.put(); + Y = sprite.frameHeight / 2; } if (Radius < 1) diff --git a/tests/unit/src/flixel/ui/FlxButtonTest.hx b/tests/unit/src/flixel/ui/FlxButtonTest.hx index 943c7c261e..1f3023ea9a 100644 --- a/tests/unit/src/flixel/ui/FlxButtonTest.hx +++ b/tests/unit/src/flixel/ui/FlxButtonTest.hx @@ -46,13 +46,9 @@ class FlxButtonTest extends FlxTest function assertStatusAnimationsExist() { - var normalName:String = button.statusAnimations[NORMAL]; - var highlightName:String = button.statusAnimations[HIGHLIGHT]; - var pressedName:String = button.statusAnimations[PRESSED]; - - Assert.isNotNull(button.animation.getByName(normalName)); - Assert.isNotNull(button.animation.getByName(highlightName)); - Assert.isNotNull(button.animation.getByName(pressedName)); + Assert.isNotNull(button.animation.getByName(NORMAL.toString())); + Assert.isNotNull(button.animation.getByName(HIGHLIGHT.toString())); + Assert.isNotNull(button.animation.getByName(PRESSED.toString())); } @Test // #1479