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!