Collisions for some 'moved' meshes are not detected with the Null Engine

I’m using the Null Engine server side to maintain game state for a multi-player game. Client-side collision detection appears to be working, but with the null engine, players will fall through after leaving the first platform:

platforms

In the image above the players spawn on the ‘red’ platform, but will fall through the other platforms - but only according to the server state.

The client calculates and renders the expected collision, but the next update from the server results in the screenshot above.

1 Like

Pinging @RaananW

1 Like

Hi Patrick,

would you be able to show me the part of code that is not working? Would be great to try and debug this and see why the collisions don’t work correctly. As it is the same code (and the engine has no direct collision code in it) it will be very interesting to see what’s going on there.

A quick question - how do you keep the synchronization between the user and the server? constant network/socket updates? Are you providing the movement of the player? the player’s final position?

@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:

  1. Player presses jump
  2. Client animates the player jumping
  3. Client sends ‘Jump’ command to the server
  4. Server ‘animates’ the jump and sends the updated character velocity to all the clients
  5. 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!

OK!

Let;s take it from here -

https://www.babylonjs-playground.com/#3Y7Z0W#1

This is a null engine reference of everything you pasted here. Remove the createEngine reference at the bottom (delete. don’t comment out, as it keeps it as a reference) and you will see how it works in the regular engine.

The null engine is working, let’s try reproducing your issue here and see whether or not you can understand what the problem is on your platform.

2 Likes

I’ve (finally) got to testing the code, and can see it working in the playground, but locally the ActionManager ‘ExecuteCodeAction’ is never called.

I’ve replaced the character loaded with a ‘box’ model on the server and had the same results, and removed the collision groups… same.

I’ve tried similar intersection logic on the server:

`this.onGround = false;
this.mesh && this.platforms.forEach(p => this.onGround = this.onGround || p.mesh.intersectsMesh(this.mesh));`

But the server seems to think the player (box) mesh is ALWAYS intersecting with the platforms - but this ONLY happens on the server.

So I have identical code on the client and server now, and I’m still getting the same behavior.

I added some console log out put after the platform meshes are moved - and the bounding boxes/spheres have the same center after their position is set - is that expected?

@Patrick_Dench, could you try console.logging the position and absolutePosition of the player mesh on the server side? If they are not matching up, then maybe you could try mesh.computeWorldMatrix(true).

I’ve also noticed unexpected positioning with NullEngine, especially with meshes that are children of other meshes. I’ve seen absolutePosition taking a long time to update after modifications to position (almost as if absolutePosition is slowly interpolating towards the value of position instead of immediately taking its value).

I worked around this by creating entirely new “dummy” meshes with no parents.

Edit: For context, I ran into this error when “rewinding” (or moving back in time) the player mesh on the server side for bullet collisions to take place in the correct past game state. However, when I “rewinded” the player by updating its position, its position was updated correctly, however its absolutePosition was heavily lagging behind updates to its position. Thus, bullet collisions failed to register correctly.

As mentioned, I worked around this by creating an entirely new “dummy” mesh for the rewind and ran bullet collision detection on this “dummy” mesh (and left the actual player mesh untouched).

are you referring to center or center world? center should be the same. center world should change constantly.

I believe this is an async problem between your client code and the server. Some important piece of information is not being sent on time or is not processed as on the client. It is either that or that the initial server initialization is not correct.

The null server is nothing more than a regular engine without the rendering. Check how the render loop works on both, make sure they are fully synced, mock actions on the server and see if it works there correctly before bringing in network communication to the game.