首頁  >  文章  >  web前端  >  html5遊戲發展-憤怒的小鳥-開源講座(三)-碰撞產生的衝力

html5遊戲發展-憤怒的小鳥-開源講座(三)-碰撞產生的衝力

黄舟
黄舟原創
2017-03-02 13:40:272209瀏覽

在前面已經實現了利用外力將小鳥彈飛出去,並且實現了鏡頭的跟隨。本次來研究一下小鳥與其他物體之間發生碰撞時的衝力,以及由碰撞而使物體發生變形,進而消失,下面是前兩講的鏈接,看本篇教程之前請朋友們最好先了解一下。

其實在box2d中,只要我們設定了物體的密度,摩擦,以及彈力等屬性之後,他們之間會模擬真實的世界進行碰撞,如果想要根據這些碰撞來做一些特殊的處理的話,就需要取得它們之間碰撞的衝力,從而根據衝力的大小來做自己想要做的事情,在lufylegend庫件中使用下面一行程式碼來檢測碰撞。

LGlobal.box2d.setEvent(LEvent.POST_SOLVE,postSolve);

碰撞函數如下,接受兩個參數

function postSolve(contact, impulse){
}

然後用impulse.normalImpulses[0]來取得碰撞產生的衝力大小。

下面,我們來根據碰撞的衝力來控制豬頭的狀態,首先準備下面兩張圖


然後,建立Pig類別如下

function Pig(){
	base(this,LSprite,[]);
	var self = this;
	self.hp = 200;
	self.name = "pig";
	self.list = ["pig01","pig02"];
	self.bitmap = new LBitmap(new LBitmapData(imglist[self.list[0]]));
	self.addChild(self.bitmap);
	self.addBodyCircle(24,self.bitmap.getHeight()*0.5,self.bitmap.getWidth()*0.5,1,5,.4,.13);
}
Pig.prototype.hit = function(value){
	var self = this;
	if(value < 10)return;
	if(self.hp == 200)self.bitmap.bitmapData = new LBitmapData(imglist[self.list[1]]);
	self.hp -= value;
}

上面程式碼,在建構器裡先為豬頭設定了一張健康的狀態圖片,然後在hit函數裡,將豬頭的圖片變成了一張受傷的圖片。
有了上面的Pig類,只要在豬頭和其他物體之間發生碰撞的時候,將碰撞的衝力傳入hit函數,就能控制豬頭的狀態和hp的值,當然你也可以為豬頭準備多種狀態的圖片,例如輕傷,重傷等,然後在hit函數中根據它的hp值的大小,來給他設定不同的顯示圖片。

另外,在憤怒的小鳥這個遊戲中,每個物體也都是有它的不同的狀態的,比如下面的兩張圖,表示木條的兩個狀態


為了方便操作這些物體,我們和上面的豬頭一樣,建立一個Stage類,如下

function Stage(list,rotate,m,ctrl){
	base(this,LSprite,[]);
	var self = this;
	self.name = "stage";
	self.ctrl = ctrl;
	self.list = list;
	self.bitmap = new LBitmap(new LBitmapData(imglist[self.list[0]]));
	self.hp = 200;
	self.addChild(self.bitmap);
	self.addBodyPolygon(self.bitmap.getWidth(),self.bitmap.getHeight(),1,m,.4,.2);
	if(rotate != 0)self.setRotate(rotate*Math.PI/180);
}
Stage.prototype.hit = function(value){
	var self = this;
	if(!self.ctrl)return;
	if(value < 1)return;
	if(self.hp == 200)self.bitmap.bitmapData = new LBitmapData(imglist[self.list[1]]);
	self.hp -= value;
}

原理和Pig類相同,就不多做解釋了。
然後,在主函數中加入一些物體,如下

	setStage(["desk"],800,430,0,10,false);
	setStage(["desk"],970,430,0,10,false);
	setStage(["st11","st12"],935,410,0,1,true);
	setStage(["st01","st02"],905,370,90,1,true);
	setStage(["st01","st02"],965,370,90,1,true);
	setStage(["st11","st12"],935,310,0,1,true);
	setStage(["st31","st32"],817,370,90,1,true);
	setStage(["st31","st32"],970,370,90,1,true);
	setStage(["st31","st32"],895,250,0,1,true);
	setStage(["st21","st22"],955,230,0,1,true);
	setStage(["st31","st32"],858,150,90,1,true);
	setStage(["st31","st32"],925,150,90,1,true);
	setStage(["st11","st12"],935,50,0,1,true);
	setStage(["st21","st22"],950,30,90,1,true);
	setStage(["st21","st22"],800,430,90,1,true);
	setStage(["st21","st22"],1100,430,90,1,true);
	var pig = new Pig();
	pig.x = 950;
	pig.y = 173;
	backLayer.addChild(pig);

