Complete HTML5 Concentration game made with PIXI.js – Adding animation with Tween.js

Read all posts about "" game

Some days ago I showed you the basics on PIXI.js by making a simple yet complete Concentration game.

Later, a reader called Bence Dobos improved it by adding some animations made with TweenJS library.

TweenJS is a simple tweening library for use in Javascript. It was developed to integrate well with the EaselJS library, but is not dependent on or specific to it. It supports tweening of both numeric object properties & CSS style properties. The API is simple but very powerful, making it easy to create complex tweens by chaining commands.

By adding different types of tweens according to game events (placing tiles, turning tiles, removing tiles), Bence improved the visual appeal of the game.

Try it by yourself:

Click on tiles and try to match them.

And here is the source code with new lines highlighted:

<!DOCTYPE HTML>
<html>
     <head>
          <title>PIXI Concentration</title>
          <style>
               body {
                    margin: 0;
                    padding: 0;
                    background-color: #885500;
               }
          </style>
          <script src="pixi.dev.js"></script>
          <script src="tweenjs.js"></script>
     </head>
     <body>
          <script>
               // first tile picked up by the player
               var firstTile=null;
               // second tile picked up by the player
               var secondTile=null;
               // can the player pick up a tile?
               var canPick=true;
               // create an new instance of a pixi stage with a grey background
               var stage = new PIXI.Stage(0x888888);
               // create a renderer instance width=640 height=480
               var renderer = PIXI.autoDetectRenderer(640,480);
               // add the renderer view element to the DOM
               document.body.appendChild(renderer.view);
               // importing a texture atlas created with texturepacker
               var tileAtlas = ["images.json"];
               // create a new loader
               var loader = new PIXI.AssetLoader(tileAtlas);			         
               // create an empty container
               var gameContainer = new PIXI.DisplayObjectContainer();
               // add the container to the stage
               stage.addChild(gameContainer);
               // use callback
               loader.onComplete = onTilesLoaded
               //begin load
               loader.load();	
               function onTilesLoaded(){
                    // choose 24 random tile images
                    var chosenTiles=new Array();
                    while(chosenTiles.length<48){
                         var candidate=Math.floor(Math.random()*44);
                         if(chosenTiles.indexOf(candidate)==-1){
                              chosenTiles.push(candidate,candidate)
                         }			
                    }
                    // shuffle the chosen tiles
                    for(i=0;i<96;i++){
                         var from = Math.floor(Math.random()*48);
                         var to = Math.floor(Math.random()*48);
                         var tmp = chosenTiles[from];
                         chosenTiles[from]=chosenTiles[to];
                         chosenTiles[to]=tmp;
                    }
                    // place down tiles
                    for(i=0;i<8;i++){
                         for(j=0;j<6;j++){
                              // new sprite
                              var tile = PIXI.Sprite.fromFrame(chosenTiles[i*6+j]);
                              // buttonmode+interactive = acts like a button
                              tile.buttonMode=true;
                              tile.interactive = true;
                              // is the tile selected?
                              tile.isSelected=false;
                              // set a tile value
                              tile.theVal=chosenTiles[i*6+j];
                              // place the tile
                              tile.position.x = Math.random()*600;
                              tile.position.y = -Math.random()*100 - 100;
                              tile.rotation = Math.random()*2*3.14;
                              // paint tile black
                              tile.tint = 0x000000;
                              // set it a bit transparent (it will look grey)
                              tile.alpha=0.5;
                              new TWEEN.Tween(tile)
                                   .to({x: 7+i*80, y: 7+j*80, rotation:0}, 2400 + Math.random()*1200)
                                   .easing(TWEEN.Easing.Elastic.Out)
                              .start();
                              // add the tile
                              gameContainer.addChild(tile);
                              // mouse-touch listener
                              tile.mousedown = tile.touchstart = function(data){
                                   // can I pick a tile?
                                   if(canPick) {
                                        // is the tile already selected?
                                        if(!this.isSelected){
                                             new TWEEN.Tween(this)
                                                  .to({width:0.0, x:"+32"}, 300)
                                                  .easing(TWEEN.Easing.Linear.None).onComplete(function() {
                                                       this.tint = 0xffffff;
                                                  })
                                                  .chain(new TWEEN.Tween(this)
                                                  .to({alpha: 1.0, width:64, x:"-32"}, 300)
                                                  .easing(TWEEN.Easing.Linear.None))
                                             .start();
                                             // set the tile to selected
                                             this.isSelected = true;
                                             // show the tile
                                             //this.tint = 0xffffff;
                                             //this.alpha = 1;
                                             // is it the first tile we uncover?
                                             if(firstTile==null){
                                                  firstTile=this
                                             }
                                             // this is the second tile
                                             else{
                                                  secondTile=this
                                                  // can't pick anymore
                                                  canPick=false;
                                                  // did we pick the same tiles?
                                                  if(firstTile.theVal==secondTile.theVal){
                                                       // wait a second then remove the tiles and make the player able to pick again
                                                       setTimeout(function(){
                                                            new TWEEN.Tween(firstTile)
                                                                 .to({width:"+100", height:"+100", x:"-50", y:"-50", alpha:0.0}, 600)
                                                                 .easing(TWEEN.Easing.Linear.None)
                                                                 .onComplete(function() {
                                                                      gameContainer.removeChild(this);
                                                                 })
                                                            .start();
                                                            new TWEEN.Tween(secondTile)
                                                                 .to({width:"+100", height:"+100", x:"-50", y:"-50", alpha:0.0}, 600)
                                                                 .easing(TWEEN.Easing.Linear.None).onComplete(function() {    
                                                                      gameContainer.removeChild(this);
                                                                      canPick=true;
                                                                 })
                                                            .start();
                                                            firstTile=null;
                                                            secondTile=null;
                                                       },1000);
                                                  }
                                                  // we picked different tiles
                                                  else{
                                                       // wait a second then cover the tiles and make the player able to pick again
                                                       setTimeout(function(){
                                                            firstTile.isSelected=false
                                                            secondTile.isSelected=false
                                                            new TWEEN.Tween(firstTile)
                                                                 .to({alpha: 0.5, width:0.0, x:"+32"}, 150)
                                                                 .easing(TWEEN.Easing.Linear.None).onComplete(function() {
                                                                      this.tint = 0x000000;
                                                                 })
                                                                 .chain(new TWEEN.Tween(firstTile)
                                                                 .to({width:64, x:"-32"}, 150)
                                                                 .easing(TWEEN.Easing.Linear.None))
                                                            .start();
                                                            new TWEEN.Tween(secondTile)
                                                                 .to({alpha: 0.5, width:0.0, x:"+32"}, 150)
                                                                 .easing(TWEEN.Easing.Linear.None)
                                                                 .onComplete(function() {
                                                                      this.tint = 0x000000;
                                                                      canPick=true;
                                                                 })
                                                                 .chain(new TWEEN.Tween(secondTile)
                                                                 .to({width:64, x:"-32"}, 150)
                                                                 .easing(TWEEN.Easing.Linear.None))
                                                            .start();
                                                            firstTile=null;
                                                            secondTile=null;
                                                       },1000);
                                                  }
                                             }	
                                        }
                                   }
                              }
                         }
                    } 
                    requestAnimFrame(animate);
               }
               function animate() {
                    requestAnimFrame(animate);
                    TWEEN.update();
                    renderer.render(stage);
               }
          </script>
     </body>
</html>

As usual you can also download the entire project, libraries included.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

215 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stairs
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers