Calling a function every "nth" second ? - Limiting firing rate of enemy

This is a method inside the Enemy class.

shoot(){
let scene = this.scene;
let name = this.name;

    if(scene.getMeshByName(name) != null){
        if (scene.getMeshByName("Bullet") == null)
        {
            console.log("Enemy shoots");
            fireBullet(this.scene, this.mesh);       
        }         
    }         
}

function fireBullet(scene, mesh){

var bullet = BABYLON.MeshBuilder.CreateSphere("Bullet", { segments: 3, diameter: 0.3 }, scene);
    
bullet.position = mesh.getAbsolutePosition();
bullet.physicsImpostor = new BABYLON.PhysicsImpostor(bullet, 
    BABYLON.PhysicsImpostor.SphereImpostor, 
    { mass: 0.1, friction: 0.5, restition: 0.3 },
    scene);

var dir = scene.activeCamera.position.subtract(mesh.getAbsolutePosition());
bullet.physicsImpostor.applyImpulse(dir.scale(0.5), mesh.getAbsolutePosition());
bullet.life = 0;

bullet.step = ()=>{
    bullet.life++;
    if(bullet.life> 100 && bullet.physicsImpostor){
        bullet.physicsImpostor.dispose();
        bullet.dispose();                
    }
};

scene.onBeforeRenderObservable.add(bullet.step);   

}

And this is how I call the enemy’s shoot method.

function addEnemy(enemyList, scene){

enemyList.push(scene.getMeshByName("skull"));

enemyList[0] = new Enemy(scene, "skull", enemyList[0]);

//Adding up the move() functions of each enemy to the render ovservable
for(let i=0; i<enemyList.length; i++){
    scene.onBeforeRenderObservable.add(function(){enemyList[i].move();});
    scene.onBeforeRenderObservable.add(function(){enemyList[i].shoot();});           
}    

}

I know it seems like a weird way to do what I’m trying to do but how do I limit the firing rate of the enemy. Right now it shoots as soon as the bullet mesh is disposed cause of a collision or if it misses, it’s disposed using the bullet.step() function.

Is it possible to make it shoot every 3 seconds for example ?

[SOLUTION] Implemented based on Null’s reply, for everyone to see if this post is found :

shoot(){             
    let scene = this.scene;       
    let name = this.name;        
    let mesh = this.mesh;
    let timeNow = Date.now();        
    
    if(scene.getMeshByName(name) != null){
        // Checking if enemy's bullet is still in the scene
        if(scene.getMeshByName("Bullet"+name) == null)
        {  
            // Enemy shoots every nth second
            let timePassed = (timeNow - this.timeThen) / 1000;
            let firingRate = 2;                                
            if( timePassed >= firingRate){
                fireBullet(scene, mesh, name );
                this.timeThen = timeNow;
            }              
        }                
    }         
}

Hey there, why don’t you keep a counter in the update function adding it with the previous elapsed time. Then call a new shoot when the value of the counter is bigger than 3000ms say and make the counter zero again. This way you also don’t shoot onDispose anymore.

1 Like

I lost you a bit sorry I’m not experienced. What do you mean by “update function” ?

Also keeping a counter I think won’t be possible cause the shoot() function is called every time like a new one and the counter doesn’t carry over between each call.

Please correct me if I’m wrong.

The update function is the function called in the render loop. You are using the onBeforeRenderObservable for example.

In the end it comes down to how you have structured your project. How I would do it, I would make a character class which calls the “shoot” function. In this case you keep the counter as a class property. By adding an update function in the character class then you can do what I suggested before.

1 Like

Late reply but for some reason it took me a long time to implement this. I guess I needed a break cause yesterday I couldn’t do it for so many hours,probably I was hazy cause of all the previous work for the day and I just did it in 5 minutes.

If you spot anything dodgy, or any other suggestion in general please care to mention it !

Thank you :relaxed:

shoot(){             
    let scene = this.scene;       
    let name = this.name;        
    let mesh = this.mesh;
    let timeNow = Date.now();        
    
    if(scene.getMeshByName(name) != null){
        // Checking if enemy's bullet is still in the scene
        if(scene.getMeshByName("Bullet"+name) == null)
        {  
            // Enemy shoots every nth second
            let timePassed = (timeNow - this.timeThen) / 1000;
            let firingRate = 2;                                
            if( timePassed >= firingRate){
                fireBullet(scene, mesh, name );
                this.timeThen = timeNow;
            }              
        }                
    }         
}