Pandaban – Build HTML5 Sokoban game with Panda2 and play it with keyboard or by swiping
Talking about Sokoban game, Game development, HTML5 and Javascript.
Learn cross platform HTML5 game development
Check my Gumroad page for commented source code, games and books.
And now, the game itself:
You should know the rules, control the character with ARROW keys or by swiping.
In the source code, still uncommented, you can find a lot of useful features, such as:
* mouse input detection
* keyboard detection
* sprite sheets
* tweens
And I also improved it a bit making it less redundant compared to my previous versions, have a look:
game.module(
"game.main"
)
.body(function() {
var gameOptions = {
tileSize: 40,
animationSpeed: 200
}
var level = [
[1,1,1,1,1,1,1,1],
[1,0,0,1,1,1,1,1],
[1,0,0,1,1,1,1,1],
[1,0,0,0,0,0,0,1],
[1,1,4,2,1,3,0,1],
[1,0,0,0,1,0,0,1],
[1,0,0,0,1,1,1,1],
[1,1,1,1,1,1,1,1]
]
var EMPTY = 0;
var WALL = 1;
var SPOT = 2;
var CRATE = 3;
var PLAYER = 4;
game.addAsset("tiles.png");
game.createScene("Main", {
init: function() {
this.canMove = true;
this.drawLevel();
},
drawLevel: function(){
this.sheet = new game.SpriteSheet("tiles.png", gameOptions.tileSize, gameOptions.tileSize);
this.crates = [];
this.crates.length = 0;
for (var i = 0; i < level.length; i++) {
this.crates[i] = [];
for (var j = 0; j < level[i].length; j++) {
this.crates[i][j] = null;
var item = level[i][j];
switch(item){
case PLAYER:
case PLAYER + SPOT:
this.player = this.sheet.frame(item);
this.player.position.set(j * gameOptions.tileSize, i * gameOptions.tileSize);
this.player.addTo(this.stage);
this.player.zIndex = 1;
this.player.posX = j;
this.player.posY = i;
var tile = this.sheet.frame(item - PLAYER);
tile.position.set(j * gameOptions.tileSize, i * gameOptions.tileSize);
tile.addTo(this.stage);
tile.zIndex = 0;
break;
case CRATE:
case CRATE + SPOT:
this.crates[i][j] = this.sheet.frame(item);
this.crates[i][j].position.set(j * gameOptions.tileSize, i * gameOptions.tileSize);
this.crates[i][j].addTo(this.stage);
this.crates[i][j].zIndex = 1;
var tile = this.sheet.frame(item - CRATE);
tile.position.set(j * gameOptions.tileSize, i * gameOptions.tileSize);
tile.addTo(this.stage);
tile.zIndex = 0;
break;
default:
var tile = this.sheet.frame(item);
tile.position.set(j * gameOptions.tileSize, i * gameOptions.tileSize);
tile.addTo(this.stage);
tile.zIndex = 0;
}
}
}
game.scene.stage.children.sort(this.depthCompare);
},
swipe: function(d){
switch(d){
case "RIGHT":
this.checkMove(1, 0);
break;
case "LEFT":
this.checkMove(-1, 0);
break;
case "UP":
this.checkMove(0, -1);
break;
case "DOWN":
this.checkMove(0, 1);
break;
}
},
checkMove: function(deltaX, deltaY){
if(this.canMove){
if(this.isWalkable(this.player.posX + deltaX, this.player.posY + deltaY)){
this.movePlayer(deltaX, deltaY, false);
return;
}
if(this.isCrate(this.player.posX + deltaX, this.player.posY + deltaY)){
if(this.isWalkable(this.player.posX + 2 * deltaX, this.player.posY + 2 * deltaY)){
this.movePlayer(deltaX, deltaY, true);
return;
}
}
}
},
isWalkable: function(posX, posY){
return level[posY][posX] == EMPTY || level[posY][posX] == SPOT;
},
isCrate: function(posX, posY){
return level[posY][posX] == CRATE || level[posY][posX] == CRATE + SPOT;
},
movePlayer: function(deltaX, deltaY, pushCrate){
this.canMove = false;
var playerTween = new game.Tween(this.player.position);
playerTween.to({
x: this.player.x + deltaX * gameOptions.tileSize,
y: this.player.y + deltaY * gameOptions.tileSize
}, gameOptions.animationSpeed);
playerTween.start();
playerTween.onComplete(function() {
level[this.player.posY][this.player.posX] -= PLAYER;
this.player.posX += deltaX;
this.player.posY += deltaY;
level[this.player.posY][this.player.posX] += PLAYER;
if(pushCrate){
this.crates[this.player.posY + deltaY][this.player.posX + deltaX] = this.crates[this.player.posY][this.player.posX];
this.crates[this.player.posY][this.player.posX] = null;
level[this.player.posY][this.player.posX] -= CRATE;
level[this.player.posY + deltaY][this.player.posX + deltaX] += CRATE;
this.crates[this.player.posY + deltaY][this.player.posX + deltaX].texture = this.sheet.textures[level[this.player.posY + deltaY][this.player.posX + deltaX]];
}
this.player.texture = this.sheet.textures[level[this.player.posY][this.player.posX]];
this.canMove = true;
}.bind(this));
if(pushCrate){
var crateTween = new game.Tween(this.crates[this.player.posY + deltaY][this.player.posX + deltaX].position);
crateTween.to({
x: this.crates[this.player.posY + deltaY][this.player.posX + deltaX].x + deltaX * gameOptions.tileSize,
y: this.crates[this.player.posY + deltaY][this.player.posX + deltaX].y + deltaY * gameOptions.tileSize
}, gameOptions.animationSpeed);
crateTween.start();
}
},
depthCompare: function (a, b){
if (a.zIndex < b.zIndex) return -1;
if (a.zIndex > b.zIndex) return 1;
return 0;
},
update: function() {
if (game.keyboard.down("LEFT")){
this.checkMove(-1, 0);
}
if (game.keyboard.down("RIGHT")){
this.checkMove(1, 0);
}
if (game.keyboard.down("UP")){
this.checkMove(0, -1);
}
if (game.keyboard.down("DOWN")){
this.checkMove(0, 1);
}
}
});
});
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.