Collision errors with velocity.rotate()
Note: This is likely only useful for strict tilemap-based maps, such as top-down RPGs.
If you have a HaxeFlixel project that uses FlxTilemap
as the background or “walls” of your environment, you may encounter the issue I had. My tilemap’s tiles are 16x16 pixels width and height, and the player’s sprite is the same. This can result in some odd behaviour when using the movement code found in the HaxeFlixel tutorial project.
Specifically, when moving in certain directions right up against a “wall” in your tilemap, the player can stop when they should continue moving and have the room to do so. In my problem, it only occurred when there was a wall tile to the right of the player’s current facing
direction - that is, if the player moved upwards, they would collide with a wall tile to their top-right corner.
Here’s the code as used in the tutorial:
velocity.set(SPEED, 0); velocity.rotate(FlxPoint.weak(0, 0), newAngle);
As explained in the tutorial, newAngle is an Int
containing the angle we want the player to face, going clockwise up to 360 (it also works for down to -360).
0
degrees equals right, so facing downwards would be 90
and so on. velocity.rotate
uses this angle to calculate the X and Y components of the new
player velocity, so they move in the correct direction. This is useful to ensure players don’t go faster than they should when moving in diagonal directions,
for instance. It also allows for easier analogue movement, if you choose to enable that in your game.
However, that bit of code is also the cause of our problem. velocity
is a floating point value, meaning it can hold decimal values. It may be a
bug in the current implementation (using HaxeFlixel version 4.1.5), but when calculating the new velocity of the player using nice clean integer angles
like 90
or 180
, we should get something like velocity.x == 100
and velocity.y == 0
. What happens instead is that the component that should be
returning 0
instead returns a tiny fraction such as velocity.y == 0.00000001
. This causes the game engine to see a collision along certain tiles, where
the game looks as though it shouldn’t be.
To fix this, there are two options.
The first and easier option is simply to round the velocity
value to an integer. We can do this using Haxe’s Math.round()
function, like so:
velocity.x = Math.round(velocity.x); velocity.y = Math.round(velocity.y);
The second is instead of using the above code snippet and setting newAngle
to the correct value for each directional input, I set the velocity itself in that input code.
Here’s my current code:
if (up) { facing = FlxObject.UP; velocity.set(0, -SPEED); } else if (down) { facing = FlxObject.DOWN; velocity.set(0, SPEED); } else if (left) { facing = FlxObject.LEFT; velocity.set(-SPEED, 0); } else if (right) { facing = FlxObject.RIGHT; velocity.set(SPEED, 0); }
We test, and…
Voilà! Ghost collisions are gone. Thanks to users from the Haxe official Discord channel for solving the problem and assisting me.