飛機躲避小游戲-是男人就撐100秒的制作_Flash教程
教程Tag:暫無Tag,歡迎添加,賺取U幣!
推薦:Flash播放器參數(shù)知多少?FlashOBJECT和EMBED標簽我們現(xiàn)在大部分人做網(wǎng)頁,都是直接用DW插入flash,而且DW也是所見即所得,直接生成了相應的flash顯示代碼。可是我們又有多少人了解這些
摘要:可以將這個游戲的整體運作看成一個粒子系統(tǒng),再加上子彈和飛機的碰撞判定即可.簡單起見,這里的飛機采用球體.
要害詞: 粒子系統(tǒng),飛機躲避游戲
Small STG Game---Lasting 100 Secs's making process
EmilMatthew(EmilMatthew@126.com)
Abstract:
We could treat this game as a particle system, which only needs the collide detect additionally.
To be easy enough as a sample program, I use one ball to take place of the plane in the game.
Key Words: Particle System, Plane avoids bullets game
1前言:
是男人就撐100秒是一個流行廣泛,但又略顯BT意味的小游戲。游戲的玩法就是四面不斷的有子彈射出,而你的任務就是控制你的飛機不斷的躲避,直到被擊中,以躲避時間的長短來評定游戲水平的高低。
這個游戲在實現(xiàn)是比較輕易的,由于子彈在這里占據(jù)了主要地位,所以考慮以子彈為中心,即考慮構建一個粒子系統(tǒng),來控制子彈的發(fā)射,發(fā)射方向的計算,以及出界的判定等。至于飛機方面,則只要有控制的部分(事件驅動,事件監(jiān)聽或用循環(huán),要視具體實現(xiàn)環(huán)境而定),把兩者結合起來,只要加上飛機與子彈間的碰撞檢測即可,這里出于演示的目的,簡單起見,采用球代替飛機的造型。
2子彈粒子系統(tǒng)的運作流程:
子彈的粒子系統(tǒng)要控制好子彈的發(fā)射,發(fā)射方向的計算,出界的判定以及碰撞檢測.
該粒子系統(tǒng)的總體框架并不困難,這里給出我實現(xiàn)過程中的總體框架:
while(runFlag)
{
For all particles
{
If(current particle is not lived)
{
Init this particle.
}
Else if(current particle is out of the game area)
{
Current particle set to dead.
}
Else
{
Current particle move and show
If(current particle is collided with the plane)
runFlag=flase;
}
}
} 這里要注重一下if….else if 中的條件判定對應的現(xiàn)實意義,即是否會出現(xiàn)實中無意義但在程序中卻出現(xiàn)的情況,假如出現(xiàn)的話,這樣的BUG將比較難抓出.
比如這里,假如將if及else if 中語中的條件及對應的內容作相應的交換,即:
if(current particle is out of the game area)
{
Current particle set to dead.
}
Else if(current particle is not lived)
{
Init this particle.
} 在第一個if判定中,會將這樣一種情況被包括進去:
if(current particle is out of game area&& current is not lived)此時,將導致第二個判定永遠無法到達.
所以,當條件復雜且多的時候,最好是列張真值表,看看所有可能的情況是否都如期的到達該到的判定條件處,避免在程序調試中浪費過多不避要的時間.
3子彈粒子設計細節(jié):
3.1子彈粒子的數(shù)據(jù)結構及存儲方式.
粒子類以一個類的形式進行封裝,里面包含了一些基本的物理屬性及粒子相關的一些動作(函數(shù))。簡要的情況如下:
class SPhy.CSPhyMc extends MovieClip
{
public var v :Number=0;//1 demision Velocity or together Velocity of vx ,vy
public var vx:Number=0;
public var vy:Number=0;
……
public function setLife(lifeValue:Number):Void
{
life=lifeValue;
}
public function getLife():Number
{
return life;
}
public function isLived():Boolean
{
return life==LIVED;
}
… …
} 而在游戲中,這采用一個數(shù)組來實現(xiàn)粒子的群落,理由是使用方便而且快速。(當然,出于一種美學上的要求,你可能會選鏈表,因為它的插入和刪除來的比較漂亮和干凈,這就取決于你自己的喜好了)
至于子彈起始的坐標值,則是隨機的散落于游戲屏幕區(qū)域外圍,要寫個相應的算法并不困難(詳見代碼部分)
3.2 發(fā)射角的計算.
發(fā)射角的計算相當于一道簡單的高中向量的題目:
已知兩點P1(x1,y1),P2(x2,y2),求P1指向P2的單位向量a.
求解:
a) 計算兩點間的距離L=sqrt((x1-x2)^2 (y1-y2)^2)
b) 求出P1P2(向量),P1P2=((x2-x1)/L,(y2-y1)/L);
c) 單位化a=P1P2/(Len(P1P2))
而你要做的,只是將子彈看成是P1,你自己的飛機看成是P2,即可,最后還應把起始速度去
乘以所求得的單位向量a=(cos(fi),sin(fi))
Vx=v*cos(fi)
Vy =v*sin(fi)
3.3 碰撞檢測
碰撞檢測是個廣泛而重要的話題,可以從簡單到復雜,難度突破主要在計算幾何上。這里針對本游戲談兩個:
3.3.1兩個圓的碰撞檢測,這個不用多說了,只要看兩個圓的圓心的距離是否比它們的半徑之和來的小就是了.
即圓1有:圓心O1(x1,y1),半徑r1
圓2有:圓心O2(x2,y2),半徑r2
則它們之間的碰撞檢測可以這樣來做:
If(Len(O1O2)<=r1 r2)
{
Two circles collide.
}
Else
{
Safe condition.
} 假如在視覺效果要求比較高的場和,尤其是不答應出現(xiàn)物體重疊的場和,不仿在Len(O1O2) 后加上一個偏移值。這樣可以保證視覺上不會看到兩個物體重疊的現(xiàn)像,盡管在精確的數(shù)值模型上二者并未相碰。而在數(shù)值精度要求高的場和,恐怕情況就要反一下了,圖形是第二位的,數(shù)據(jù)的精準才是最重要的。具體如何去平衡圖形和數(shù)據(jù)間的對應關系,還請諸位自己去斟酌了。
3.3.1圓和三角形間的碰撞檢測:
三角形可以用通常用一個五元組Q(P1,P2,k0,k1,k2)來表達(許多飛機的外形通常可以看成一個三角形)
對于Q(P1,P2,k0,k1,k2),其中,P1,P2是三角的位于上部和左下的兩個點,假設另一個點為P3,而k0是P1,P2間的斜率,k1是指P1,P3間的斜率,k2是指P2,P3間的斜率. (各字母的意義見圖1)
您所在的用戶組無法下載或查看附件:triangle.jpg。
這樣,三角形的三條邊就可以方便的表達出來了:
如直線P1P2的二維直線方程為 y=k0(x-x1) y1.
P1P3: y=k1(x-x1) y1
P2P3: y=k2(x-x2) y2這樣,判定一個點是否在三解形內,就只要判定這個點是否在三條邊指向三角形內的一側.這里,假如要判的點為p(x’,y’),則根據(jù)圖1的情況,有:
If(k0(x’-x1) y1>=0&&k1(x’-x1) y1<=0&& y’>=y2)//考慮到P2P3是水平的情況
{
Collide!
}
Else
{
Safe Condition.
}顯然,這個算法并不算得上好,因為假如三解形旋轉的話,原來的某直線的左側意味著三角形的內側可能就會意味著外側。這時,可以考慮再增加一個三元組,用來實時指示當前的三條直線指向三角形內側的方面,可取的情況有以下幾種:
a)左側 b)右側 c)上側(水平時) d下側(水平時)
4實現(xiàn)部分的要害代碼(AS2)
4.1粒子類:
import SMotion.*
import SColDet.*
class SPhy.CSPhyMc extends MovieClip
{
public var m:Number=0;//mass
public var g:Number=0;//gravity
public var pF:Number=0;//Positive forces,attention here UpCase!!!!!!!
//Because the compiler was not so perfect as you think ,add a p here to prepare for the case.
public var r:Number =0;//when it become a ball---radius.
public var v :Number=0;//1 demision Velocity or together Velocity of vx ,vy
public var vx:Number=0;
public var vy:Number=0;
public var f :Number=0;//fraction forces.
public var fx:Number=0;
public var fy:Number=0;
public var a :Number=0;//acclerate v
public var ax:Number=0;
public var ay:Number=0;
//plane game use;
public var bigFire:Number=0;
private static var DEAD:Number=0;
private static var LIVED:Number=1;
private var life:Number;
private var mMotionCom:RCSMove;
private var mColDetCom:RCSColDet;
private static var thisP:Object;
public function setLife(lifeValue:Number):Void
{
life=lifeValue;
}
public function getLife():Number
{
return life;
}
public function isLived():Boolean
{
return life==LIVED;
}
public function init():Void
{
thisP=this;
this.vx=0;
this.vy=0;
this.v=3 random(3);
this._width=10;
this._height=10;
this.r=5;
this.initCom();
}
public function initPos(targetPlane:CSPhyMc):Void
{
var randNum:Number=random(100);
//set init positoin:down,left,up,right
if(randNum<25)
{
this._x=random(Stage.width);
trace("Width" Stage.width "Height" Stage.height);
this._y=Stage.height;
}
else if(randNum<50)
{
thisP._x=_root.gStageLeft;
this._y=random(Stage.height);
}
else if(randNum<75)
{
this._x=random(Stage.width);
thisP._y=_root.gStageTop;
}
else
{
this._x=Stage.width;
this._y=random(Stage.height);
}
this.CalVx_Vy(this,targetPlane);
}
private function GetDis(mc1:CSPhyMc, mc2:CSPhyMc):Number
{
return Math.sqrt((mc1._x-mc2._x)*(mc1._x-mc2._x) (mc1._y-mc2._y)*(mc1._y-mc2._y));
}
private function CalVx_Vy(mcChase:CSPhyMc, mcAim:CSPhyMc):Void
{
var len:Number= GetDis(mcChase, mcAim);
mcChase.vx=(mcAim._x-mcChase._x)/len*mcChase.v;
mcChase.vy=(mcAim._y-mcChase._y)/len*mcChase.v;
}
public function initCom():Void
{
mMotionCom=new RCSMove();
mColDetCom=new RCSColDet();
}
public function outDetect():Boolean
{
var offset:Number=25;
return mColDetCom.particleOutDet(this,0-offset,0-offset,Stage.width 2*offset,Stage.height 2*offset);
}
public function move_show():Void
{
mMotionCom.Move2D(this,this.vx,this.vy);
}
public function collideDect(targetPlane:CSPhyMc):Boolean
{
if(_root.mcLibPlaneName=="ball")
return mColDetCom.TwoBall(targetPlane,this);
//return this.hitTest(targetPlane.getBounds(_root).xMin,targetPlane.getBounds(_root).yMax,false);
}
}4.2游戲主調度類
class ChaseAim
{
static private var thisP:Object;
private var staturs:Number;//gaming 1,failure 0
private var speed:Number;
private var bulletNum:Number=20;
private var start:Number=0;
private var end:Number=0;
public function init():Void
{ thisP=this;
staturs=1;
speed=3;
bulletNum=20;
for(var i=0;i<11;i )
{
_root.createTextField("txt" i,i,0,(i-1)*25,500,25);
}
_root.attachMovie("ball","ball1",11);
_root.ball1._x=250;
_root.ball1._y=200;
_root.ball1.r=20;
for(var i=0;i<bulletNum;i )
{
_root.attachMovie("bullet","bullet" i,20 i);
_root["bullet" i].vx=0;
_root["bullet" i].vy=0;
_root["bullet" i].v=3 random(3);
_root["bullet" i].r=5;
_root["bullet" i]._width=10;
_root["bullet" i]._height=10;
GenBullet(_root["bullet" i]);
}
start=getTimer();
setInterval(EffectF,100);
}
private function EffectF():Void
{
if(thisP.staturs!=0)
{
for(var i=0;i<thisP.bulletNum;i )
{
if (thisP.CheckOutBounds(_root["bullet" i])) thisP.GenBullet(_root["bullet" i]);
if(thisP.TwoBallCol(_root.ball1,_root["bullet" i]))thisP.staturs=0;
thisP.Move2D(_root["bullet" i]);
//_root.txt3.text=_root["bullet" i].vx;
//_root.txt4.text=_root["bullet" i].vy;
}
if( Key.isDown(Key.LEFT))_root.ball1._x -= thisP.speed;
if( Key.isDown(Key.RIGHT))_root.ball1._x = thisP.speed;
if( Key.isDown(Key.UP))_root.ball1._y -= thisP.speed;
if( Key.isDown(Key.DOWN))_root.ball1._y = thisP.speed;
if(thisP.staturs==0)
{
_root.txt0.text="you failure";
thisP.end=getTimer();
var tmp:Number=thisP.end-thisP.start;
_root.txt1.text="你共堅持了" tmp/1000 "秒";
//delete this.onEnterFrame;
}
}
}
private function GenBullet(tmpMc:CSPhyMc):Void
{ var left:Number;
var top:Number;
if(random(2))
{
left=random(7)*100-100;
top=random(2)*400;
}
else
{
left=random(2)*600;
top=random(6)*100-100;
}
tmpMc._x=left;
tmpMc._y=top;
CalVx_Vy(tmpMc, _root.ball1);
}
private function CheckOutBounds(tmpMc:CSPhyMc):Boolean
{
if(tmpMc._x<-10||tmpMc._x>510||tmpMc._y<-10||tmpMc._y>410)
return true;
else return false;
}
private function TwoBallCol(ball1:CSPhyMc,ball2:CSPhyMc):Boolean
{
if(Math.sqrt((ball1._x-ball2._x)*(ball1._x-ball2._x) (ball1._y-ball2._y)*(ball1._y-ball2._y))<=(ball1.r ball2.r))
return true;
else
return false;
}
private function GetDis(mc1:CSPhyMc, mc2:CSPhyMc):Number
{
return Math.sqrt((mc1._x-mc2._x)*(mc1._x-mc2._x) (mc1._y-mc2._y)*(mc1._y-mc2._y));
}
private function CalVx_Vy(mcChase:CSPhyMc, mcAim:CSPhyMc):Void
{
var len:Number= GetDis(mcChase, mcAim);
mcChase.vx=(mcAim._x-mcChase._x)/len*mcChase.v;
mcChase.vy=(mcAim._y-mcChase._y)/len*mcChase.v;
}
private function Move2D(mc:CSPhyMc):Void
{
mc._x =mc.vx;
mc._y =mc.vy;
}
}
4.3核心運行函數(shù):
function mainLoop():Void
{
UserPlaneControl();
if(_root.gRunFlag)
{
//trace("yes");
for(var i:Number=0;i<_root.gBulletNum;i )
{
//trace("yes");
if(!_root[mcUserBulletName i].isLived())
{
//trace("relife:" i);
_root[mcUserBulletName i].setLife(LIVED);
_root[mcUserBulletName i].init();
_root[mcUserBulletName i].initPos(_root[mcUserPlaneName]);
}
else if(_root[mcUserBulletName i].outDetect())
{
//trace("outDetect:" i);
_root[mcUserBulletName i].setLife(DEAD);
}
else
{
_root[mcUserBulletName i].move_show();
if(_root[mcUserBulletName i].collideDect(_root[mcUserPlaneName]))
_root.gRunFlag=false;
}
}
}
else
{
var timeCount:Number=0;
//clear the main game scence
clearInterval(_root.gIntervalID);
/*for(var i:Number=0;i<_root.gBulletNum;i )
_root[mcUserBulletName i].removeMovieClip();
_root[mcUserPlaneName].removeMovieClip();
*/
_root.gTimeEnd=getTimer();
timeCount=_root.gTimeEnd-_root.gTimeStart;
trace("you last:" String(timeCount) "secs.");
trace2("You lasted:" String(timeCount)/1000 "secs.");
/*start the end mc
_root.gNextScence=0;
_root.gIntervalID=setInterval(showEnd,_root.fps,_root.mcEndName,_root.result);
*/
}
}5實驗結論:
通過該模型,實現(xiàn)了一個粒子系統(tǒng)的基本運作模式,該運作模式同樣適用于其它的粒子系統(tǒng),只要在最要害的運動及顯示部分加以變換即可.
相關Flash教程:
- 相關鏈接:
- 教程說明:
Flash教程-飛機躲避小游戲-是男人就撐100秒的制作。