Talking about A Blocky Christmas game, Actionscript 3, Flash and Game development.
As you should know, tomorrow it’s Christmas, and I think you are expecting some Christmas gifts, so let me show you the Christmas gift I am giving to you all.
Did you play Bart Bonte‘s smash hit a blocky Christmas?
It’s one of the best yet simple games I played in the last months, and I am going to show you how to make your own blocky puzzle game following eight easy steps.
But before all, spend some (if not several) minutes to solve the game, the levels are really well designed and I am sure you will enjoy it.
Now, let’s start with the tutorial. Basically, a blocky Christmas is a tile based game, so all we need is an array and some coordinates.
1) Creating and showing of the game field
We are about to build level 5, because it includes everything we need to test all game features, and it’s easy to solve, so you will be able to test it without burning your brain.
The game field is a 19×19 array with walkable areas, walls, the player itself (a 1×1 green block) and some other green blocks you have to move to the goal.
So we are going to define some variables:
tileSize: the size, in pixels, of a tile.
gameField: a two-dimensional array with level walls (1) and walkable tiles (0).
player: a Point
variable holding player’s x and y starting position.
playerGoal: a Point
variable holding player’s x and y goal position.
blocks: an array of objects representing a block. Every block object contains an array of points defining its shape and the color we will use to render it.
goals: an array of objects containing an array of points defining the goal position of each block. I used an object although it contains only one item (the array) to let you expand the game easily.
The entire game is then rendered by displayGame
function which lazily clears and redraws the entire level every time we need it, but it’s ok anyway as rendering the level in a fancy way is beyond the scope of this tutorial.
This is the script:
package {
import flash.display.Sprite;
import flash.geom.Point;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
public function Main() {
displayGame();
}
private function displayGame():void {
graphics.clear();
graphics.lineStyle(1,0x000000,0.2);
for (var i:Number=0; i
And this is the result:
We have our level rendered, now it's time to allow some interaction.
2) Moving the player with arrow keys
From now on, the new blocks of code added, or rewritten, are included between start of new code
and end of new code
comments, so you can easily see what I am going to add/change to previous scripts.
At this time we need to add a KeyboardEvent
listener to check for pressed keys, assign a possible move among up, down, left and right and check if the player can move in such direction. In this case, we update player position and render the level once more.
The function which decides if the player can move is possibleMove
and at the moment it only returns true
, meaning the player can always move.
I am storing the possible move in a Point
variable, using it to save the x and y offsets of the desired player movement, so it will be (0,-1) if the player goes up, (1,0) if the player goes right, and so on.
This is the code:
package {
import flash.display.Sprite;
import flash.geom.Point;
// ******************* start of new code ******************* \\
import flash.events.KeyboardEvent;
// ******************** end of new code ******************** \\
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
// ******************* start of new code ******************* \\
private var possibleMove:Point;
// ******************** end of new code ******************** \\
public function Main() {
displayGame();
// ******************* start of new code ******************* \\
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
// ******************** end of new code ******************** \\
}
// ******************* start of new code ******************* \\
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
player.x+=possibleMove.x;
player.y+=possibleMove.y;
displayGame();
}
}
private function checkPlayerMove():Boolean {
return true;
}
// ******************** end of new code ******************** \\
private function displayGame():void {
graphics.clear();
graphics.lineStyle(1,0x000000,0.2);
for (var i:Number=0; i
And this is the result:
Move the player with arrow keys around the screen.
Unfortunately, the player does not move alone, as it's also a magnet
3) Introducing magnetism
If close to a moveable block, the player also acts as a magnet, so we expect it to pull and push attached blocks as it moves around the screen.
In this step, I am going to see when a block is directly attached to the player and make it follow player movement.
To see if a block is directly attached to the player, the Manhattan distance between the player and one of the block tiles must be one. If you need more information about Manhattan distance, check the post the fastest way to find the distance between two points.
So if we have a block directly attached to the player, we can move it in the same player direction.
This is the code:
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
private var possibleMove:Point;
public function Main() {
displayGame();
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
}
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
// ******************* start of new code ******************* \\
checkMagnet();
// ******************** end of new code ******************** \\
player.x+=possibleMove.x;
player.y+=possibleMove.y;
displayGame();
}
}
// ******************* start of new code ******************* \\
private function checkMagnet():void {
for (var i:Number=0; i
and this is the result:
You will be able to push and pull blocks around the screen, but only if you are directly adjacent to them, while in the original game a block attached to the player also becomes magnetic and is able to attach other blocks.
4) Extending magnetism
One of the ways to check for blocks attached to blocks which are attached to the player would be some kind of recursive flood fill algorithm. Check flood fill implementation post for more information about flood fill.
This time I won't use recursion, so I need to check for all tiles adjacent to each block for another block, which in this case will inherit the magnetism, and to avoid infinite loops (e.g. I am checking A and find B is adjacent, so I am checking B and find A is adjacent so I am checking A...) I need to store visited blocks into an array, this way if a block is not in the array, I can be sure it's the first time I meet it.
This is the code:
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
private var possibleMove:Point;
public function Main() {
displayGame();
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
}
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
checkMagnet();
player.x+=possibleMove.x;
player.y+=possibleMove.y;
displayGame();
}
}
// ******************* start of new code ******************* \\
private function checkMagnet():void {
var magneticBlocks:Array=new Array();
var visited:Array=[player];
for (var n:Number=0; n
And this is the result:
Now blocks inherit magnetism and the whole game moves all actors correctly, so now we must start to limit player movements.
5) Preventing player to go through walls
The first way we are going to limit player movement, is preventing it to go through walls, that is the player cannot stand over tiles marked with 1.
It's time to work a bit on checkPlayerMov
e function:
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
private var possibleMove:Point;
public function Main() {
displayGame();
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
}
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
checkMagnet();
player.x+=possibleMove.x;
player.y+=possibleMove.y;
displayGame();
}
}
private function checkMagnet():void {
var magneticBlocks:Array=new Array();
var visited:Array=[player];
for (var n:Number=0; n
And this is the result:
Now walls stop the player, but they don't stop attached blocks.
6) Preventing blocks to go through walls
Preventing blocks to go through walls is not different than preventing the player to go through walls, you just need to check blocks not to overlap walls tile by tile.
This is the code:
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
private var possibleMove:Point;
public function Main() {
displayGame();
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
}
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
checkMagnet();
player.x+=possibleMove.x;
player.y+=possibleMove.y;
displayGame();
}
}
private function checkMagnet():void {
var magneticBlocks:Array=new Array();
var visited:Array=[player];
for (var n:Number=0; n
And this is the result:
Now blocks cannot overlap walls, but they still can overlap each others
7) Preventing blocks to overlap each others
This is the most difficult thing to do without using recursive functions. Basically if a block can move (because it won't overlap any wall) but it would push another block which cannot move, the unmovable block should by threated like a solid wall, preventing the first block too to move, which becomes a wall preventing the player to push it.
It sounds complicate but you just need to scan through all blocks, transforming them to walls if they cannot move, and then run the previous routines with the remaining, free blocks.
Don't forget, at the end of the process, to clear the fake walls you set when dealing with unmoveable blocks.
This is the code:
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
private var possibleMove:Point;
public function Main() {
displayGame();
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
}
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
checkMagnet();
// ******************* start of new code ******************* \\
if (checkPlayerMove()) {
player.x+=possibleMove.x;
player.y+=possibleMove.y;
}
for (var i:Number=0; i
And this is the result:
Now everything acts just like the original game, we only need to check if the player solved the level
8) Checking for level solution
Checking for level solution is really easy, you just need to see if every block tile overlaps its goal tile, and if player position overlaps goal position, in this case the game ends:
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private var tileSize:Number=25;
private var gameField:Array=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
private var player:Point=new Point(5,9);
private var playerGoal:Point=new Point(9,13);
private var blocks:Array=[{shape:[new Point(7,3),new Point(8,3),new Point(9,3),new Point(10,3),new Point(11,3)],color:0x339900},{shape:[new Point(8,4),new Point(9,4),new Point(10,4)],color:0x00cc00}];
private var goals:Array=[{shape:[new Point(7,15),new Point(8,15),new Point(9,15),new Point(10,15),new Point(11,15)]},{shape:[new Point(8,14),new Point(9,14),new Point(10,14)]}];
private var possibleMove:Point;
public function Main() {
displayGame();
stage.addEventListener(KeyboardEvent.KEY_DOWN,movePlayer);
}
private function movePlayer(e:KeyboardEvent):void {
switch (e.keyCode) {
case 37 :
possibleMove=new Point(-1,0);
break;
case 38 :
possibleMove=new Point(0,-1);
break;
case 39 :
possibleMove=new Point(1,0);
break;
case 40 :
possibleMove=new Point(0,1);
break;
}
if (checkPlayerMove()) {
checkMagnet();
if (checkPlayerMove()) {
player.x+=possibleMove.x;
player.y+=possibleMove.y;
}
for (var i:Number=0; i
And this is the result:
Now you can play the complete level.
Download the source code of all examples.
I really wish you a blocky Christmas, and a special thanks goes to Bart Bonte for giving me the permission to dissect his game that hard.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.