2012年4月17日 星期二

[教學] 物理盒子遊戲製作 (Physical Box)

這個遊戲製作教學, 目標完成一個物理盒子遊戲, 在iOS 和Android 運作.
我們使用Adobe AIR, 結合Starling 圖像引擎Nape 物理引擎, 製作一個簡單小遊戲.

遊戲說明:
  • 按藍色盒子, 會使它消失
  • 按黑色和紅色盒子, 不會消失
  • 把紅色盒子安全地降落在啡色盒子之上
請按 [觀看] 範例

在設計上, 我們分成以下兩個層面說明:
  • 介面部分 (physical_box.mxml 檔)
       處理遊戲流程 (包括: 載入, 開始和重玩功能)
  • 遊戲部分  (MyGame.as 檔)
       處理遊戲內容 (包括:  盒子定位, 消失藍色盒子和完成遊戲功能)
圖層分佈 (介面部分)

介面部分 (physical_box.mxml 檔)
  1. 初次化Starling 和MyGame 物件
    private function init():void{
      _starling = new Starling(MyGame, this.stage);
      _starling.start();
      _starling.stage.addEventListener(starling.events.Event.ADDED, addedHandler);
    }
  2. 當MyGame 物件被加入至介面部分時, 把 MyGame 物件記下, 然後顯示開始按鈕 (startImg)
    private function addedHandler(event:starling.events.Event):void{
      if(_starling.stage.numChildren>0){
        // <----- remove listener
        _starling.stage.removeEventListener(starling.events.Event.ADDED,addedHandler);
        
        // <----- cache variable
        _myGame = _starling.stage.getChildAt(0) as MyGame;
          
        // <----- add listener
        _myGame.addEventListener(starling.events.Event.COMPLETE,completeHandler);
        
        // <----- invisible busyIndicator
        this.removeElement(busyIndicator);
        
        // <----- visible startImg
        myFade2.play();
      }
    }
    
  3. 當用戶按下開始按鈕, 等待按鈕消失 (Fade Out), 然後呼叫MyGame 物件重新開始
    private function clickStartImgHandler(event:MouseEvent):void{
      restartBtn.visible = true;
      myFade3.play();
    }
    private function effect3Stop():void{
      _myGame.reset();
      this.removeElement(startImg);
    }
    
  4. 最後, 當介面接收MyGame 回傳完成事件 (Event.Complete), 顯示完成圖案 (winImg)
    private function completeHandler(event:starling.events.Event):void{
      myFade1.play();
    }
    


遊戲部分 (MyGame.as 檔)
  1. 當MyGame 物件被產生後, 等待MyGame 物件被加入至介面部分
    public function MyGame(){
      addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
    }
    
  2. MyGame 物件進入介面後, 我們設定遊戲空間, 加入遊戲背景圖案, 和定設兩個遊戲事件
    private function addedToStageHandler(event:Event):void{
      // <----- cache variable
      _ns = Starling.current.nativeStage;
      _space = new Space(new Vec2(0, 3000));
      
      // <----- add listener
      addEventListener(Event.ENTER_FRAME, enterFrameHandler);
      _ns.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
      
      // <----- add background
      addChild(Image.fromBitmap(new _bgClass()));
    }
    
  3. 遊戲事件一: 若用戶按下藍色盒子, 它便會消失
    private function downHandler(event:MouseEvent):void{
      var mp:Vec2 = new Vec2(event.stageX, event.stageY);
      var bodies:BodyList = _space.bodiesUnderPoint(mp);
      if(bodies.length > 0){
        var b:Body = bodies.shift();
        if(b.graphic as Box!=null){
          removeChild(b.graphic);
          b.shapes.clear();
        }
      }
    }
    
  4. 遊戲事件二: 若紅色盒子進入有效區域 (winRect), 便發出完成事件 (Event.Complete)
    private function enterFrameHandler(event:Event):void{
      _space.step(1/60);
      if(_winRect!=null)
        if(_winRect.contains(_star.position.x, _star.position.y)){
          // <----- clear condition
          _winRect= null;
          
          // <----- dispatch event
          this.dispatchEvent(new Event(Event.COMPLETE));
        }
    }
    
  5. 當介面呼叫MyGame 物件重新開始, 我們刪除舊有內容, 然後設定新內容
    public function reset():void{
      // <----- remove all objectes
      var bodies:BodyList = _space.bodies;
      for(var i:int=0; i<bodies.length; i++){
        var b:Body = bodies.at(i);
        this.removeChild(b.graphic);
        b.shapes.clear();
      }
      
      // <----- add objectes
      defineObject();
    }
    
  6. 新內容包括: 盒子可移動範圍, 新盒子, 和紅色盒子有效區域 (winRect)
    private function defineObject():void{
      ......
      addBox(halfW+10, stageH-600);
      
      _base = addBase(halfW, stageH-100);
      _star = addStar(halfW, stageH-610);
      
      _winRect = new Rectangle(halfW-Base.WIDTH/2, stageH-100-Star.HEIGHT, Base.WIDTH, Star.HEIGHT);
    }
    

若大家有興趣, 可以改良一下, 加入更多關卡玩玩喔.
大家可以 [下載] 範例試試看.

注意事項:

  • 若在發佈iOS 版本時, 出現錯誤訊息 (Exception in thread "main" java.lang.OutOfMemoryError: Java heap space),  請選擇執行"Export Release Build" , 它可以避免產生這個錯誤.

錯誤訊息 Java heap space
Export Release Build

沒有留言: