Phaser Snow

Let There Be Snow!

I’ll admit I’m not anywhere near snow while writing this, but I love it as an effect in a game, and since it is seasonal to Christmas time, I was inspired to put this together.

The original code

Originally I had placed several flakes, which was a simple Phaser graphic and looping through the group with a forEach

this.snowGroup.forEach(function(flake){
	flake.y++;
}.bind(this))

This worked fine at first, but the problem came when I tried to increase the number of flakes from 50 to 200, and then as a test up to 500. The code started going sluggish, and then I remembered an old interview question about a starfield. I have to admit I failed that interview question but looked the answer up later after becoming obsessed with the problem.

A linked list

A linked list works by each child of a group having a reference to the child before or after it, or sometimes both. Once you have the reference you call a function of the first or last child in the group, and that function then calls the same function in the next or previous child, and it starts a chain reaction. This can be incredibly fast! I implement this in the move function of the flake class below.

 

Click the image to see the result

How to use

//change width and height if you only want to use a
//small area
var snow=new Snow(game.width,game.height);

The Code

The Snow Class

class Snow extends Phaser.Group {
    constructor(w = 200, h = 200) {
        super(game);
        this.w = w;
        this.h = h;
        this.lastFlake = null;
        //
        //
        //
        this.makeFlakes();
    }
    makeFlakes() {
        for (var i = 0; i < 250; i++) {
            var flake = new Flake(this.w, this.h);
            //if the last flake exists 
            //place it as the prev flake
            if (this.lastFlake != null) {
                flake.prevFlake = this.lastFlake;
            }
            this.lastFlake = flake;
        }
    }
    update() {
    	//move the last flake
    	//this will start a chain reaction
        this.lastFlake.move();
    }
}

The Flake Class

class Flake extends Phaser.Group {
    constructor(w, h) {
        super(game);

        //make the graphic
        var f = game.add.graphics();
        f.beginFill(0xffffff, 1);
        f.drawCircle(0, 0, 10);
        f.endFill();
        this.add(f);
        //
        //
        this.w=w;
        this.h=h;
        //
        //
        //init properties
        
        this.y = game.rnd.integerInRange(0, h);
        this.reset();
    }
    reset()
    {
    	//re-init properites
    	this.x = game.rnd.integerInRange(0, this.w);
    	this.drift = game.rnd.integerInRange(-1, 1) * (.05 + Math.random() * .1);
        this.fallSpeed = 1 + Math.random() * 10;
        this.scale.x = .1 + Math.random();
        this.scale.y = this.scale.x;
        this.alpha = .1 + Math.random();
    }
    move()
    {
    	this.x+=this.drift;
    	this.y+=this.fallSpeed;
    	if (this.y>this.h)
    	{
    		//take back to top
    		this.y=-10;
    		this.reset();
    	}
    	if (this.prevFlake)
    	{
    		//move the previous flake
    		this.prevFlake.move();
    	}
    }
}

Happy Holidays Looking forward to more Phaser in 2018!

Leave a Comment