2013年6月23日 星期日

Flash遊戲引擎 CitrusEngine (六) 建立你的第一個遊戲- 場景編輯ObjectMaker與Camera控制

經過前面幾篇的介紹,相信您已經可以做出一個簡單的2D物理遊戲,有敵人,可以用鍵盤操作角色作動作,不過可能開始會有一些疑惑,場景難道遊戲的場景不能在大一點嗎?
如果你想作一個關卡,總寬有5000以上(瑪莉兄弟一樣),可別真的去設定一個寬5000以上的Satge,實際上在CitrusEngine裏面的世界理論上是不預設的(無限大),我們一開始設定的Stage size (500x400)只是遊戲中畫面鏡頭(Camera)的大小,如下圖示意

實際上只要角色移動時,Camera也跟著移動,就可以做到這樣的效果,一般我們把這功能叫作鏡頭跟隨。想作出這樣的效果相當簡單,因為CitrusEngine已經有提供Camera物件讓你可以直接使用。
請在initialize加上以下這句Camera物件程式碼。
//鏡頭跟隨控制
view.camera.target = hero;
//定位在畫面中心點
view.camera.offset.x = 250;
view.camera.offset.y = 200;
每個State會有一個view,每個view都有個camera,你可以設定他的屬性。
我們只要把camera的target(跟隨目標)設定成 hero物件,然後把畫面定位在stage的中心點,你作可以很容易的作出鏡頭跟隨的效果。你可以輸出並操作看看。

目前這個世界的地板(bottom)只有500px,相當小,一不小心就會掉下無底深淵XD,為了讓角色可以盡情奔馳,我們希望可以把場景作寬闊一點,當然你可以直接延伸你的地板,並且在其他更遠的地方加上平台與金幣....不過如果場景上全部的物件都用程式寫出來,實在是極為麻煩的事,接下來介紹一個讓你輕鬆編輯場景的方法。

首先去官網下載作好的Flsah組件庫
用Flash打開Components.fla這個檔案,這是一個空白的場景,讓你自己編輯你的遊戲物件。
打開這個fla的元件庫,可以看到已經有作好的元件讓你直接使用。

目前我們是使用Box2D物理引擎(別不小心使用到Nape的物件喔!),你可以直接使用元件庫裏面的Box2D物件,把相對應的物件擺放到需要的位置,這樣子就可以很輕鬆的製作你的場景。
我的場景用Platform拉出了直式的世界,Hero一開始是在左小角(藍色),黃色的物件是Coin(金幣),並放置一個Enemy敵人(紅色),為了方便之後使用,特地把最下面的Platform實體名取為bottom,各階梯實體名都取為cloud,之後我就可以用名稱來分辨他們,遊戲開始的時後Hero就可以踏著Platform往上跳。作好了之後直接輸出swf即可。

接下來,我們只要把輸出的swf拿到我們的State去用就好了。
CitrusEngine有提供一個ObjectMaker工具物件,他會自動對應你的swf,然後幫你建立場景。
首先用Loader載入你的swf。

//載入建立的場景
var _loader:Loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onViewLoaded);
_loader.load(new URLRequest("gameState.swf")); //gameState.swf就是我剛剛輸出的swf
載入好了之後用ObjectMaker去建立你的場景
/**
   * gameState.swf載入
   * @param e
   */
  private function onViewLoaded(e:Event):void 
  {
   e.target.removeEventListener(Event.COMPLETE, onViewLoaded);
   var _loader:Loader = LoaderInfo(e.target).loader;
   //加入Box2D物理引擎
   var box2D:Box2D = new Box2D("box2D");
   box2D.visible = true; //debug模式開關
   add(box2D);
   //建立場景
   ObjectMakerStarling.FromMovieClip(_loader.content as MovieClip);
   _loader.unloadAndStop();
  }
