@RaananW
Here’s the collision handler:
this.mesh.onCollideObservable.add((event, state) => {
this.velocity.addInPlace(new BABYLON.Vector3(0, this.velocity.y * -1, 0));
this.onGround = true;
this.numJump = 0;
}, COLLISION_GROUPS.Platform);
It’s only called on the collision with the first platform.
The client/server sync happens like this:
- Player presses jump
- Client animates the player jumping
- Client sends ‘Jump’ command to the server
- Server ‘animates’ the jump and sends the updated character velocity to all the clients
- Clients receive the update and update the player’s position, velocity and state accordingly.
In the client, during the render loop “move()” is called which will (obviously) move a character based on their last velocity. If the player collides with a platform the client recognizes it, and sets the Y component of the player’s velocity to 0 - in a similar call to the above collideObservable.
I can tell it’s only on the server because the server won’t send an update unless there’s player interaction. So the client will actually show the player landing on the platform - until the next update from the server which shows him below the platform (and programatically dead).
Animated Example
In the GIF above you can see the server console. It writes “Collision observable” when the player jumps on the platform (and as I’m moving on it but that’s a different issue). I’m able to jump on the platform and triggers additional messages, then I jump to the lower platform.
The client shows the player landing on the lower platform - while the server logs “Blaaaargh… player [GUID] died!” It isn’t until I try to MOVE after landing that the client is updated with the “authoritative” (and dead) state from the server.
Platforms are hard-coded into the scene at this point. This is called 4 times with the appropriate values for the start property:
this.state.platforms.push(new Platform(this.state.scene, {
id: '1',
collisionGroup: COLLISION_GROUPS.Platform,
name: '1',
file: 'platform_1.glb',
start: new BABYLON.Vector3(0, 0, 0),
gravity: 0
}));
The platform constructor:
constructor(scene: BABYLON.Scene, config: EntityConfig) {
this.config = config;
BABYLON.SceneLoader.ImportMesh('', process.env.SERVER_URL + '/assets/', config.file, scene,
(meshes, particleSystem, skeletons, animationGroups) => {
this.mesh = meshes[0];
meshes.forEach(m => {
m.collisionGroup = config.collisionGroup;
m.checkCollisions = true;
});
const boundingInfo = getBoundingInfo(meshes);
this.mesh.ellipsoid = new BABYLON.Vector3(...getEllipsoidSize(boundingInfo));
this.mesh.setBoundingInfo(boundingInfo);
this.mesh.position = new BABYLON.Vector3(config.start.x, config.start.y, config.start.z);
}
);
}
And lastly the player’s ‘move’ function…
move() : void {
if (this.mesh && !this.onGround) {
this.velocity.addInPlace(new BABYLON.Vector3(0, this.config.gravity, 0));
}
if(this.mesh && !this.isDead) {
if (this.velocity.y > 0) {
this.mesh.position.addInPlace(this.velocity);
} else {
this.mesh.moveWithCollisions(this.velocity);
}
}
}
You can ‘play’ the game it it’s current state here: https://space-cheetah-1c131.web.app/ (if it won’t load I may have to restart the dyno)
And I stream the development work Sat/Sun/Mon/Tues at 8pm CT (1a GMT) at https://twitch.tv/CoachDench if you ever want to stop by
Thanks for looking at this!