[翻譯]國外的一篇AS2飛機教程(1)

來源:互聯網
上載者:User

作者自己的水平應該是很高的了,但從遊戲的模式上而言,這個遊戲並沒有太多的創新,仍舊是無限循制,
不過想法上已經相當完整了,有這樣一個很好的開發習慣,想做大的東東,就不會無從下手了。
作者寫此文章的主要目的是在於介紹給大家如何真正用物件導向的AS2來寫遊戲,
所以,從這個角度而言,這篇文章還是相當優秀的,尤其是在國內這方面資料比較饋乏的時候,
這種文章可謂雪中送碳的佳舉,我翻譯一下,一方面是自己有提高,另一個方面,也算是給廣大的
FLASHER做點貢獻吧~~~~(文章已被閃吧收錄,可以到這裡下原始碼
   http://www2.flash8.net/teach/2715.htm
)
(第一次翻國外的東東,所以有什麼不地道的地方,敬請高手斧正.
對了,要是作者本人給你發郵件說想找EmilMatthew收中文版的著作權費時,你們就說不認識我啊,
謝謝啦~~~:)
)

這篇文檔是我第一個用OOP(物件導向的編程)方法寫的AS2遊戲。
這個一個標準的空間打擊敵人的遊戲,有三架敵機和一架遊戲者的噴火鐳射機。
起初只會有一關,但是設計上可以使得增加關數的可能性變得非常方便。
遊戲中會有基本的分數以及生命值。
和別的正在掙紮著實行在FLASH MX2004中的新的ACTIONSCRIPT2.0文法的人一樣,
這篇文檔也是為了我個人學習的好處。
我會遵照一個合理的傳統的OOP設計的結構。
非常感謝並尊重來自http://www.1coinplay.com的Squize讓我使用他的小精靈紙(?)來做為這個例子。

1要求文檔。
2使用事件。
3類的表格。
4互動的表格。
5實驗最初的代碼。
6迭代(Iteration)
7測試。
8發布。

*************************************************************************************
1要求:
Spaceship:
上下左右移動。
通過空格鍵來發射鐳射。

Enemy:
在一個隨機的高度從右移到左。
有三個執行個體。
當它從左移出螢幕時,重新回到右側。

BackGround:
從左移到右。
前景要比背景移動的快(視差(PARALLAX))

Laser:
當空格鍵按下時火焰從飛船中噴出。

Game:
如果射到敵人,遊戲者得到分數。
如果飛船撞到敵機,則會損失生命值。
如果遊戲者得到了勝利的分數,那個他(她)就贏了,遊戲重新開始。
如果損失生命數超過三,遊戲結束,遊戲者失敗。

2使用的事件:
使用的事件是用圖表來代表(設計的)要求。它們展示了在遊戲中會發生的不同的事件,或者是所有會發生的不同的動作。

這就是你所有所要做的。僅僅是把它們在一張紙上完整的實現(NUT ?),
這張表格能很好的給最終將使用的類及方法一個好的提示。
當你做完這些以後,該是你搞定你會要使用什麼類以及這些類需要什麼什麼屬性及方法.

類的表格:
類的表格展示了類之間的關係。
在我們下面的這張表格裡:飛船,敵人,鐳射及背景類都包含在進了遊戲類.
這意味著那些類的實體被在遊戲類中聲明了。
這被叫做取合或者是“有一層”關係而區別於被描述為“是一種”關係的繼承。?
遊戲類被取彙總進了我的Flash檔案裡。

類的描述:
宇宙飛船類
屬性或方法    類型      描述
speed       Number  x變數的增量
moveShip()  method  用按鍵來移動飛船
setShipX(x) setter  _x變數擷取值的方法
getShipX()  getter  返回_x值
setShipY(y) setter  _y變數擷取值的方法
getShipY()  getter  返回_y值

敵機類
屬性或方法    類型      描述
enSpeed     Number  x變數的增量
moveEn()    method  隨機的移動敵機
setEnX(x)   setter  _x變數擷取值的方法
getEnX()    getter  返回_x值
setEnY(y)   setter  _y變數擷取值的方法
getEnY()    getter  返回_y值

鐳射類
屬性或方法      類型      描述
fire() method start   當空格鍵按下時移動
setLaserX(x)  setter  _x變數擷取值的方法
getLaserX()   getter  返回_x值
setLaserY(y)  setter  _y變數擷取值的方法
getLaserY()   getter  返回_y值

背景類
屬性或方法      類型      描述
scroll()     method   從右移到左
setBackX(x)  setter   _x變數擷取值的方法
getBackX()   getter   返回_x值
setBackY(y)  setter   _y變數擷取值的方法
getBackY()   getter   返回_y值

遊戲類
屬性或方法              類型      描述
score                Number   遊戲者的得分
lives                Number   遊戲者的生命數
checkCollisions()    method   碰撞檢測
CheckLives(lives)    method   如果生命值為0就停止遊戲。
checkScore()         method   檢測並展示分數

互動的表格
互動表格述了通過方法傳遞的資訊來符合我們一開始所提出的要求。
我現在對這項計劃是否有效沒有任何概念,因為我不知道Flash是否能處理組合。
遊戲類包含著其它類並且是遊戲的管理者。
但是我並不清楚是否能在一個類中控制一個繼承於MovieClip類的子類(的執行個體).
那好,這裡就是這計劃,讓我們看一下它是否能起作用。
計劃不是被放在混凝土裡的。如果它們無效,你可以把它們扔掉,或者是修改,甚至從草稿重新開始。
最重要的事情是過程。
通過過程來明確問題並呈現給我們處理問題的方法。這就像給電影的情節串聯圖版.
你草擬出它,呈現出指令碼的想法同時也瞄準了觀眾的需求。
一旦你把這個都搞定了,你就把它扔在了一邊並用本能進行著導演。
你知道故事的背景因為你瀏覽了情節串聯圖版的過程。這裡也是如此:

上面是我畫的一個份互動的表格。
我甚至做了一些改變並意識到一些在類表格中裡所遺漏的內容。
就像那個moveship方法需要一個方向(左,右,上,下)並且我能過一個變數dir來傳遞按了哪個鍵。
dir可以是string類(“left”)或者是一個字母(1,2,3,4).這並不重要。

測試優先:
我建立了一個新的Flash 檔案並建立了一個spaceship_mc(mc),把它串連到庫裡的ship_mc並把“Spaceship”放進串連(link)AS2 CLASS選項中。
然後在互動面板中我寫下了下面的代碼:
//串連spaceship_mc
attachMovie("ship_mc", "myShip",  getNextHighestDepth());
//聲明變數
var enArray:Array;  // 現在是空的
var bulletArray:Array; // 空的
var myGame = new Game(myShip , enArray , bulletArray);
//遊戲迴圈
_root.onEnterFrame = function(){
 myGame.moveShip("right");
}
Then I wrote minimal code so that the classes would just compile
然後我寫下最少量的代碼以致能讓它剛好編譯
class Game{
 //遊戲類,控制整個遊戲並包含其它類的執行個體。
 // 聲明變數

 var ship:Spaceship;
 var enemyArray:Array;
 var laserArray:Array;
 (譯者註:上面最好用Private加以標明,否則就沒有封裝的意義了)
 // 建構函式
 function Game(_ship:Spaceship, _enArray:Array, _bullArray:Array){
 ship       = _ship;
 enemyArray = _enArray;
 laserArray = _bullArray;
 }
 (譯者註:這個函數最好在頭前加Public在尾部加:void,這樣子就比較正規了。)
}
然後在Spaceship.as檔案裡我這樣寫:
class Spaceship extends MovieClip{

}
然後編譯,但是沒有錯誤。
但是那裡應該有些錯誤因為moveShip方法還沒有出現?嗯??(譯者註:我倒)
在調試中什麼也沒有出現。
相當討厭的出錯檢查。。。噢,好吧。。。
現在我必須寫Game.moveShip方法了。。。我會寫下它並測試。。。
我寫下了moveShip方法並意識到我必須再寫一個可以檢測哪個鍵被按下了並傳回一個Sring類的dir變數的
chekcKey 方法用以檢測按鍵。
// Game類
// 檢測按鍵的方法:
 function checkKey():String{
 if(Key.isDown(Key.RIGHT)){
 dir = "right";
 }
 if(Key.isDown(Key.LEFT)){
 dir = "left";
 }
 if(Key.isDown(Key.UP)){
 dir = "up";
 }
 if(Key.isDown(Key.DOWN)){
 dir = "down";
 }
 return dir;
 } 
 // moveship方法
 // 1. 檢查按鍵
 // 2. 分配變數dir就是在每按下鍵一次,把dir傳給spaceship.move方法
 function moveShip(dir:String){
 ship.move(dir);
 }