Box2D物理引擎是一定要加的,然後我們用ObjectMakerStarling.FromMovieClip去建立從Loader取出的MovieClip。
之後把Loader的內容釋放掉。如果你現在輸出的話,你就可以看到你用flash輸出的場景,而且還可以操作,很方便吧!
再來我們對遊戲裏的元素作一些細部的設定。你可以用State的getObjectByName("物件名稱")或getObjectsByType(物件類別)來取得各個元素去設定你想要的View或他的參數。
//加入地板
   var bottom:Platform = getObjectByName("bottom") as Platform; //取出名稱為bottom的物件
   bottom.view = "500x30.jpg";
   //加入角色
   var bitmap:Bitmap = new _heroPng();
   var texture:Texture = Texture.fromBitmap(bitmap);
   var xml:XML = XML(new _heroConfig());
   var sTextureAtlas:TextureAtlas = new TextureAtlas(texture, xml);
   var hero:Hero = getFirstObjectByType(Hero) as Hero;  //取出類別為Hero的物件
   hero.acceleration = 0.3; //加速度
   hero.maxVelocity = 5; //速度極限
   hero.view = new AnimationSequence(sTextureAtlas, ["walk", "duck", "idle", "jump", "hurt"], "idle");
   hero.offsetY = -10;
   hero.group = 1;
   
   hero.onJump.add(heroOnJump);//跳躍觸發
   hero.onGiveDamage.add(heroOnGiveDamage);//攻擊觸發
   hero.onTakeDamage.add(heroOnTakeDamage);//被攻擊觸發
   
   //加入一個平台
   
   var _CitrusObjectVec:Vector. = getObjectsByName("cloud"); //取出所有名稱為cloud的物件陣列
   var _num:int = _CitrusObjectVec.length;
   var _cloud:Platform;
   var i:int;
   for (i = 0; i < _num; i++) 
   {
    _cloud = _CitrusObjectVec[i] as Platform; 
    _cloud.view = "200x30.jpg";
    _cloud.oneWay = true;
   }
   //加入一個金幣
   _CitrusObjectVec = getObjectsByType(Coin); //取出所有類別為Coin的物件陣列
   _num = _CitrusObjectVec.length;
   var _coin:Coin;
   //加入敵人
   var enemy:Enemy = getFirstObjectByType(Enemy) as Enemy; //取出第一個類別為Enemy的物件
   enemy.leftBound = 130;
   enemy.rightBound = 270;
   enemy.view = "Enemy.png";
好了之後,關掉Box2D的debug,你就可以看到一個完整的遊戲。
最後你會發現一個很蠢的現象,就是場景根據鏡頭移動,不過你的記分欄位,與生命值欄位居然也一起跟的動了....
我們希望他應該一直都在同一個位子才對。原因是你的記分欄(_scoreTd)與生命值(_livesTd)都跟遊戲中的物件在同一個View,偏偏一個State又只有一個View,所以你也沒有其他地方可以擺...
其實場景上每個CitrusSprite物件有個屬性叫做parallaxY與parallaxX,他可以讓你控制鏡頭移動時與物件相對移動的比例,一般來說你可以用這個屬性作出遊戲中的遠景與近景移動的距離感(你可以自己實驗看看..),預設是1,你可以把他設成0,這樣就物件就不會跟著鏡頭移動了。(設成0.5的話會有遠景的效果)
//分數欄位
   var _scoreTd:CitrusSprite = new CitrusSprite("scoreTd", { view: new TextField(200, 50, "分數:0") , x:80, y:0, group:2 });
   _scoreTd.parallaxX = 0;
                        _scoreTd.parallaxY = 0;
   add(_scoreTd);
   //生命欄位
   var _livesTd:CitrusSprite = new CitrusSprite("livesTd", { view: new TextField(200, 50, "生命:" + citrusEngine.gameData.lives) , x:180, y:0, group:2 } ) ;
                        _livesTd.parallaxX = 0;
   _livesTd.parallaxY = 0;
   add(_livesTd);
Demo預覽
原始碼下載

Flash遊戲引擎 CitrusEngine (七) 開始你的第一個行動APP遊戲吧 - 開始一個CitrusEngine APP專案

沒有留言: