Maison >interface Web >Tutoriel H5 >[Développement de jeux html5] Sokoban classique

[Développement de jeux html5] Sokoban classique

黄舟
黄舟original
2017-03-01 16:29:353060parcourir

Mots d'ouverture :

Le moteur lufylegend.js a été mis à jour vers la version 1.6 ou supérieure, bien que j'ai publié quelques tutoriels un après l'autre. un autre , et fournit également quelques exemples de jeux simples, mais je n'ai jamais produit plusieurs œuvres complètes. En fait, mon temps est trop limité la prochaine fois, j'utiliserai le moteur lufylegend.js pour développer autant que possible plusieurs jeux. Il s'agit d'un travail complet pour augmenter le pouvoir de persuasion de ce moteur. J'espère que les amis qui aiment le HTML5 et le développement de jeux pourront me donner plus d'avis.

Cette fois, jetons un coup d'œil à un jeu Sokoban classique. Je pense que tout le monde connaît ce jeu. Le jeu Sokoban est originaire du Japon et est un jeu d'exercice extrêmement logique. Dans le jeu, les cases peuvent uniquement être poussées mais pas tirées. Les joueurs doivent remettre toutes les cases en place dans un espace limité, comme le montre l'image ci-dessous.

[Développement de jeux html5] Sokoban classique

Figure 1



Ceci est développé par moi en utilisant la dernière version du moteur lufylegend.js. Si vous souhaitez le défier, vous pouvez cliquer sur le lien du jeu ci-dessous pour voir combien de niveaux vous pouvez passer.

http://lufylegend.com/demo/box

Le jeu a un total de 6 niveaux J'ai ajouté un système de classement. au jeu. Après avoir réussi un niveau, vous pouvez télécharger vos propres résultats et rivaliser avec les autres, ou vous pouvez répondre à l'article ci-dessous avec votre expérience sur la façon de réussir le niveau.

Début de la production

D'accord, assez de bêtises, voyons maintenant comment créer ce jeu.

Tout d'abord, vous devez télécharger le moteur lufylegend.js

Ce qui suit est la version lufylegend-1.6.0 que j'ai publiée sur mon blog Post

http://blog.csdn.net/lufy_legend/article/details/8593968

Passons au développement pas à pas.

Deuxièmement, dessinez le fond et la boîte

Préparons d'abord une image,


Figure 2

Si nous divisons la figure ci-dessus en 5 parties égales, alors leurs numéros de série sont 0,1 ,2,3,4.

Nous pouvons utiliser les 5 petites images ci-dessus pour épisser n'importe quelle pièce et le placement des boîtes dans la pièce.

Par exemple, l'exemple d'image 1 au début de mon blog est une capture d'écran du premier niveau du jeu. Pour dessiner cette pièce, il faut d'abord savoir où doivent être ces images. placé. Préparez un tableau.


var stage01 = [
[-1,-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, 1, 1,-1,-1],
[-1,-1, 1, 0, 0, 4, 0, 0, 1,-1,-1],
[-1,-1, 1, 4, 4, 0, 4, 4, 1,-1,-1],
[-1,-1, 1, 0, 0, 4, 0, 0, 1,-1,-1],
[-1,-1, 1, 1, 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]
];

Le -1 ci-dessus signifie ne pas le placer, et puis 0, 1, 4, etc. correspondent respectivement aux numéros de série dans Graphique 2.

Il est simple de dessiner la pièce selon ce tableau, regardez la fonction ci-dessous

function drawFloor(x,y){
	if(list[y][x] < 0)return;
	var bitmap = new LBitmap(bitmapDataList[list[y][x]]);
	bitmap.x = x*STEP;
	bitmap.y = y*STEP;
	boxLayer.addChild(bitmap);
}

Ce tableau liste est le tableau stage01 ci-dessus, le paramètre x, y est respectivement le numéro de série de la colonne et de la ligne du tableau, et STEP est la longueur de chaque petite image. Pour dessiner une petite tuile, j'ai en fait créé un objet LBitmap.

À propos de LSprite, LBitmap et d'autres objets sont des objets très couramment utilisés dans le moteur lufylegend.js Pour leur utilisation, veuillez vous référer au document officiel de l'API ou lire certains de mes articles précédents pour en savoir plus. . Inutile d'entrer dans les détails ici.

Bien sûr, au début, il doit y avoir une boîte dans la pièce, et la position initiale de la boîte doit également être prédéfinie. Nous créons également un tableau.

var box01 = [
{x:3,y:3},
{x:4,y:3},
{x:5,y:3},
{x:5,y:5},
{x:6,y:5},
{x:7,y:5}
];

La fonction pour dessiner des boîtes est la suivante

function drawBox(){
	var bitmap;
	for(var i=0;i<boxList[stageIndex].length;i++){
		bitmap = new LBitmap(bitmapDataList[2]);
		bitmap.x = boxList[stageIndex][i].x*STEP;
		bitmap.y = boxList[stageIndex][i].y*STEP;
		boxLayer.addChild(bitmap);
		nowBoxList.push(bitmap);
	}
}

Ci-dessus, j'utilise également l'objet LBitmap pour afficher ces boîtes, et le tableau nowBoxList est utilisé pour stocker ceux chargés. L'objet box sur l'interface de jeu est ensuite utilisé pour déterminer si le jeu est réussi.

Parce que le 4 dans le tableau stage01 indique la position de la boîte qui doit être restaurée, donc pour juger si le jeu est réussi, il vous suffit de juger si ces positions coïncident avec les positions de toutes les cases. Voici comment procéder.

function checkBox(){
	var bitmap,x,y,win=true;
	list = [];
	for(var i=0;i<stageList[stageIndex].length;i++){
		list.push(stageList[stageIndex][i].join(",").split(","));
	}
	
	for(var i=0;i<nowBoxList.length;i++){
		bitmap = nowBoxList[i];
		x = bitmap.x / STEP;
		y = bitmap.y / STEP;
		if(list[y][x] == 4){
			bitmap.bitmapData = bitmapDataList[3];
		}else{
			bitmap.bitmapData = bitmapDataList[2];
			win = false;
		}
		list[y][x] += 10;
	}
	if(win)gameClearShow();
}

J'ai intercepté le code directement depuis le programme, donc de nouveaux tableaux et objets sont apparus.

stageList储存了所有的关卡信息,stageIndex是当前关卡的序号,stageList[stageIndex]就可以获取当前关卡的信息,bitmapDataList数组储存了图1中小图片的LBitmapData对象,这些暂且不说,关键是下面。

		if(list[y][x] == 4){
			bitmap.bitmapData = bitmapDataList[3];
		}else{
			bitmap.bitmapData = bitmapDataList[2];
			win = false;
		}

函数中循环了所有箱子的位置,如果他们的位置的序号为4,则表示该箱子已经归位,全部归位表示过关,否则游戏继续,返回false。

三,主人公登场,推动箱子。

同样准备一张图片,如下


图3

人物走动动画,当然就需要lufylegend引擎中另一个重要的对象LAnimation,它专门用来顺序播放图片以形成动画,具体用法请参照官方API文档。

下面是主人公的构造器

/**
 * 循环事件 
 * @param data 图片数据
 * @param row 图片分割行数
 * @param col 图片分割列数
 **/
function Character(data,row,col){
	base(this,LSprite,[]);
	var self = this;
	//设定人物动作速度
	self.speed = 2;
	self.speedIndex = 0;
	//设定人物大小
	data.setProperties(0,0,data.image.width/col,data.image.height/row);
	//得到人物图片拆分数组
	var list = LGlobal.pideCoordinate(data.image.width,data.image.height,row,col);
	//设定人物动画
	self.anime = new LAnimation(this,data,list);
	//设定不移动
	self.move = false;
	//在一个移动步长中的移动次数设定
	self.moveIndex = 0;
};

主人公如何推动箱子,看下面的onmove函数

/**
 * 开始移动 
 **/
Character.prototype.onmove = function (){
	var self = this;
	//设定一个移动步长中的移动次数
	var ml_cnt = 4;
	//计算一次移动的长度
	var ml = STEP/ml_cnt;
	//根据移动方向,开始移动
	switch (self.direction){
		case UP:
			self.y -= ml;
			if(box)box.y -= ml;
			break;
		case LEFT:
			self.x -= ml;
			if(box)box.x -= ml;
			break;
		case RIGHT:
			self.x += ml;
			if(box)box.x += ml;
			break;
		case DOWN:
			self.y += ml;
			if(box)box.y += ml;
			break;
	}
	self.moveIndex++;
	//当移动次数等于设定的次数,开始判断是否继续移动
	if(self.moveIndex >= ml_cnt){
		self.moveIndex = 0;
		box = null;
		self.move = false;
		checkBox();
	}
};

可以看到,箱子是不是跟着主人公一起走,关键是要看box这个变量,这个变量的值是在下面的checkRoad函数中设置的。

