HTML5 deck of cards management updated to Phaser 3

Read all posts about "" game

About three years ago I published a HTML5 card management prototype built with Phaser, and since developers are bringing back card games, here I am to update the prototype to Phaser 3, since the original post uses an old Phaser 2 version.

A deck of cards is shuffled and the first card is drawn on the table. Then you can swipe up to make next card appear above current card or swipe down to make next card appear below current card. Then next card takes the place of the current card which leaves the stage, and you can swipe to call the third card, and so on.

It could be useful for one of those games where players try to guess if next card will be higher or lower than current one.

Have a look at the prototype:

Swip up or down to draw next card.

The updated source code is also completely commented, for a clean understanding of the whole process:

// the game itself
let game;

// global object with game options
let gameOptions = {

    // card width, in pixels
    cardWidth: 334,

    // card height, in pixels
    cardHeight: 440,

    // card scale. 1 = original size, 0.5 half size and so on
    cardScale: 0.8
}
window.onload = function() {
    let gameConfig = {
        type: Phaser.AUTO,
        backgroundColor: 0x4488aa,
        scale: {
            mode: Phaser.Scale.FIT,
            autoCenter: Phaser.Scale.CENTER_BOTH,
            parent: "thegame",
            width: 750,
            height: 1334
        },
        scene: playGame
    }
    game = new Phaser.Game(gameConfig);
    window.focus();
}

// two constants for better understanding of "UP" and "DOWN"
const UP = -1;
const DOWN = 1;
class playGame extends Phaser.Scene {
    constructor() {
        super("PlayGame");
    }
    preload() {

        // loading the sprite sheet with all cards
        this.load.spritesheet("cards", "cards.png", {
            frameWidth: gameOptions.cardWidth,
            frameHeight: gameOptions.cardHeight
        });
    }
    create() {

        // can we swipe?
        this.canSwipe = true;

        // create an array with 52 integers from 0 to 51
        this.deck = Phaser.Utils.Array.NumberArray(0, 51);

        // shuffle the array
        Phaser.Utils.Array.Shuffle(this.deck);

        // the two cards in game
        this.cardsInGame = [this.createCard(0), this.createCard(1)];

        // we already have card 0 and 1 in game so next card index is 2
        this.nextCardIndex = 2;

        // a tween to make first card enter into play
        this.tweens.add({
            targets: this.cardsInGame[0],
            x: game.config.width / 2,
            duration: 500,
            ease: "Cubic.easeOut"
        });

        // listener for player input
        this.input.on("pointerup", this.checkSwipe, this);
    }

    // method to create a card, given an index
    createCard(i) {

        // the card itself, a sprite created outside the stage, on the left
        let card = this.add.sprite(- gameOptions.cardWidth * gameOptions.cardScale, game.config.height / 2, "cards", this.deck[i]);

        // scale the sprite
        card.setScale(gameOptions.cardScale);

        // return the card
        return card;
    }

    // method to check if player input was a swipe
    checkSwipe(e) {

        // can the player swipe?
        if(this.canSwipe) {

            // determine swipe time, "release" timestamp minus "press" timestamp
            let swipeTime = e.upTime - e.downTime;

            // determine swipe vector
            let swipe = new Phaser.Math. Vector2(e.upX - e.downX, e.upY - e.downY);

            // get the magnitude, or length, of swipe vector
            let swipeMagnitude = swipe.length();

            // reduce the vector to a magnitude of 1
            let swipeNormal = swipe.normalize();

            // we have a vertical swipe when:
            // * swipeMagnitude is bigger than 20, that is the player swiped for at least 20 pixels
            // * swipeTime is less than 1 second, gestures longer than one second can't be considered swipes
            // * the absolute value of the y component of the normal is 0.8
            if(swipeMagnitude > 20 && swipeTime < 1000 && Math.abs(swipeNormal.y) > 0.8) {

                // swiping down
                if(swipeNormal.y > 0.8) {
                    this.handleSwipe(DOWN);
                }

                // swiping up
                if(swipeNormal.y < -0.8) {
                    this.handleSwipe(UP);
                }
            }
        }
    }

    // method to handle a swipe, given the direction
    handleSwipe(direction) {

        // we are swiping so we can't swipe anymore
        this.canSwipe = false;

        // which card are we moving?
        let cardToMove = (this.nextCardIndex + 1) % 2;

        // set moving card vertical position
        this.cardsInGame[cardToMove].y += direction * gameOptions.cardHeight * gameOptions.cardScale * 1.1;


        // tween the card to move to the horizontal center of the stage...
        this.tweens.add({
            targets: this.cardsInGame[cardToMove],
            x: game.config.width / 2,
            duration: 500,
            ease: "Cubic.easeOut",
            callbackScope: this,
            onComplete: function() {

                // ... then wait a second or little more...
                this.time.addEvent({
                    delay: 1200,
                    callbackScope: this,

                    // ... then call moveCards method
                    callback: this.moveCards,
                });
            }
        })
    }

    // method to update cards position
    moveCards() {

        // moving the first card
        let cardToMove = this.nextCardIndex % 2;

        // tween the card outside of the stage to the right
        this.tweens.add({
            targets: this.cardsInGame[cardToMove],
            x: game.config.width + 2 * gameOptions.cardWidth * gameOptions.cardScale,
            duration: 500,
            ease: "Cubic.easeOut"
        });

        // moving the second card
        cardToMove = (this.nextCardIndex + 1) % 2;

        // tween the card to the center of the stage...
        this.tweens.add({
            targets: this.cardsInGame[cardToMove],
            y: game.config.height / 2,
            duration: 500,
            ease: "Cubic.easeOut",
            callbackScope: this,
            onComplete: function(){

                // ... then recycle the card which we moved outside the screen
                cardToMove = this.nextCardIndex % 2;
                this.cardsInGame[cardToMove].setFrame(this.deck[this.nextCardIndex]);
                this.nextCardIndex = (this.nextCardIndex + 1) % 52;
                this.cardsInGame[cardToMove].x = gameOptions.cardWidth * gameOptions.cardScale / -2;

                // now we can swipe again
                this.canSwipe = true;
            }
        });
    }
}

Inside the source code of the project you will also find a PSD file with the card spritesheet, courtesy of game-icons.net, but keep in mind the texture I used is just for this test and it’s way too big for most, if not all, mobile devices.

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