Crowd performance / kinematic controller in rapier.js

99 Views Asked by At

I'm currently building an auto-shooter / zombie game on the web ( WIP )

And I came across a few perfs issues regarding the kinematic controller / setNextKinematicPosition

Context :

enter image description here

I've got zombies / which are capsuled kinematic entities. They spawn randomly and move across the terrain to attack us.

I'm using a single kinematic player controller for all the zombies and applying kinematic forces so each of them does not pass through actual collided objects + does not pass through other zombies

// set the velocity of the zombie toward the actual direction, and applying gravity in Y position
tempVec.set ( -v31.x * dt * this.targets[i].speed, -9.81 * dt * 2, - v31.z * dt * this.targets[i].speed )


// this is the part that calculate the new position of the zombie

this.characterController.computeColliderMovement(
    this.targets[i].collider._collider,           // The collider we would like to move.
    tempVec, // The movement we would like to apply if there wasn’t any obstacle.
    null,
    null,
    ( collider )=>{

        // this is filter from the collision solver : 
        // if the colliding object is a sensor => no collision

        const isSensor = collider.isSensor()

        return isSensor == false
    }
)

let correctedMovement = this.characterController.computedMovement();

const rpos = this.targets[i].collider.rigidBody.translation()

this.targets[i].position.set(

    rpos.x + correctedMovement.x,
    rpos.y + correctedMovement.y,
    rpos.z + correctedMovement.z
)

this.targets[i].collider.rigidBody.setNextKinematicTranslation(this.targets[i].position)

Problem :

Getting 20 zombies into kinematic forces leads a big drop of performances. I analysed the situation here and did a few check and realised that each zombie performs 10 to a 100 times a collision in the filter by logging the zombieCollisions value in the filter :

enter image description here

let zombieCollisions = 0

this.characterController.computeColliderMovement(
    this.targets[i].collider._collider,           // The collider we would like to move.
    tempVec, // The movement we would like to apply if there wasn’t any obstacle.
    null,
    null,
    ( collider )=>{

        // this is filter from the collision solver : 
        // if the colliding object is a sensor => no collision

        const isSensor = collider.isSensor()

        console.log( zombieCollisions )

        return isSensor == false
    }
)

Solution ?

Well, I've tried so many things, my best bet was to skip the collision test when there are more than a X value using but it ultimately leads to weird behavior and break the simulation kind of :

let zombieCollisions = 0

this.characterController.computeColliderMovement(
    this.targets[i].collider._collider,           // The collider we would like to move.
    tempVec, // The movement we would like to apply if there wasn’t any obstacle.
    null,
    null,
    ( collider )=>{

        // this is filter from the collision solver : 
        // if the colliding object is a sensor => no collision
        // if the current zombie colliders with other zombie more than 6 times => stop colliding

        const isSensor = collider.isSensor()

        const c =  (collider.parent().userData).mesh.componentType
       
        if( c == 'avatar'){

            zombieCollisions++
        }

        return isSensor == false && (c != 'avatar' || zombieCollisions < 6 )
    }
)

Questions :

Is having from 10 to a 100 collision tests per zombie using a kinematic control a standard behavior ?

Is there another way than using the kinematic controller to get the zombie to collide between each other ?

Has there been some benchmarks and tests that I'm not aware of about a kind of "crowd simulation" using rapier.js ? I've been crawling the web to get a solution on this but no chances yet.

Is there a way to spread the collision tests across multiples frame and somehow accepts than sometimes the capsules are merging / passing through for a few frames, without breaking the physics / the perfs ?

It is a long a long post I'm sorry.

Thank you very much for your time

0

There are 0 best solutions below