Character.prototype.checkRoad = function (dir){
	var self = this;
	var tox,toy;
	//开始计算移动目的地的坐标
	switch (dir){
		case UP:
			tox = 0;
			toy = -1;
			break;
		case LEFT:
			tox = -1;
			toy = 0;
			break;
		case RIGHT:
			tox = 1;
			toy = 0;
			break;
		case DOWN:
			tox = 0;
			toy = 1;
			break;
	}
	if(list[self.y/STEP + toy][self.x/STEP + tox]==1)return false;
	if(list[self.y/STEP + toy][self.x/STEP + tox]>4){
		if(list[self.y/STEP + toy*2][self.x/STEP + tox*2]==1 || list[self.y/STEP + toy*2][self.x/STEP + tox*2]>4)return false;
		box = getBox(self.x + tox*STEP,self.y + toy*STEP);
	}
	return true;
};

其实,就是判断一下主人公要走的方向的前方是不是有障碍物,如果障碍物是墙则不可移动,如果是箱子的话,就要看看箱子的后面是不是有障碍物,如果有则不可移动,否则箱子就需要跟着主人公一起移动,将box设置为主人公前方的箱子即可。
上面这个函数,是在人物即将发生移动的时候被调用的,如下。

/**
 * 改变人物方向,并判断是否可移动
 **/
Character.prototype.changeDir = function (dir){
	var self = this;
	if(self.move)return;
	self.direction = dir;
	self.anime.setAction(dir);
	if(!self.checkRoad(dir))return;
	self.move = true;
	steps.text = parseInt(steps.text) + 1;
};

当图1中的方向图标被按下的时候,根据点击的方向,来实现人物的移动。

点击方向图标的方法当然是鼠标事件

ctrlLayer.addEventListener(LMouseEvent.MOUSE_UP,onCtrl);

然后在onCtrl函数中根据点击的位置,来进行相应的移动。

function onCtrl(event){
	var ctrlSize = 60;
	if(event.selfX >= ctrlSize && event.selfX <= ctrlSize*2){
		if(event.selfY >= 0 && event.selfY <= ctrlSize){
			player.changeDir(UP);
		}else if(event.selfY >= ctrlSize*2 && event.selfY <= ctrlSize*3){
			player.changeDir(DOWN);
		}
	}else if(event.selfY >= ctrlSize && event.selfY <= ctrlSize*2){
		if(event.selfX >= 0 && event.selfX <= ctrlSize){
			player.changeDir(LEFT);
		}else if(event.selfX >= ctrlSize*2 && event.selfX <= ctrlSize*3){
			player.changeDir(RIGHT);
		}
	}
}

这样,游戏的主要功能部分,就介绍完了。

四,建一个开始画面

如下。


[Développement de jeux html5] Sokoban classique

图4

使用lufylegend.js引擎做个界面,可以说毫无难度,代码如下。

function GameLogo(){
	base(this,LSprite,[]);
	var self = this;
	
	var logolist = [[1,1,1,1],[1,2,4,1],[1,4,2,1],[1,1,1,1]];
	var bitmap,logoLayer;
	
	logoLayer = new LSprite();
	logoLayer.graphics.drawRect(6,"#FF7F50",[0,0,LGlobal.width,LGlobal.height],true,"#FFDAB9");
	self.addChild(logoLayer);
	
	logoLayer = new LSprite();
	logoLayer.x = 50;
	logoLayer.y = 50;
	for(var i=0;i<logolist.length;i++){
		for(var j=0;j<logolist.length;j++){
			bitmap = new LBitmap(bitmapDataList[logolist[i][j]]);
			bitmap.x = j*STEP;
			bitmap.y = i*STEP;
			logoLayer.addChild(bitmap);
		}
	}
	bitmap = new LBitmap(new LBitmapData(imglist["player"],0,0,STEP,STEP));
	bitmap.x = STEP;
	bitmap.y = 2*STEP;
	logoLayer.addChild(bitmap);
	self.addChild(logoLayer);
	
	labelText = new LTextField();
	labelText.rotate = -20;
	labelText.color = "#4B0082";
	labelText.font = "HG行書体";
	labelText.size = 100;
	labelText.x = 300;
	labelText.y = 50;
	labelText.stroke = true;
	labelText.lineWidth = 4;
	labelText.text = "推";
	self.addChild(labelText);
	
	labelText = new LTextField();
	labelText.color = "#4B0082";
	labelText.font = "HG行書体";
	labelText.size = 100;
	labelText.x = 450;
	labelText.y = 60;
	labelText.stroke = true;
	labelText.lineWidth = 4;
	labelText.text = "箱";
	self.addChild(labelText);
	
	labelText = new LTextField();
	labelText.rotate = 20;
	labelText.color = "#4B0082";
	labelText.font = "HG行書体";
	labelText.size = 100;
	labelText.x = 600;
	labelText.y = 60;
	labelText.stroke = true;
	labelText.lineWidth = 4;
	labelText.text = "子";
	self.addChild(labelText);
	
	labelText = new LTextField();
	labelText.color = "#B22222";
	labelText.font = "HG行書体";
	labelText.size = 40;
	labelText.x = 100;
	labelText.y = 250;
	labelText.stroke = true;
	labelText.lineWidth = 4;
	labelText.text = "Click to Start Game !!";
	self.addChild(labelText);
	
	var social = new Social();
	social.x = 220;
	social.y = 330;
	self.addChild(social);
	
	labelText = new LTextField();
	labelText.font = "HG行書体";
	labelText.size = 14;
	labelText.x = 400;
	labelText.y = 390;
	labelText.text = "- Html5 Game Engine lufylegend.js";
	self.addChild(labelText);
	labelText = new LTextField();
	labelText.color = "#006400";
	labelText.font = "HG行書体";
	labelText.size = 14;
	labelText.x = 400;
	labelText.y = 410;
	labelText.text = "http://www.lufylegend.com/lufylegend";
	self.addChild(labelText);
	
	self.addEventListener(LMouseEvent.MOUSE_UP,menuShow);
};