編譯後並得到了錯誤。。。
" 行 38: 沒有'move'方法."
太棒了,開始得到錯誤了,(譯者注,我再倒),那正是所期待著的要發生的事。
現在寫下ship.move方法來清除錯誤。。。
那就是“測試優先”的想法(作者這樣寫:主要是這裡做的是個小東東,而且主要目的
在於嘗試AS2編程,至於諸位自己做項目的時候,用什麼模式,還請自己拿捏准喲.)
把方法在一系列的測試中實施直到它們出了問題,然後編寫方法直到它符合要求接著移向下一個方法。
我使得飛船移動,這裡就是我如何做的。。。

class Game{
 //聲明變數
 var ship:Spaceship;
 var enemyArray:Array;
 var laserArray:Array;
 var dir:String;
 
 // ====   建構函式  ==============
 function Game(_ship:Spaceship, _enArray:Array,
 _bullArray:Array){
 ship       = _ship;
 enemyArray = _enArray;
 laserArray = _bullArray;
 }
 
 // ====  檢查按鍵的方法 =======
 function checkKey():String{
 if(Key.isDown(Key.RIGHT)){
 dir = "right";
 }
 else if(Key.isDown(Key.LEFT)){
 dir = "left";
 }
 else if(Key.isDown(Key.UP)){
 dir = "up";
 }
 else if(Key.isDown(Key.DOWN)){
 dir = "down";
 }
 else dir="stop";
 //下面這個起作用了
 //trace(dir + " - in game.checkey");

 return dir;
 }
 
 // ===  移動飛船的方法 =====
 // 1.檢查按鍵
 // 2.分配給變數dir相應的方向
 // 3 把變數dir的值傳進spaceship.move方法中
 function moveShip(dir:String){
 ship.move(checkKey());

 }
} //game類結束
在宇宙飛船類中:

class Spaceship extends MovieClip{
 var dir:String;
function move(_dir:String){
 dir = _dir;
 if(dir=="left") _x -= 20;
 if(dir=="right")_x += 20;
 if(dir=="up")   _y -= 20;
 if(dir=="down") _y += 20;
 if(dir=="stop"){
  _x +=0;
  _y +=0;
  }
 }
} //Spaceship類結束
我在把變數dir傳進ship.move方法時沒有遇到任何麻煩,然後我嘗試試著直接使用checkKey方法,因為它總是返回dir,當然,這個起效了。
然後我不得不加一個stop在其中...無論何時當鍵按起的時候,飛船的運動有一些可笑,這樣的狀態一直持繼著,直到我在後來能把運動變得平緩為止...
但是我知道我的設計起效了。
我僅僅要作是只是把宇宙飛船(SPACESHIP)的執行個體傳給遊戲類的建構函式中。
然後,哈哈,presto(類例於芝麻開門之類的話)...接下來是什麼呢?嗯,或許是發射鐳射子彈吧。。。好的,讓我們走。

 

發射雷射子彈
這個花了我兩天的時間,我幾乎不能相信。我持續著錯誤的子彈發射。。。這裡是我發射鐳射子彈方法的第一次嘗試。
// 在game類中:
//  ====== 發射鐳射子彈 ======== 
 function fireLaser_old(){
 if(Key.isDown(Key.SPACE)){
     // set start pt of laser
  laserArray[bulletNum]._y = ship.getY();
  laserArray[bulletNum]._x = ship.getX();
  // if space bar pressed set flag
  hasFired = true;
  bulletNum++;
  if(bulletNum >=5){
   bulletNum = 0;
   }
  }
 }
上面的代碼已相當接近我最後結束時的狀態,最實際的問題是在於movelaser方法。
噢哈哈,我把鐳射子彈發射放在了我的FLA中的EnterFrame迴圈中了...大大的錯誤...
這必須放在FLA檔案的onKeyDown事件中。這就是目前為止的狀況:

//在fla檔案的actions面板中
attachMovie("ship_mc", "myShip",  getNextHighestDepth());
var enArray     = new Array(3);
var bulletArray = new Array(5);
//串連bullet數組
for(var i =0;i < 5;i++){
 attachMovie("laser_mc", "laser"+i, 100 + i);
 bulletArray[i] = _root["laser"+i];
}
// 聲明並初始化遊戲類的實體
// 把飛船, 敵機數組和子彈數組傳進去
var myGame = new Game(myShip , enArray , bulletArray);

//  ======= 擷取索引值============ //
someListener = new Object();
someListener.onKeyDown = function () {
 myGame.fireLaser();
 
 };
Key.addListener(someListener);

// 遊戲迴圈
_root.onEnterFrame = function(){
 myGame.checkKey();
 myGame.moveShip(dir);
 myGame.moveLaser();
}
這樣好了一些,但是仍舊沒有得到正確的子彈發射。。。它要比空格鍵延遲兩個鍵後才發射。
嗯,好吧,這是我這次使用的moveLaser方法:
// ========= move laser  ==========//
 function moveLaser_old(){
  if(hasFired==true){
  laserArray[bulletNum]._x += 30;
  }
  if(laserArray[bulletNum]._x > Stage.width)
  {
   laserArray[bulletNum]._x = -10;
   hasFired = false;
  }
 } // ============== //

下面是最終(也就是現在)使用的鐳射子彈發射方法。
它的運作很簡單,得到飛機的位置並傳遞給子彈。
然後子彈數目開始增加,當數字大於5的時候,它被重新初始化到0。
// ========= FIRE LASER ====== //
 function fireLaser(){
  if(Key.isDown(Key.SPACE)){
   // set start point
   laserArray[bulletNum]._y = ship.getY();
   laserArray[bulletNum]._x = ship.getX();
   // increment the bullet number
   ++bulletNum;
   // if more than 5 bullets , start again at 0
   if (bulletNum>5) {
    bulletNum = 0;
    }
  }
 }
下面是最終移動子彈的方法,同樣是非常的單簡。
這個過程遍曆所有的子彈,如果有子彈可以提供,就移動它。它仍舊不是很完美,但現在還能湊和著用。
// ======= MOVE LASER ======= //
 function moveLaser(){
  var bulleti = 0;
  while (bulleti<6) {
  laserArray[bulleti]._x += 30;
  bulleti++;
  }
 } // ============= //

下面是到目前為止所建立的遊戲類:

class Game{
 //  ========= 聲明變數
 var ship:Spaceship;
 var enemyArray:Array;
 var laserArray:Array;
 var dir:String;
 var bulletNum:Number = 0;
 
 // ====   建構函式==============
 function Game(_ship:Spaceship, _enArray:Array,
  _bullArray:Array){
  ship       = _ship;
  enemyArray = _enArray;
  laserArray = _bullArray;
 }
 
 // ====  檢測鍵被按下的方法 =======
 function checkKey():String{
 if(Key.isDown(Key.RIGHT)){
 dir = "right";
 }
 else if(Key.isDown(Key.LEFT)){
 dir = "left";
 }
 else if(Key.isDown(Key.UP)){
 dir = "up";
 }
 else if(Key.isDown(Key.DOWN)){
 dir = "down";
 }
 else dir="stop";
 
 return dir;
 }

 // ===  移動飛船的方法 =====
 // 1.檢查按鍵
 // 2.分配給變數dir相應的方向
 // 3 把變數dir的值傳進spaceship.move方法中
 function moveShip(dir:String){
 ship.move(checkKey());

 }
 
 // ========= 發射子彈 ====== //
 function fireLaser(){
  if(Key.isDown(Key.SPACE)){
   // 設定起始位置
   laserArray[bulletNum]._y = ship.getY();
   laserArray[bulletNum]._x = ship.getX();
   // 增加子彈數目
   ++bulletNum;
   // 如果大於5,重新將數目開始於 0
   if (bulletNum>5) {
    bulletNum = 0;
    }
  }
 }
 
 // ======= 移動子彈 ======= //
 function moveLaser(){
  var bulleti = 0;
  while (bulleti<6) {
  laserArray[bulleti]._x += 30;
  bulleti++;
  }
 } // ============= //
 
  
} //  ------ 遊戲類結束 ------- //
 
下面是Spaceship類和它所使用的 getX 和getY方法:

class Spaceship extends MovieClip{
 var dir:String;
 // ===== 移動 =========
 function move(_dir:String){
 dir = _dir;
 if(dir=="left") _x -= 20;
 if(dir=="right")_x += 20;
 if(dir=="up")   _y -= 20;
 if(dir=="down") _y += 20;
 if(dir=="stop"){
  _x +=0;
  _y +=0;
  }
 }
 // ====== 得到X值 ====
 function getX():Number{
 return _x;
 }
 //  ======= 得到Y值 =====
 function getY():Number{
 return _y;
 }
} //  ====Spaceship類結束 

這裡是Laser類:

class Laser extends MovieClip{
 // ======= 建構函式 ========= //
 function Laser(x:Number, y:Number){
 _x = x;
 _y = y;
 }
}

下載到目前為止的原始碼:

下面讓我們進入這篇文章的第二部分.

 

 

 

 

 

 

 

 

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.