Skip to content

Add FlxG.centerGraphic() and camera.centerGraphic() #3329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: 6.2.0
Choose a base branch
from
47 changes: 47 additions & 0 deletions flixel/FlxCamera.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1873,6 +1873,53 @@ class FlxCamera extends FlxBasic
setScale(scaleX, scaleY);
}

/**
* Centers `FlxSprite` by graphic size in this camera view, either by the x axis, y axis, or both.
*
* @param sprite The sprite to center.
* @param axes On what axes to center the sprite (e.g. `X`, `Y`, `XY`) - default is both.
* @return Centered sprite for chaining.
* @since 6.2.0
*/
public function centerGraphic<T:FlxSprite>(sprite:T, axes:FlxAxes = XY):T
{
final graphicBounds = sprite.getScreenBounds(null, this);

if (axes.x)
{
final offset = sprite.x - graphicBounds.x;
sprite.x = (width - graphicBounds.width) / 2 + offset;
}

if (axes.y)
{
final offset = sprite.y - graphicBounds.y;
sprite.y = (height - graphicBounds.height) / 2 + offset;
}

graphicBounds.put();
return sprite;
}

/**
* Centers `FlxObject` by hitbox size in this camera view, either by the x axis, y axis, or both.
*
* @param object The object to center.
* @param axes On what axes to center the object (e.g. `X`, `Y`, `XY`) - default is both.
* @return Centered object for chaining.
* @since 6.2.0
*/
public function centerHitbox<T:FlxObject>(object:T, axes:FlxAxes = XY):T
{
if (axes.x)
object.x = scroll.x + (width - object.width) / 2;

if (axes.y)
object.y = scroll.y + (height - object.height) / 2;

return object;
}

/**
* The size and position of this camera's margins, via `viewMarginLeft`, `viewMarginTop`, `viewWidth`
* and `viewHeight`.
Expand Down
50 changes: 49 additions & 1 deletion flixel/FlxG.hx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import flixel.system.frontEnds.VCRFrontEnd;
import flixel.system.frontEnds.WatchFrontEnd;
import flixel.system.scaleModes.BaseScaleMode;
import flixel.system.scaleModes.RatioScaleMode;
import flixel.util.FlxAxes;
import flixel.util.FlxCollision;
import flixel.util.FlxSave;
import flixel.util.typeLimit.NextState;
Expand Down Expand Up @@ -476,7 +477,54 @@ class FlxG
{
return overlap(objectOrGroup1, objectOrGroup2, notifyCallback, FlxObject.separate);
}


/**
* Centers `FlxSprite` by graphic size in game space, either by the x axis, y axis, or both.
*
* @param sprite The sprite to center.
* @param axes On what axes to center the sprite (e.g. `X`, `Y`, `XY`) - default is both.
* @return Centered sprite for chaining.
* @since 6.2.0
*/
public static function centerGraphic<T:FlxSprite>(sprite:T, axes:FlxAxes = XY):T
{
final graphicBounds = sprite.getGraphicBounds();

if (axes.x)
{
final offset = sprite.x - graphicBounds.x;
sprite.x = (FlxG.width - graphicBounds.width) / 2 + offset;
}

if (axes.y)
{
final offset = sprite.y - graphicBounds.y;
sprite.y = (FlxG.height - graphicBounds.height) / 2 + offset;
}

graphicBounds.put();
return sprite;
}

/**
* Centers `FlxObject` by hitbox size in game space, either by the x axis, y axis, or both.
*
* @param object The object to center.
* @param axes On what axes to center the object (e.g. `X`, `Y`, `XY`) - default is both.
* @return Centered object for chaining.
* @since 6.2.0
*/
public static function centerHitbox<T:FlxObject>(object:T, axes:FlxAxes = XY):T
{
if (axes.x)
object.x = (FlxG.width - object.width) / 2;

if (axes.y)
object.y = (FlxG.height - object.height) / 2;

return object;
}

/**
* Regular `DisplayObject`s are normally displayed over the Flixel cursor and the Flixel debugger if simply
* added to `stage`. This function simplifies things by adding a `DisplayObject` directly below mouse level.
Expand Down
15 changes: 5 additions & 10 deletions flixel/FlxObject.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1173,24 +1173,19 @@ class FlxObject extends FlxBasic
kill();
}
#end

/**
* Centers this `FlxObject` on the screen, either by the x axis, y axis, or both.
*
*
* @param axes On what axes to center the object (e.g. `X`, `Y`, `XY`) - default is both.
* @return This FlxObject for chaining
*/
@:deprecated("screenCenter is deprecated, use FlxG.centerHitbox instead")
public inline function screenCenter(axes:FlxAxes = XY):FlxObject
{
if (axes.x)
x = (FlxG.width - width) / 2;

if (axes.y)
y = (FlxG.height - height) / 2;

return this;
return FlxG.centerHitbox(this, axes);
}

/**
* Helper function to set the coordinates of this object.
* Handy since it only requires one line of code.
Expand Down
4 changes: 2 additions & 2 deletions flixel/FlxSprite.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1368,8 +1368,8 @@ class FlxSprite extends FlxObject
if (pixelPerfectPosition)
newRect.floor();
_scaledOrigin.set(origin.x * scale.x, origin.y * scale.y);
newRect.x += -Std.int(camera.scroll.x * scrollFactor.x) - offset.x + origin.x - _scaledOrigin.x;
newRect.y += -Std.int(camera.scroll.y * scrollFactor.y) - offset.y + origin.y - _scaledOrigin.y;
newRect.x += -camera.scroll.x * scrollFactor.x - offset.x + origin.x - _scaledOrigin.x;
newRect.y += -camera.scroll.y * scrollFactor.y - offset.y + origin.y - _scaledOrigin.y;
if (isPixelPerfectRender(camera))
newRect.floor();
newRect.setSize(frameWidth * Math.abs(scale.x), frameHeight * Math.abs(scale.y));
Expand Down
81 changes: 80 additions & 1 deletion tests/unit/src/flixel/FlxCameraTest.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package flixel;

import flixel.math.FlxPoint;
import flixel.util.FlxColor;
import massive.munit.Assert;

Expand Down Expand Up @@ -89,7 +90,85 @@ class FlxCameraTest extends FlxTest
camera.follow(new FlxObject());
Assert.areEqual(defaultLerp, camera.followLerp);
}


@Test // #3329
function testCenterGraphic()
{
final cam = FlxG.camera;
cam.scroll.set(100, 100);
cam.zoom *= 2;

Assert.areEqual(cam.width, 640);
Assert.areEqual(cam.height, 480);

final sprite = new FlxSprite();
sprite.makeGraphic(10, 10);
sprite.scrollFactor.set(2, 2);
sprite.origin.set(10, 10);
sprite.offset.set(10, 10);
sprite.scale.set(2, 4);
sprite.angle = 180;
sprite.pixelPerfectPosition = true;
sprite.pixelPerfectRender = true;

function assertCenterGraphic(sprite, expectedX, expectedY)
{
FlxAssert.areNear(sprite.x, expectedX);
FlxAssert.areNear(sprite.y, expectedY);
}

sprite.setPosition(0, 0);
cam.centerGraphic(sprite, X);
assertCenterGraphic(sprite, 100 + 320 - 10 - (-110 + 10), 0);

sprite.setPosition(0, 0);
cam.centerGraphic(sprite, Y);
assertCenterGraphic(sprite, 0, 100 + 240 - 20 - (-110 + 10));

sprite.setPosition(0, 0);
cam.centerGraphic(sprite, XY);
assertCenterGraphic(sprite, 100 + 320 - 10 - (-110 + 10), 100 + 240 - 20 - (-110 + 10));

sprite.setPosition(1640, 1480);
cam.centerGraphic(sprite);
assertCenterGraphic(sprite, 100 + 320 - 10 - (-110 + 10), 100 + 240 - 20 - (-110 + 10));
}

@Test // #3329
function testCenterHitbox()
{
final cam = FlxG.camera;
cam.scroll.set(100, 100);
cam.zoom *= 2;

Assert.areEqual(cam.width, 640);
Assert.areEqual(cam.height, 480);

final object = new FlxObject(0, 0, 10, 10);

function assertCenterHitbox(object, expectedX, expectedY)
{
Assert.areEqual(object.x, expectedX);
Assert.areEqual(object.y, expectedY);
}

object.setPosition(0, 0);
cam.centerHitbox(object, X);
assertCenterHitbox(object, 100 + 320 - 5, 0);

object.setPosition(0, 0);
cam.centerHitbox(object, Y);
assertCenterHitbox(object, 0, 100 + 240 - 5);

object.setPosition(0, 0);
cam.centerHitbox(object, XY);
assertCenterHitbox(object, 100 + 320 - 5, 100 + 240 - 5);

object.setPosition(1640, 1480);
cam.centerHitbox(object);
assertCenterHitbox(object, 100 + 320 - 5, 100 + 240 - 5);
}

@Test
function testFadeInFadeOut()
{
Expand Down
69 changes: 69 additions & 0 deletions tests/unit/src/flixel/FlxGTest.hx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package flixel;

import flixel.math.FlxPoint;
import massive.munit.Assert;

@:access(flixel.FlxG)
Expand Down Expand Up @@ -104,4 +105,72 @@ class FlxGTest extends FlxTest
{
Assert.areEqual(480, FlxG.height);
}

@Test // #3329
function testCenterGraphic()
{
Assert.areEqual(FlxG.width, 640);
Assert.areEqual(FlxG.height, 480);

final sprite = new FlxSprite();
sprite.makeGraphic(10, 10);
sprite.origin.set(10, 10);
sprite.offset.set(10, 10);
sprite.scale.set(2, 4);
sprite.angle = 180;
sprite.pixelPerfectPosition = true;

function assertCenterGraphic(sprite, expectedX, expectedY)
{
FlxAssert.areNear(sprite.x, expectedX);
FlxAssert.areNear(sprite.y, expectedY);
}

sprite.setPosition(0, 0);
FlxG.centerGraphic(sprite, X);
assertCenterGraphic(sprite, 320 - 10 - (-10 + 10), 0);

sprite.setPosition(0, 0);
FlxG.centerGraphic(sprite, Y);
assertCenterGraphic(sprite, 0, 240 - 20 - (-10 + 10));

sprite.setPosition(0, 0);
FlxG.centerGraphic(sprite, XY);
assertCenterGraphic(sprite, 320 - 10 - (-10 + 10), 240 - 20 - (-10 + 10));

sprite.setPosition(1640, 1480);
FlxG.centerGraphic(sprite);
assertCenterGraphic(sprite, 320 - 10 - (-10 + 10), 240 - 20 - (-10 + 10));
}

@Test // #3329
function testCenterHitbox()
{
Assert.areEqual(FlxG.width, 640);
Assert.areEqual(FlxG.height, 480);

final object = new FlxObject(0, 0, 10, 10);

function assertCenterHitbox(object, expectedX, expectedY)
{
Assert.areEqual(object.x, expectedX);
Assert.areEqual(object.y, expectedY);
}

object.setPosition(0, 0);
FlxG.centerHitbox(object, X);
assertCenterHitbox(object, 320 - 5, 0);

object.setPosition(0, 0);
FlxG.centerHitbox(object, Y);
assertCenterHitbox(object, 0, 240 - 5);

object.setPosition(0, 0);
FlxG.centerHitbox(object, XY);
assertCenterHitbox(object, 320 - 5, 240 - 5);

object.setPosition(1640, 1480);
FlxG.centerHitbox(object);
assertCenterHitbox(object, 320 - 5, 240 - 5);
}
}
30 changes: 0 additions & 30 deletions tests/unit/src/flixel/FlxObjectTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -340,36 +340,6 @@ class FlxObjectTest extends FlxTest
assertNotOnScreen(0, FlxG.height);
}

@Test
function testScreenCenter()
{
var center = FlxPoint.get((FlxG.width - object1.width) / 2, (FlxG.height - object1.height) / 2);
var offCenter = center.copyTo().add(1000, 1000);

object1.setPosition(offCenter.x, offCenter.y);
object1.screenCenter(X);
Assert.areEqual(object1.x, center.x);
Assert.areEqual(object1.y, offCenter.y);

object1.setPosition(offCenter.x, offCenter.y);
object1.screenCenter(Y);
Assert.areEqual(object1.x, offCenter.x);
Assert.areEqual(object1.y, center.y);

object1.setPosition(offCenter.x, offCenter.y);
object1.screenCenter(XY);
Assert.areEqual(object1.x, center.x);
Assert.areEqual(object1.y, center.y);

object1.setPosition(offCenter.x, offCenter.y);
object1.screenCenter();
Assert.areEqual(object1.x, center.x);
Assert.areEqual(object1.y, center.y);

offCenter.put();
center.put();
}

@Test
function testgetRotatedBounds()
{
Expand Down