就是显示几张图片,以及添加一些文字,LTextField对象的使用方法请参考官方API文档。

五,建一个选择画面

如下。


[Développement de jeux html5] Sokoban classique

图5

代码如下。

function GameMenu(){
	base(this,LSprite,[]);
	var self = this;
	
	var menuLayer;
	menuLayer = new LSprite();
	menuLayer.graphics.drawRect(6,"#ADD8E6",[0,0,LGlobal.width,LGlobal.height],true,"#E6E6FA");
	self.addChild(menuLayer);
	
	labelText = new LTextField();
	labelText.color = "#B22222";
	labelText.font = "HG行書体";
	labelText.size = 40;
	labelText.x = 200;
	labelText.y = 30;
	labelText.stroke = true;
	labelText.lineWidth = 4;
	labelText.text = "Please select !!";
	menuLayer.addChild(labelText);
	for(var i=0;i<stageMenu.length;i++){
		self.stageVsMenu(stageMenu[i]);
	}
};
GameMenu.prototype.stageVsMenu = function(obj){
	var self = this;
	
	var menuButton,btn_up;
	if(obj.open){
		btn_up = new LSprite();
		btn_up.graphics.drawRect(2,"#000",[0,0,150,90],true,"#191970");
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 20;
		labelText.x = 40;
		labelText.y = 5;
		btn_up.addChild(labelText)
		labelText.text = "第"+(obj.index+1)+"关";
		
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 12;
		labelText.x = 10;
		labelText.y = 40;
		btn_up.addChild(labelText)
		labelText.text = "step:"+obj.step;
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 12;
		labelText.x = 10;
		labelText.y = 60;
		btn_up.addChild(labelText)
		labelText.text = "times:"+obj.times;
		
		
		var btn_down = new LSprite();
		btn_down.graphics.drawRect(2,"#000",[0,0,150,90],true,"#2F4F4F");
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 20;
		labelText.x = 40;
		labelText.y = 5;
		labelText.text = "第"+(obj.index+1)+"关";
		btn_down.addChild(labelText);
		
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 12;
		labelText.x = 10;
		labelText.y = 40;
		btn_down.addChild(labelText)
		labelText.text = "step:"+obj.step;
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 12;
		labelText.x = 10;
		labelText.y = 60;
		btn_down.addChild(labelText)
		labelText.text = "times:"+obj.times;
		
		menuButton = new LButton(btn_up,btn_down);
		menuButton.obj = obj;
		menuButton.addEventListener(LMouseEvent.MOUSE_UP,function(event,self){
			gameStart(self.obj.index);
		});
	}else{
		btn_up = new LSprite();
		btn_up.graphics.drawRect(2,"#000",[0,0,150,90],true,"#708090");
		labelText = new LTextField();
		labelText.color = "#ffffff";
		labelText.font = "HG行書体";
		labelText.size = 20;
		labelText.x = 40;
		labelText.y = 5;
		btn_up.addChild(labelText)
		labelText.text = "???";
		menuButton = btn_up;
	};
	self.addChild(menuButton);
	menuButton.x = obj.x * 220 + 100; 
	menuButton.y = obj.y * 140 + 130;
}

好了,游戏主要的代码已经都贴出来了。

源码

由于上面的代码比较零碎,而且我也只是挑中心部分说了一下,下面提供完整游戏源代码,想研究一下的朋友可以点击下面的连接下载。

http://lufylegend.com/lufylegend_download/box.rar

注意:该附件只包含本次文章源码,lufylegend.js引擎请到http://lufylegend.com/lufylegend进行下载。


 以上就是[html5游戏开发]经典的推箱子的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn