Hi everyone,
these days I’ve been playing again with Phaser, and trying to implement a simple top-down game where the player would be controller with an analog controller (using a Xbox one, but assuming they would probably all pretty similar).
I have been having issues with movement when using two axes at the same time, especially down + left/right when there is a horizontal line of walls below (jumpiness), and up + left/right when there is a vertical line of walls on the side (getting stuck).
I am not sure that my description is super clear, so I made a quick capture:
The code
Player class:
class Player extends Phaser.Physics.Arcade.Sprite {
constructor(scene, x, y, name) {
super(scene, x, y, name);
scene.add.existing(this);
scene.physics.add.existing(this);
// Set physics properties
this.body.setSize(16, 10); // Set the body size
this.body.setOffset(0, 6);
this.body.setCollideWorldBounds(true); // Prevent going outside the world bounds
// Player physics-related properties
this.deadzone = 0.15; // Deadzone threshold for input sensitivity
this.speedFactor = 100; // Increased speed factor for faster movement
};
movePlayer(x, y) {
const magnitude = Math.sqrt(x * x + y * y);
// If the magnitude is below the deadzone, stop the player (set velocity to 0)
if (magnitude < this.deadzone) {
this.body.setVelocity(0, 0); // Reset velocity when no movement input
return;
}
// Normalize diagonal movement (if both x and y are non-zero)
if (x !== 0 && y !== 0) {
x = x / Math.sqrt(2); // Normalize x-axis
y = y / Math.sqrt(2); // Normalize y-axis
}
// Apply speed factor and set the velocity
this.body.setVelocity(x * this.speedFactor, y * this.speedFactor);
}
}
export { Player };
Wall class:
class Wall extends Phaser.Physics.Arcade.Sprite {
constructor(scene, x, y, name) {
super(scene, x, y, name);
scene.add.existing(this);
scene.physics.add.existing(this, true);
this.body.immovable = true;
this.zRatio = 100;
this.body.setSize(16, 24);
this.body.setOffset(0, 8);
this.zOrder = y * this.zRatio;
this.setDepth(this.zOrder);
};
};
export { Wall };
And in the main game scene, I call these like this (minus imports etc.):
export class Game extends Scene {
constructor () {
super('Game');
};
create() {
// Quick and dirty array to test with multiple walls
// The final thing will probably use a json map from a server
this.tilesGroup = this.physics.add.staticGroup();
this.wallArray = [
{x: 48, y:80, texture:'wall-001'},
{x: 64, y:80, texture:'wall-001'},
{x: 80, y:80, texture:'wall-001'},
{x: 128, y:80, texture:'wall-001'},
{x: 128, y:96, texture:'wall-001'},
{x: 128, y:112, texture:'wall-001'}
];
for(let i=0; i<this.wallArray.length; i++) {
let tile = new Wall(this, this.wallArray[i].x, this.wallArray[i].y, this.wallArray[i].texture);
this.tilesGroup.add(tile);
};
this.player = new Player(this, 50, 50, 'playerSprite');
this.physics.add.collider(this.player, this.tilesGroup);
this.hasGamepad = false;
this.cameras.main.setBounds(0, 0, 800, 600);
this.cameras.main.startFollow(this.player, true, 0.1, 0.1);
};
update() {
if (this.input.gamepad.total === 0) {
// No gamepad found
return;
};
this.hasGamepad = true;
const pad = this.input.gamepad.getPad(0);
if (pad.axes.length) {
this.player.movePlayer(pad.axes[0].getValue(), pad.axes[1].getValue());
this.player.update();
};
}
changeScene() {
this.scene.start('GameOver');
};
};
Not sure what is causing the issue… I tried to use dot product to modify the Player velocity but ended up messing things up even more … (also it seems to me that it is what the engine is proabably already doing under the hood?).
Thanks a lot!