setStage函數如下,是為了實例化一個物體

function setStage(list,x,y,rotate,m,ctrl){
	var stageLayer = new Stage(list,rotate,m,ctrl);
	stageLayer.x = x;
	stageLayer.y = y;
	backLayer.addChild(stageLayer);
	return stageLayer;
}

上面的程式碼所產生的畫面如下


如果你玩過憤怒的小鳥這個遊戲的話,對上面的畫面應該不陌生吧,它就是憤怒的小鳥第一關的畫面。

接下來,修改碰撞偵測函數,因為我在lufylegend庫件中將body的UserData設定成了LSprite物件本身,所以這裡透過GetUserData來得到LSprite物件

function postSolve(contact, impulse){
	if(contact.GetFixtureA().GetBody().GetUserData().hit)contact.GetFixtureA().GetBody().GetUserData().hit(impulse.normalImpulses[0]);
	if(contact.GetFixtureB().GetBody().GetUserData().hit)contact.GetFixtureB().GetBody().GetUserData().hit(impulse.normalImpulses[0]);
}

有了上面的碰撞,現在運行遊戲的話,可以得到下面的效果

#可以看到,畫面中的豬頭和一些木條的狀態都已經發生了變化了,這樣我們就完成了根據碰撞來改變物體的狀態了,下面當豬頭的hp變成0的時候,將它移除遊戲畫面。

一般豬頭在消失的時候,會有一個類似爆炸的效果,如下圖


#下面建立一個RemoveObject類別來實現這一效果

function RemoveObject(){
	base(this,LSprite,[]);
	var self = this;
	self.name = "remove";
	self.index = 0;
	self.bitmap = new LBitmap(new LBitmapData(imglist["remove"]));
	self.addChild(self.bitmap);
}
RemoveObject.prototype.run = function(){
	var self = this;
	if(self.index++ > 20){
		self.parent.removeChild(self);
	}	
}

上面的run函數中,之所以要在運行20次循環之後才將其移除,是為了讓上面的爆炸狀態稍微持續一小段時間,然後才消失。

剩下最後一個處理,就是在循環函數中,監視這些物體的狀態,來控制它們什麼時候消失

function onframe(){
	if(bird){
		backLayer.x = LGlobal.width*0.5 - (bird.x + bird.getWidth()*0.5);	
		if(backLayer.x > 0){
			backLayer.x=0;
		}else if(backLayer.x < LGlobal.width - 1600){
			backLayer.x = LGlobal.width - 1600;
		}
		LGlobal.box2d.synchronous();
	}
	var child;
	for(var key in backLayer.childList){
		child = backLayer.childList[key];
		if(child.name == null)continue;
		if(child.x < -child.getWidth() || child.x > backLayer.getWidth()){
			backLayer.removeChild(child);
			if(child.name == "bird01"){
				bird = null;
				backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,moveStart);
				backLayer.addEventListener(LMouseEvent.MOUSE_MOVE,moveRun);
				backLayer.addEventListener(LMouseEvent.MOUSE_UP,moveEnd);
			}
		}else if((child.name == "stage" || child.name == "pig") && child.hp <= 0){
			if(child.name == "pig"){
				var removeObj = new RemoveObject();
				removeObj.x = child.x;
				removeObj.y = child.y;
				backLayer.addChild(removeObj);
			}
			backLayer.removeChild(child);
		}else if(child.name == "remove"){
			child.run();
		}
	}
}

上面程式碼都很簡單,就不解釋了,其中小鳥消失之後,我加入了三個事件,用來移動屏幕,最後會給出完整代碼,大家可以看一下

backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,moveStart);
backLayer.addEventListener(LMouseEvent.MOUSE_MOVE,moveRun);
backLayer.addEventListener(LMouseEvent.MOUSE_UP,moveEnd);


#好了,下面是效果圖和測試連接,試試看

http://lufy.netne.net/lufylegend-js/lufylegend-1.4/box2d/sample04/index.html



##大家可以看到,上面的小鳥已經把豬頭撞爆了!


下面給出本次教學的源碼,lufylegend庫件和box2dweb需要自己下載配置一下,庫件1.4.1的擴充部分請到第一講中下載。

http://fsanguo.comoj.com/download.php?i=AngryBirds3.rar

#


本系列講座到此為止了,憤怒的小鳥的基本功能已經都實現了,剩下的就是將元素多樣化了,大家可以盡情發揮自己的想像力,製作自己喜歡的實體遊戲了。

# 以上就是html5遊戲發展-憤怒的小鳥-開源講座(三)-碰撞產生的衝力的內容,更多相關內容請關注PHP中文網(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn