Talking about o:anquan game, Game development, HTML5, Javascript and Phaser.
Recently I played o:anquan on my iPhone, published by Pine Entertainment. The idea behind o:anquan is inspired by the control of a traditional Vietnamese children’s board game. You play on a 6×6 board, and each turn three random numbers between 1 and 9 are placed in three random empty spots on the board. The player at this time can select a number and drag it around the board, only passing across empty spots. At each step, the number decreases and leaves a “1” behind it. At the end of the turn, all matching numbers are removed from the board, and three new numbers appear. The game ends when there aren’t possible moves. It’s really easier to play than to explain, so have a go, since it’s free. The game engine is a simplified version of Globez, the same engine I used in the making of Dungeon Raid tutorial series and in the making of DrawSum HTML5 game which I also ported as a free Google Play Android game, which I invite you to donwload and play as well as read the “making of”. Back to the prototype we are making, at the moment we manage tile movement but we don’t remove tiles from the board and this will be made in next step. If you want to try by yourself, it’s just a flood fill operation. You can have some more information about flood fill at this page. Now, let’s play: select and drag numbers, you can also backtrack. Being the source code almost a copy of Dungeon Raid series, it won’t be commented at the moment, but I will during next step when I’ll finish the game. One of the most interesting things in writing a lot of code, is you can always reuse your code for new projects.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | var game; var gameOptions = { gameWidth: 800, gameHeight: 1400, tileSize: 120, fieldSize: { rows: 6, cols: 6 }, fallSpeed: 250, diagonal: false , colors: [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff] } window.onload = function () { game = new Phaser.Game(gameOptions.gameWidth, gameOptions.gameHeight); game.state.add( "TheGame" , TheGame); game.state.start( "TheGame" ); } var TheGame = function (){}; TheGame.prototype = { preload: function (){ game.stage.backgroundColor = 0x222222; game.load.spritesheet( "tiles" , "assets/sprites/tiles.png" , gameOptions.tileSize, gameOptions.tileSize); }, create: function (){ game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; game.scale.pageAlignHorizontally = true ; game.scale.pageAlignVertically = true ; this .createLevel(); game.input.onDown.add( this .pickTile, this ); }, createLevel: function (){ this .tilesArray = []; this .tileGroup = game.add.group(); this .tileGroup.x = (game.width - gameOptions.tileSize * gameOptions.fieldSize.cols) / 2; this .tileGroup.y = (game.height - gameOptions.tileSize * gameOptions.fieldSize.rows) / 2; for ( var i = 0; i < gameOptions.fieldSize.rows; i++){ this .tilesArray[i] = []; for ( var j = 0; j < gameOptions.fieldSize.cols; j++){ this .addTile(i, j); } } this .placeNumbers(); }, placeNumbers: function (){ var emptySpots = []; for ( var i = 0; i < gameOptions.fieldSize.rows; i++){ for ( var j = 0; j < gameOptions.fieldSize.cols; j++){ if ( this .tilesArray[i][j].value == 0){ emptySpots.push( this .tilesArray[i][j].coordinate); } } } for (i = 0; i < 3; i++){ var item = Phaser.ArrayUtils.removeRandomItem(emptySpots); if (item){ var randomValue = game.rnd.integerInRange(1, 9); this .tilesArray[item.y][item.x].value = randomValue; this .tilesArray[item.y][item.x].frame = randomValue; } } }, addTile: function (row, col){ var tileXPos = col * gameOptions.tileSize + gameOptions.tileSize / 2; var tileYPos = row * gameOptions.tileSize + gameOptions.tileSize / 2; var theTile = game.add.sprite(tileXPos, tileYPos, "tiles" ); theTile.anchor.set(0.5); theTile.value = 0; theTile.picked = false ; theTile.coordinate = new Phaser.Point(col, row); this .tilesArray[row][col] = theTile; this .tileGroup.add(theTile); }, pickTile: function (e){ this .visitedTiles = []; this .visitedTiles.length = 0; if ( this .tileGroup.getBounds().contains(e.position.x, e.position.y)){ var col = Math.floor((e.position.x - this .tileGroup.x) / gameOptions.tileSize); var row = Math.floor((e.position.y - this .tileGroup.y) / gameOptions.tileSize); if ( this .tilesArray[row][col].value > 0){ this .tilesArray[row][col].alpha = 0.5; game.input.onDown.remove( this .pickTile, this ); game.input.onUp.add( this .releaseTile, this ); game.input.addMoveCallback( this .moveTile, this ); this .visitedTiles.push( this .tilesArray[row][col].coordinate); } } }, moveTile: function (e){ if ( this .tileGroup.getBounds().contains(e.position.x, e.position.y)){ var col = Math.floor((e.position.x - this .tileGroup.x) / gameOptions.tileSize); var row = Math.floor((e.position.y - this .tileGroup.y) / gameOptions.tileSize); if (row != this .visitedTiles[ this .visitedTiles.length - 1].y || col != this .visitedTiles[ this .visitedTiles.length - 1].x){ var distance = new Phaser.Point(e.position.x - this .tileGroup.x, e.position.y - this .tileGroup.y).distance( this .tilesArray[row][col]); if (distance < gameOptions.tileSize * 0.4){ var previousTileValue = this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].value; if (! this .tilesArray[row][col].picked && this .checkAdjacent( new Phaser.Point(col, row), this .visitedTiles[ this .visitedTiles.length - 1]) && previousTileValue > 1 && this .tilesArray[row][col].value == 0){ this .tilesArray[row][col].picked = true ; this .tilesArray[row][col].alpha = 0.5; this .tilesArray[row][col].value = previousTileValue - 1; this .tilesArray[row][col].frame = previousTileValue - 1; this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].value = 1; this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].frame = 1; this .visitedTiles.push( this .tilesArray[row][col].coordinate); } else { if ( this .visitedTiles.length > 1 && row == this .visitedTiles[ this .visitedTiles.length - 2].y && col == this .visitedTiles[ this .visitedTiles.length - 2].x){ this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].value = 0; this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].frame = 0; this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].picked = false ; this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].alpha = 1; this .visitedTiles.pop(); this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].value = previousTileValue + 1; this .tilesArray[ this .visitedTiles[ this .visitedTiles.length - 1].y][ this .visitedTiles[ this .visitedTiles.length - 1].x].frame = previousTileValue + 1; } } } } } }, releaseTile: function (){ game.input.onUp.remove( this .releaseTile, this ); game.input.deleteMoveCallback( this .moveTile, this ); game.input.onDown.add( this .pickTile, this ); for ( var i = 0; i < this .visitedTiles.length; i++){ this .tilesArray[ this .visitedTiles[i].y][ this .visitedTiles[i].x].picked = false ; this .tilesArray[ this .visitedTiles[i].y][ this .visitedTiles[i].x].alpha = 1; } if ( this .visitedTiles.length > 1){ this .placeNumbers(); } }, checkAdjacent: function (p1, p2){ if (gameOptions.diagonal){ return (Math.abs(p1.x - p2.x) <= 1) && (Math.abs(p1.y - p2.y) <= 1); } else { return (Math.abs(p1.x - p2.x) == 1 && p1.y - p2.y == 0) || (Math.abs(p1.y - p2.y) == 1 && p1.x - p2.x == 0); } } } |
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.