iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 20
3
Software Development

遊戲之美 - 連連看經典遊戲開發系列 第 20

[20- Pixi教學] 連連看公仔實作- 逐格動畫

  • 分享至 

  • xImage
  •  

動畫物件

在一般的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;
}
  1. 產生動畫並設定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


上一篇
[19- Pixi教學] 連連看盤面實作
下一篇
[21- Pixi教學] 連線效果實作-Graphics
系列文
遊戲之美 - 連連看經典遊戲開發31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言