Talking about Sokoban game, Game development, HTML5 and Javascript.
Did you try Panda2 Game Engine? It’s a HTML5 game engine which comes with a great IDE, I already showed you how to build a Tipsy Tower prototype with it and now I just built a complete Sokoban prototype with it. You should know I am a Sokoban fan, you can find plenty of tutorials in different programming languages showing how to build a Sokoban game, and now it’s time to show you the Panda2 prototype. Look at the IDE in action: 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.