Search code examples
javascriptphaser-frameworkparticles

Phaser 3 - Particles become more the more often I emit them?


I have particles that I emit when clicking and moving my mouse over a certain object. However I noticed that while the particles start out as little, they become more and more the more often I click and move my mouse,until the stream of particles is far too dense.

This only seems to happen when I click down multiple times (thus triggering the pointerdown event multiple times), not when I click once and keep moving.

How can I stop this?

function pet(start, scene, pointer = null)
{
    if(start){
        scene.input.on('pointermove', function(){
            if (scene.input.activePointer.isDown && gameState.chara.getBounds().contains(scene.input.activePointer.x, scene.input.activePointer.y)){
                gameState.sparkle.emitParticle(1,scene.input.activePointer.x, scene.input.activePointer.y);   // !!!! Here is where I emit my particles
            }
        });
    } else {
        gameState.sparkle.stop();   // !!!! Here I stop my particles
    }
}

const gameState = {
    gameWidth: 800,
    gameHeight: 800,
    menu: {},
    textStyle: { 
        fontFamily: "'Comic Sans MS'", 
        fill: "#fff", 
        align: "center",
        boundsAlignH: "left", 
        boundsAlignV: "top"
    },
};

function preload()
{
    this.load.baseURL = 'assets/';
    
    //  Chara
    this.load.atlas('chara', 'chara.png', 'chara.json');
    
    // Particle
    this.load.image('sparkle', 'sparkle.png');  // Here I load my particle image
    
}

function create()
{
    // Scene
    let scene = this;
    
    // Chara
    this.anims.create({
        key: "wag",
        frameRate: 12,
        frames: this.anims.generateFrameNames("chara", {
            prefix: 'idle_000',
            start: 0, 
            end: 5}),
        repeat: 0,
    });
    this.anims.create({
    key: "happy",
        frameRate: 12,
        frames: this.anims.generateFrameNames("chara", {
            prefix: 'happy_000',
            start: 0, 
            end: 5}),
        repeat: -1
    });
    gameState.chara = this.add.sprite(400, 400, "chara", "idle_0000");
    gameState.chara.setInteractive({cursor: "pointer"});
    
    // !!!! Here I set up my Particle Emitter !!!!
    gameState.sparkle = this.add.particles('sparkle').createEmitter({
        x: gameState.height/2,
        y: gameState.width/2,
        scale: { min: 0.1, max: 0.5 },
        speed: { min: -100, max: 100 },
        quantity: 0.1,
        frequency: 1,
        lifespan: 1000,
        gravityY: 100,
        on: false,
    });

    gameState.chara.on('pointerdown', function(){ pet(true, scene) });
    gameState.chara.on('pointerout', function(){ pet(false, scene, 'default') });
    gameState.chara.on('pointerup', function(){ pet(false, scene, 'pointer') });
}

function update()
{   

}

// Configs

var config = {
    backgroundColor: "0xf0f0f0",
    scale: {
        width: gameState.gameWidth,
        height: gameState.gameHeight,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: {
        preload, create, update
    }
};
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>


Solution

  • The problem is, that you are adding a new scene.input.on('pointermove',...) event-handler in the pet function, on each click.

    I would only change the code abit (look below), this should prevent generating too many particles and too many event-handlers (too many event-handlers could harm performance, so be careful, when adding them).

    Here is how I would modify the Code:
    (I stripped out and added some stuff to make the demo, easier to understand and shorter. And also that the snippet can be executed, without errors/warnings)

    The main changes are marked and explained in the code, with comments

    function pet(start, scene, pointer = null)
    {
        if(start){
            // Update: remove Event listener add click state
            gameState.mouseDown = true
        } else {
            // Update: add click state
            gameState.mouseDown = false;
            gameState.sparkle.stop();
        }
    }
    
    const gameState = {
        gameWidth: 400,
        gameHeight: 200,
       // Update: add click state
        mouseDown: false
    };
    
    function create()
    {
         // Scene
         let scene = this;
        
         // Just could for Demo START
         var graphics = this.add.graphics();
         graphics.fillStyle(0xff0000);
         graphics.fillRect(2,2,10,10);
         graphics.generateTexture('particle', 20, 20);
         graphics.clear();
         graphics.fillStyle(0xffffff);
         graphics.fillRect(0,0,40,40);
         graphics.generateTexture('player', 40, 40);
         graphics.destroy();
         // Just Code for Demo END
    
        gameState.chara = this.add.sprite(200, 100, "player");
        gameState.chara.setInteractive({cursor: "pointer"});
        
        gameState.sparkle = this.add.particles('particle').createEmitter({
            scale: { min: 0.1, max: 0.5 },
            speed: { min: -100, max: 100 },
            quantity: 0.1,
            frequency: 1,
            lifespan: 1000,
            gravityY: 100,
            on: false,
        });
    
        gameState.chara.on('pointerdown', function(){ pet(true, scene) });
        gameState.chara.on('pointerout', function(){ pet(false, scene, 'default') });
        gameState.chara.on('pointerup', function(){ pet(false, scene, 'pointer') });
        
        // Update: add new single Event Listener
        gameState.chara.on('pointermove', function(pointer){
            if(gameState.mouseDown){
              gameState.sparkle.emitParticle(1,pointer.x, pointer.y); 
            }
        });
    }
    
    // Configs
    var config = {
        width: gameState.gameWidth,
        height: gameState.gameHeight,
        scene: { create }
    };
    var game = new Phaser.Game(config);
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>