動畫物件
在一般的2D遊戲中,動畫可以用2D骨骼動畫製作(如:Spine)、粒子系統(如:Particles)、或者使用Tween(如:gsap)以及逐格動畫來製作。
下面為這四種動畫的介紹:
- 骨骼動畫:針對角色動畫的骨架做設定,並且經由改變骨骼元件方向及變形來讓角色做出如行走、跳躍等動態動作。使用骨骼動畫可以大大降低角色所占的圖像空間,尤其是在2D的遊戲裡,這是不可或缺的技術。
- 粒子系統:有許多編輯器可以編輯出粒子效果的設定檔,並藉由粒子系統的程式來做出特效。
- Tween:針對一個物件的某個屬性去設定一段時間將該屬性從a數值變成b數值。可以用在物件位移(更動x、y屬性)、放大縮小(更動scale)、旋轉(更動rotate)等效果上。也可以更改自定義屬性,如跑分效果(將分數慢慢加上去)。
下面是官網上的一個效果範例:
- 逐格動畫:逐格動畫是最簡單原始的動畫類型,由許多張的動態圖組合成為一幅動畫。逐格動畫的動畫製作能夠最精緻、最多樣化,但是也需要花最多力氣在繪製圖像,並且會有很大的檔案大小。其原理與一般電影、gif檔相同。
逐格動畫
PIXI.extras.AnimatedSprite是在Pixi.JS裡處理動畫的類別,官網對此類別的說明如下:
An AnimatedSprite is a simple way to display an animation depicted by a list of textures.
也就是可以用來播放由多張連續的圖檔組成的逐格動畫,在前面的[13- 遊戲製作] 素材處理的部份,已經有分享過該如何將連續圖檔打包成所需的格式,在這一章裡,則會在遊戲裡來實際使用這些連續圖檔。
角色動畫需求
在遊戲中,我們希望角色動畫可以在不同的時間播放不同的動畫,讓角色與遊戲能夠更有互動感,播放時機與動畫的設計如下:
- 待機動畫:播放Character_Idle.json
- 消除成功時:播放Character_Laugh.json
- 按下提示時:播放Character_Jump.json
角色動畫程式撰寫
1. 產生動畫元件: 傳入要產生的動畫名稱,然後設定動畫完成後要呼叫的動作。
createAnim(id:string, onComplete:any){ let anim = Loader.resources[id].textures; let textures = []; for(var index in anim) { textures.push(anim[index]); } var character = new PIXI.extras.AnimatedSprite(textures); character.play(); character.animationSpeed = 0.25; character.loop = false; character.onComplete = onComplete; this.addChild(character); return character; }
2. 產生動畫並設定handler:因為動畫若播到一半被中斷會很突兀,這邊一律是等到動畫播完後,才會依狀態判斷下一個要播的動畫
private shouldPlayTarget:string = 'idle'; constructor(){ super(); //每次動畫完成之後,都要判斷下一個要播放的動畫為何 this.idle = this.createAnim('Character_Idle', this.playAnim.bind(this)); this.jump = this.createAnim('Character_Jump', this.playAnim.bind(this)); this.laugh = this.createAnim('Character_Laugh', this.playAnim.bind(this)); eventEmitter.on(GameFlowEvent.LinkedLineSuccess, ()=>{ this.shouldPlayTarget = 'laugh';//設定下一個要播的動畫 }); eventEmitter.on(GameFlowEvent.TipsRequest, ()=>{ this.shouldPlayTarget = 'jump'; }); } //依據shouldPlayTarget的值來判斷現在要播的動畫 //如果沒有特殊要播的動畫的話,則一律播放待機動畫 playAnim(){ this.idle.visible = false; this.laugh.visible = false; this.jump.visible = false; this[this.shouldPlayTarget].visible = true; this[this.shouldPlayTarget].gotoAndPlay(0); this.shouldPlayTarget = 'idle'; }
Container特性
在上面,我們是直接產生三個動畫物件,在需要使用時才會把visible設為true並且播放,因此要小心是否會造成效能問題,在研究了一下Container.js的原始碼,可以發現如果當元件的visible為false時,是不會去render這個物件的,也不會去處理其相關子元件的畫面變更。
Source:Container.js
在經過實測後,的確將畫面上不會被看到的元件的visible設為false後,能夠提升畫面的fps,因此這也是開發上一個可以多加利用的小技巧。
另外,filter的使用,會花費較多的效能,需要謹慎使用。而mask下的物件,即便因為mask而無法看到,仍舊會一直被render,因此即便是已經在mask下因此畫面上無法看見的元件,依然建議要把可試範圍外的物件的visible設為false,以提升遊戲效能。
今日成果
線上demo:http://claire-chang.com/ironman2018/1104/
今日成果下載:ironman1104