飛機(jī)躲避小游戲-是男人就撐100秒的制作_Flash教程
教程Tag:暫無(wú)Tag,歡迎添加,賺取U幣!
推薦:Flash播放器參數(shù)知多少?FlashOBJECT和EMBED標(biāo)簽我們現(xiàn)在大部分人做網(wǎng)頁(yè),都是直接用DW插入flash,而且DW也是所見(jiàn)即所得,直接生成了相應(yīng)的flash顯示代碼�?墒俏覀冇钟卸嗌偃肆私膺@些
摘要:可以將這個(gè)游戲的整體運(yùn)作看成一個(gè)粒子系統(tǒng),再加上子彈和飛機(jī)的碰撞判定即可.簡(jiǎn)單起見(jiàn),這里的飛機(jī)采用球體.
要害詞: 粒子系統(tǒng),飛機(jī)躲避游戲
Small STG Game---Lasting 100 Secs's making process
EmilMatthew([email protected])
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秒是一個(gè)流行廣泛,但又略顯BT意味的小游戲。游戲的玩法就是四面不斷的有子彈射出,而你的任務(wù)就是控制你的飛機(jī)不斷的躲避,直到被擊中,以躲避時(shí)間的長(zhǎng)短來(lái)評(píng)定游戲水平的高低。
這個(gè)游戲在實(shí)現(xiàn)是比較輕易的,由于子彈在這里占據(jù)了主要地位,所以考慮以子彈為中心,即考慮構(gòu)建一個(gè)粒子系統(tǒng),來(lái)控制子彈的發(fā)射,發(fā)射方向的計(jì)算,以及出界的判定等。至于飛機(jī)方面,則只要有控制的部分(事件驅(qū)動(dòng),事件監(jiān)聽(tīng)或用循環(huán),要視具體實(shí)現(xiàn)環(huán)境而定),把兩者結(jié)合起來(lái),只要加上飛機(jī)與子彈間的碰撞檢測(cè)即可,這里出于演示的目的,簡(jiǎn)單起見(jiàn),采用球代替飛機(jī)的造型。
2子彈粒子系統(tǒng)的運(yùn)作流程:
子彈的粒子系統(tǒng)要控制好子彈的發(fā)射,發(fā)射方向的計(jì)算,出界的判定以及碰撞檢測(cè).
該粒子系統(tǒng)的總體框架并不困難,這里給出我實(shí)現(xiàn)過(guò)程中的總體框架:
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 中的條件判定對(duì)應(yīng)的現(xiàn)實(shí)意義,即是否會(huì)出現(xiàn)實(shí)中無(wú)意義但在程序中卻出現(xiàn)的情況,假如出現(xiàn)的話(huà),這樣的BUG將比較難抓出.
比如這里,假如將if及else if 中語(yǔ)中的條件及對(duì)應(yīng)的內(nèi)容作相應(yīng)的交換,即:
if(current particle is out of the game area)
{
Current particle set to dead.
}
Else if(current particle is not lived)
{
Init this particle.
} 在第一個(gè)if判定中,會(huì)將這樣一種情況被包括進(jìn)去:
if(current particle is out of game area&& current is not lived)此時(shí),將導(dǎo)致第二個(gè)判定永遠(yuǎn)無(wú)法到達(dá).
所以,當(dāng)條件復(fù)雜且多的時(shí)候,最好是列張真值表,看看所有可能的情況是否都如期的到達(dá)該到的判定條件處,避免在程序調(diào)試中浪費(fèi)過(guò)多不避要的時(shí)間.
3子彈粒子設(shè)計(jì)細(xì)節(jié):
3.1子彈粒子的數(shù)據(jù)結(jié)構(gòu)及存儲(chǔ)方式.
粒子類(lèi)以一個(gè)類(lèi)的形式進(jìn)行封裝,里面包含了一些基本的物理屬性及粒子相關(guān)的一些動(dòng)作(函數(shù))。簡(jiǎn)要的情況如下:
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;
}
… …
} 而在游戲中,這采用一個(gè)數(shù)組來(lái)實(shí)現(xiàn)粒子的群落,理由是使用方便而且快速。(當(dāng)然,出于一種美學(xué)上的要求,你可能會(huì)選鏈表,因?yàn)樗牟迦牒蛣h除來(lái)的比較漂亮和干凈,這就取決于你自己的喜好了)
至于子彈起始的坐標(biāo)值,則是隨機(jī)的散落于游戲屏幕區(qū)域外圍,要寫(xiě)個(gè)相應(yīng)的算法并不困難(詳見(jiàn)代碼部分)
3.2 發(fā)射角的計(jì)算.
發(fā)射角的計(jì)算相當(dāng)于一道簡(jiǎn)單的高中向量的題目:
已知兩點(diǎn)P1(x1,y1),P2(x2,y2),求P1指向P2的單位向量a.
求解:
a) 計(jì)算兩點(diǎn)間的距離L=sqrt((x1-x2)^2 (y1-y2)^2)
b) 求出P1P2(向量),P1P2=((x2-x1)/L,(y2-y1)/L);
c) 單位化a=P1P2/(Len(P1P2))
而你要做的,只是將子彈看成是P1,你自己的飛機(jī)看成是P2,即可,最后還應(yīng)把起始速度去
乘以所求得的單位向量a=(cos(fi),sin(fi))
Vx=v*cos(fi)
Vy =v*sin(fi)
3.3 碰撞檢測(cè)
碰撞檢測(cè)是個(gè)廣泛而重要的話(huà)題,可以從簡(jiǎn)單到復(fù)雜,難度突破主要在計(jì)算幾何上。這里針對(duì)本游戲談兩個(gè):
3.3.1兩個(gè)圓的碰撞檢測(cè),這個(gè)不用多說(shuō)了,只要看兩個(gè)圓的圓心的距離是否比它們的半徑之和來(lái)的小就是了.
即圓1有:圓心O1(x1,y1),半徑r1
圓2有:圓心O2(x2,y2),半徑r2
則它們之間的碰撞檢測(cè)可以這樣來(lái)做:
If(Len(O1O2)<=r1 r2)
{
Two circles collide.
}
Else
{
Safe condition.
} 假如在視覺(jué)效果要求比較高的場(chǎng)和,尤其是不答應(yīng)出現(xiàn)物體重疊的場(chǎng)和,不仿在Len(O1O2) 后加上一個(gè)偏移值。這樣可以保證視覺(jué)上不會(huì)看到兩個(gè)物體重疊的現(xiàn)像,盡管在精確的數(shù)值模型上二者并未相碰。而在數(shù)值精度要求高的場(chǎng)和,恐怕情況就要反一下了,圖形是第二位的,數(shù)據(jù)的精準(zhǔn)才是最重要的。具體如何去平衡圖形和數(shù)據(jù)間的對(duì)應(yīng)關(guān)系,還請(qǐng)諸位自己去斟酌了。
3.3.1圓和三角形間的碰撞檢測(cè):
三角形可以用通常用一個(gè)五元組Q(P1,P2,k0,k1,k2)來(lái)表達(dá)(許多飛機(jī)的外形通�?梢钥闯梢粋(gè)三角形)
對(duì)于Q(P1,P2,k0,k1,k2),其中,P1,P2是三角的位于上部和左下的兩個(gè)點(diǎn),假設(shè)另一個(gè)點(diǎn)為P3,而k0是P1,P2間的斜率,k1是指P1,P3間的斜率,k2是指P2,P3間的斜率. (各字母的意義見(jiàn)圖1)
您所在的用戶(hù)組無(wú)法下載或查看附件:triangle.jpg。
這樣,三角形的三條邊就可以方便的表達(dá)出來(lái)了:
如直線(xiàn)P1P2的二維直線(xiàn)方程為 y=k0(x-x1) y1.
P1P3: y=k1(x-x1) y1
P2P3: y=k2(x-x2) y2這樣,判定一個(gè)點(diǎn)是否在三解形內(nèi),就只要判定這個(gè)點(diǎn)是否在三條邊指向三角形內(nèi)的一側(cè).這里,假如要判的點(diǎn)為p(x’,y’),則根據(jù)圖1的情況,有:
If(k0(x’-x1) y1>=0&&k1(x’-x1) y1<=0&& y’>=y2)//考慮到P2P3是水平的情況
{
Collide!
}
Else
{
Safe Condition.
}顯然,這個(gè)算法并不算得上好,因?yàn)榧偃缛庑涡D(zhuǎn)的話(huà),原來(lái)的某直線(xiàn)的左側(cè)意味著三角形的內(nèi)側(cè)可能就會(huì)意味著外側(cè)。這時(shí),可以考慮再增加一個(gè)三元組,用來(lái)實(shí)時(shí)指示當(dāng)前的三條直線(xiàn)指向三角形內(nèi)側(cè)的方面,可取的情況有以下幾種:
a)左側(cè) b)右側(cè) c)上側(cè)(水平時(shí)) d下側(cè)(水平時(shí))
4實(shí)現(xiàn)部分的要害代碼(AS2)
4.1粒子類(lèi):
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游戲主調(diào)度類(lèi)
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="你共堅(jiān)持了" 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核心運(yùn)行函數(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實(shí)驗(yàn)結(jié)論:
通過(guò)該模型,實(shí)現(xiàn)了一個(gè)粒子系統(tǒng)的基本運(yùn)作模式,該運(yùn)作模式同樣適用于其它的粒子系統(tǒng),只要在最要害的運(yùn)動(dòng)及顯示部分加以變換即可.
相關(guān)Flash教程:
- as中禁用ESC鍵
- AS3.0 圖片變黑白 圖片彩色變黑白代碼
- flash as3.0 跨域的解決辦法
- 模板無(wú)憂(yōu)FLASH透明代碼
- Flash教你制作卡通MM眨眼睛動(dòng)畫(huà)
- Flash從零開(kāi)始學(xué)習(xí)創(chuàng)建單選按鈕
- Flash繪制小龍與花插畫(huà)場(chǎng)景
- Flash程序的測(cè)試方法
- Flash CS4文字顏色緩動(dòng)特效
- 網(wǎng)頁(yè)中演示類(lèi)FLASH動(dòng)畫(huà)制作規(guī)范
- Flash CS3循環(huán)背景的運(yùn)用技巧
- Flash鼠繪技巧教你制作紅綠色的樹(shù)葉
Flash教程Rss訂閱網(wǎng)站制作教程搜索
Flash教程推薦
- 巧用Flash的Media組件實(shí)現(xiàn)多首mp3連播
- Flash教程:制作有趣的星座查詢(xún)器(1)
- 學(xué)習(xí)AS3:*新的變量類(lèi)型
- 使用Flash繪制唐老鴨卡通矢量頭像
- Flash MX2004入門(mén)與進(jìn)階實(shí)例——元件和實(shí)例(8)
- Flash MX2004入門(mén)與進(jìn)階實(shí)例--動(dòng)畫(huà)基礎(chǔ)(30)
- flash action 詳解(3)
- getURL函數(shù)的使用方法指南
- Flash基礎(chǔ)精彩實(shí)例教程:飄動(dòng)的彩旗
- 關(guān)于As2.0 編程的一些規(guī)則
- 相關(guān)鏈接:
- 教程說(shuō)明:
Flash教程-飛機(jī)躲避小游戲-是男人就撐100秒的制作
。