DEV Community

Roman Guivan
Roman Guivan

Posted on

match 3 game in pixi.js 103: JUICE and POLISH

After PART 1 and PART 2 we're left with an app that has the humble beginnings of a match-three game, but still won't be sufficient to get you a PASS if it was any kind of assignment

Let's add some sprinkles here and there, once you're done - the result might end up being somthing like this (or way better, it's all in your hands, really!)

Animations

The easiest cheapest way to animate sprites without additional animation frames (which i don't have) is to change sprite's properties over time. Position, scale and tint are my TOP-3. If i would like my animals to EXPAND a bit, after they're added onto the screen, something like this would totally do:

  function animate(sprite) {
      setTimeout(()=> sprite.scale.set(0.9, 0.9), 100);
      setTimeout(()=> sprite.scale.set(1.1, 1.1), 200);
      setTimeout(()=> sprite.scale.set(1.0, 1.0), 300);
  }
Enter fullscreen mode Exit fullscreen mode

The results would be a bit crude and jerky, but you get the idea. Here's a 60fps version of this same function

  function animate(sprite, scaleTo, timeSeconds) {
      const frames = timeSeconds * 60, timePerFrameSeconds = 1 / 60;
      for (let i=0; i< frames; i++) {
         const frameTimeSeconds = timePerFrameSeconds * i;
         const scale = i / frames * scaleTo;
         setTimeout(()=> sprite.scale.set(scale, scale), frameTimeSeconds * 1000);
      }
  }
Enter fullscreen mode Exit fullscreen mode

Again, crude, requestAnimationFrame would perform better than setTimeout, I'm using this code for explaining purposes only.

What we achieved here is called linear interpolation. We gradually changed value of sprite scale, over time, till sprite.scale became scaleTo. While linear interpolation is perfectly fine, human eye finds these most tasteless and dull. Tween.js to the rescue!

Tween.js will calculate interpolated values for different kinds of easing functions, so instead of linear - your animated scaling can be exponential or use one of many other functions available.

You can check the animations (or just tweens) i have used in the game here For example, this same scale animation looks like this:

    export function popIn(sprite, time = 300) {
const props = { x: 0.8, y: 0.8 };
new TWEEN.Tween(props)
    .to({ x: 1, y: 1 }, time)
    .easing(TWEEN.Easing.Bounce.Out) // Use an easing function to make the animation smooth.
    .onUpdate(() => {
        sprite.scale.x = props.x;
        sprite.scale.y = props.y
    })
    .start()
  }
Enter fullscreen mode Exit fullscreen mode

Now add popIn(sprite); somewhere after you have added it onto screen with this.addChild(sprite) and you're golden! Things "pop-in" nicely. I suggest you try animating sprite.tint too, to add some color to it.

IMPORTANT NOTE
Tween.js has an .update() function that has to be called too, with a timestamp. PIXI's dt, or one from requestAnimationFrame won't do. What does work for me, is passing performance.now() value. Here's the place where i do it in my implementation

Sounds

You can write your own wrapper around HTML5 audio, insert an element, listen to load event and so on, but for practical purposes i suggest you give howler.js a try.

Get some free sounds from https://freesound.org/, organize them into your static assets folder, then you can create a separate audio.js module and trigger sound effects as exported members

Some looping background theme music might be a good idea too.

Once again the source of the example can be found here or just play the deployed version

If you have followed this series, and actually made something of yours - post links or your questions in the comments bellow.

I think at it's current state the repo already shows the basics of making a match-three game in PIXI.js. A losing condition and some additional scenes like a menu and a game over screen still can be added. If you're interested in these being explained - leave it in the comments below too.

For now - i'm leaving this series here, hope you liked it. Roman G - signing off

Discussion (0)