2012年8月20日 星期一

[教學] Flash 遊戲製作 (憤怒豬 Angry Pig)

為大家介紹如何在Adobe AIR 編寫憤怒的小鳥(Angry Birds) 遊戲. 者作製作一個簡單範例 - 憤怒豬(Angry Pig), 以Starling 圖像引擎Nape 物理引擎完成.

請按 [觀看] 範例

遊戲內容與物理盒子遊戲相近, 不同在於處理以下事件(Event) 的內容:
  • MouseEvent.MOUSE_DOWN 時, 若用戶按在_pigImg 上, 把_dragFlag 設定true
    private function downHandler(event:MouseEvent):void{
      var mp:Vec2 = new Vec2(event.stageX, event.stageY);
      var bodies:BodyList = _space.bodiesUnderPoint(mp);
      
      // <----- start the launching action
      if(bodies.length > 0){
        var b:Body = bodies.shift();
        if(b==_pigImg)
          _dragFlag = true;
      }
    }
    
  • MouseEvent.MOUSE_UP 時, 若_pigImg 存在和_dragFlagtrue:
     - 建立_pig 於Nape 物理世界中
     - 以用戶手指與憤怒豬(_pigImg) 原來位置的距離乘以十倍, 設定_pig 拋出的速度 (velocity)
     - 移除_pigImg 這個圖案 (它是沒有物理效果)
     - 重設_historyData 路徑記錄

    private function upHandler(event:MouseEvent):void{
      if(_pigImg!=null && _dragFlag){
        var mp:Vec2 = new Vec2(_ns.mouseX, _ns.mouseY);
        var b:Vec2 = mp.subeq(_pigPosition);
        
        // <----- add a pig to physical world
        _pig = addPig(_ns.mouseX, _ns.mouseY);
        _pig.velocity = new Vec2(-b.x*10, -b.y*10);
        
        // <----- remove the launching pig
        this.removeChild(_pigImg.graphic);
        _pigImg.shapes.clear();
        
        // <----- reset paths of history
        _historyData = new Vector.<HistoryData>;
      }
      
      // <----- stop the launching action
      _dragFlag = false;
    }
    
  • Event.ENTER_FRAME 時, 我們進行以下測試和行為:
     - 若_historyData 路徑記錄存在:
        - 把路徑以QuadBatch 方式批次渲染於螢幕上
        - 然後把最後的路徑記下 (最多記錄30 個)
     - 若_dragFlagtrue, 把_pigImg 圖案移至用戶手指的位置上
     - 若_pig 存在, 測試它是否正在移動, 若接近停頓狀態, 重設_pigImg
     - 最後, 假如星星_star 移動速度大於一個數值, 遊戲便可完成
    private function enterFrameHandler(event:Event):void{
      // <----- run nape physical engine
      _space.step(1/60);
      
      if(_historyContainer!=null){
        // <----- reset history container
        _historyContainer.reset();
        
        // <----- draw paths to history container
        for(var i:int=_historyData.length-1; i>=0; i--){
          _historyImage.x = _historyData[i].x;
          _historyImage.y = _historyData[i].y;
          _historyImage.alpha = 1-i/_historyData.length;
          _historyContainer.addImage(_historyImage);
        }
        
        // <----- save the latest path
        if(_historyData.length<30 && _pig!=null){
          var historyData:HistoryData = new HistoryData();
          historyData.x = _pig.position.x
          historyData.y = _pig.position.y;
          _historyData.push(historyData);
        }
      }
      
      // <----- draw the launching position
      if(_dragFlag){
        var mp:Vec2 = new Vec2(_ns.mouseX, _ns.mouseY);
        _pigImg.position.set(mp);
      }
      
      // <----- kill the pig, if it stops
      if(_pig!=null && _star!=null){
        var v:Number = Math.abs(_pig.velocity.x)+Math.abs(_pig.velocity.y);
        if(v<50 || _pig.velocity.angle==0){
          this.removeChild(_pig.graphic);
          _pig.shapes.clear();
          _pig = null;
          _pigImg = addPigImage(_pigPosition.x, _pigPosition.y);
        }
      }
      
      // <----- game over, if the star is hitted
      if(_star!=null){
        var v2:Number =Math.abs(_star.velocity.x)+Math.abs(_star.velocity.y);
        if(v2>100 && _pig!=null){
          _star = null;
          this.dispatchEvent(new Event(Event.COMPLETE));
        }
      }
    }
    
當然製作一個成功遊戲, 需要很多配合(如: 遊戲流程, 角色設計, 場景設計, 測試優化, 市場推廣... 等). 但遊戲的核心部分, 不是一個困難, 重點在於創意與技術結合成一件產品喔.

大家可以 [下載] 範例試試看.

沒有留言: