In the previous three posts, we looked at the various interpolation methods Phaser 3 offers, followed by a look at the Phaser.Curves.Spline and Phaser.Curves.Path classes, and delved into the path follower object, before arriving at code which takes much of the tweening logic of the path follower object that allows the player to accelerate and decelerate the path follower. Fundamentally, moving the sprites around the path involved using tweens to set the x/y coordinates directly.
In this post, I look at ways of getting the arcade physics engine getting more involved.
Getting the arcade physics engine more involved
In the various path following logic I have explored so far, I was directly setting the position of the sprite (i.e. its x/y coordinate) by reference to a coordinate of a particular point on the path, as opposed to manipulating the velocity of the sprite.
However, there are situations where it makes things more convenient to "involve" the physics engine a bit more in moving the sprites around the screen.
Setting the velocity of the physics body
Having spent rummaging around the various examples, I found this code here, which is using the path object, but is adding code in the tween update property to "copy" the pathDelta (see previous post for explanation of pathDelta) to the physics body velocity. Based on this logic, I have created the below example.
The key piece of code is below (literally plucked straight out of the example by Samme) but with the game object changed to alien.
alien.startFollow({
duration: 10000,
yoyo: true,
repeat: -1,
// startAt: 1,
onUpdate: function () {
// Scale the delta vector to a 1-second velocity vector.
alien.body.velocity
.copy(alien.pathDelta)
.scale(1000 / this.parent.systems.game.loop.delta);
}
});
It is still the tween that is updating the x/y coordinate of the parent game object (I believe).
I don't frankly understand:
why adjusting the physics body velocity to the pathDelta doesn't mess up the movement of the sprite, and
how to bring the alien game object into the scope of the scene (ie change it into this.alien) and make the thing work, as I cant figure out the scope of the this.parent.systems.game.loop.delta bit....
Nonetheless, the code does appear to show that the various physics body properties are being updated appropriate without the tween and the physics engine "fighting" against each other.
Don't use tween but rely on the physics engine
Of course, the above logic still does not allow you to explicitly set the speed of the game object, rather than the duration.
What if we wanted to set the physics body velocity and let the physics engine move the sprite?
There's lots of different ways of doing this, but one way is to get the "next point" on the path using getPoint method, and rather than setting the x/y coordinate of the sprite directly to that point, use physics.moveTo to move the sprite to that point. Below Codepen is my implementation of such an approach.
The key part of the above example code is the pathUpdate method (this in turn is called by the preUpdate loop of the game object), as shown below. this.target is the variable that holds the "next" destination point. each time this method is called, it checks whether the sprite has reached the destination point (with some wiggle room set by this.epsilon). If it has, the "t-value" is incremented, the next destination point is set by getPoint method, and the sprite is sent flying towards that point with the moveTo method.
pathUpdate() {
if (Phaser.Math.Distance.Between(this.x, this.y, this.target.x, this.target.y) > this.epsilon) return
if (this.t >= 1) {
this.stopFollow();
} else {
this.t = Math.min(this.t + 1/this.followSteps, 1);
this.target = this.path.getPoint(this.t).add(this.pathOffset);
if (this.rotateToPath) {
this.setRotation(this.path.getTangent(this.t).angle()+this.pathRotationOffset);
}
this.scene.physics.moveTo(this, this.target.x, this.target.y, this.speed);
}
}
The code behind the moveTo method is shown below. Essentially, the code (ignoring the extra parameter maxTime) is calculating the angle between the destination and the game object using arc tan, and then uses setToPolar method to set the velocity property of the physics body.
moveTo: function (gameObject, x, y, speed, maxTime) {
if (speed === undefined) { speed = 60; }
if (maxTime === undefined) { maxTime = 0; }
var angle = Math.atan2(y - gameObject.y, x - gameObject.x);
if (maxTime > 0) {
// We know how many pixels we need to move, but how fast?
speed = DistanceBetween(gameObject.x, gameObject.y, x, y) / (maxTime / 1000);
}
gameObject.body.velocity.setToPolar(angle, speed);
return angle;
},
To illustrate the flexibility of this approach, I have created the following example which mimics the classic Galaga game.
Full transparency: the flight paths as well as the logic for the formation was taken from a Youtube channel Ather Omar, and his tutorials on creating Galaga available here, which is all about writing a Galaga clone in C++ (by the by, even if you don't write in C++, this Youtube channel has a lot of very interesting content).
Commenti