LibGDX圖形模塊之2D動(dòng)畫

2D動(dòng)畫是一種用于使用靜態(tài)圖像創(chuàng)建運(yùn)動(dòng)錯(cuò)覺(jué)的技術(shù)韧衣。 本文介紹如何使用LibGDX的動(dòng)畫類來(lái)創(chuàng)建動(dòng)畫盅藻。

動(dòng)畫由多個(gè)幀組成,以設(shè)定的間隔以序列顯示畅铭。 運(yùn)行 人的動(dòng)畫可以通過(guò)循環(huán)運(yùn)行并播放這些圖像來(lái)實(shí)現(xiàn)氏淑。
以下“sprite sheet”圖像顯示一個(gè)男人跑步的完整循環(huán)。 每個(gè)框包含一個(gè)動(dòng)畫幀硕噩。 當(dāng)這些幀在一段時(shí)間內(nèi)順序顯示時(shí)假残,它們就成了動(dòng)畫。

sprite sheet.png

幀速率是每秒更改幀的頻率炉擅。 示例精靈表的完整運(yùn)行周期有30幀(6列和5行)辉懒。 如果該動(dòng)畫在一秒鐘內(nèi)完成一個(gè)周期阳惹,則每秒必須顯示30幀,因此幀速率為30 FPS眶俩。 每幀的時(shí)間(稱為幀時(shí)間或間隔時(shí)間)是FPS的倒數(shù)穆端,在這種情況下為每幀0.033秒。

動(dòng)畫是一個(gè)非常簡(jiǎn)單的狀態(tài)機(jī)仿便。 跑步的人根據(jù)精靈畫面有30個(gè)狀態(tài)。 編號(hào)的框架代表一個(gè)正在跑步的人經(jīng)歷的狀態(tài)攒巍,一次只有一個(gè)嗽仪。 當(dāng)前狀態(tài)由動(dòng)畫開(kāi)始以來(lái)的時(shí)間量決定。 如果少于0.033秒柒莉,我們?cè)跔顟B(tài)1闻坚,所以第一個(gè)sprite被繪制。 如果我們?cè)?.033和0.067秒之間兢孝,那么我們?cè)跔顟B(tài)2窿凤,依此類推。 如果動(dòng)畫循環(huán)跨蟹,則在顯示所有幀后返回到第一幀雳殊。

Paste_Image.png

動(dòng)畫類
LibGDX's Animation (code) 類可用于輕松管理動(dòng)畫。 它的構(gòu)造函數(shù) 具有圖像列表和幀間隔時(shí)間窗轩。 在播放過(guò)程中夯秃,其getKeyFrame方法會(huì)根據(jù) 已用時(shí)間參數(shù),返回該時(shí)間的適當(dāng)圖像痢艺。

TextureAtlas使用示例

LibGDX's TextureAtlas (code)通常用于將許多單獨(dú)的紋理區(qū)域組合成的紋理集合,以減少昂貴的繪圖調(diào)用仓洼。 (details here).。

TexturePacker和TextureAtlas提供了一種方便的方法來(lái)生成動(dòng)畫堤舒。 動(dòng)畫的所有源圖像應(yīng)以最后的下劃線和幀號(hào)命名色建,如running_0.png,running_1.png舌缤,running_2.png等箕戳。TexturePacker將自動(dòng)使用這些數(shù)字作為幀號(hào)(只要將參數(shù)useIndexes設(shè)置為真)。

加載TextureAtlas之后友驮,可以立即獲取完整的框架數(shù)組漂羊,并將其傳遞到Animation構(gòu)造函數(shù)中:

public Animation<TextureRegion> runningAnimation;
//...
runningAnimation = 
    new Animation<TextureRegion>(0.033f, atlas.findRegions("running"), PlayMode.LOOP);

精靈示例演示

以下代碼片段將使用animation_sheet.png sprite-sheet創(chuàng)建一個(gè)動(dòng)畫,并將動(dòng)畫渲染到屏幕卸留。

public class Animator implements ApplicationListener {

    // Constant rows and columns of the sprite sheet
    private static final int FRAME_COLS = 6, FRAME_ROWS = 5;

    // Objects used
    Animation<TextureRegion> walkAnimation; // Must declare frame type (TextureRegion)
    Texture walkSheet;
    SpriteBatch spriteBatch;

    // A variable for tracking elapsed time for the animation
    float stateTime;

    @Override
    public void create() {

        // Load the sprite sheet as a Texture
        walkSheet = new Texture(Gdx.files.internal("animation_sheet.png"));

        // Use the split utility method to create a 2D array of TextureRegions. This is 
        // possible because this sprite sheet contains frames of equal size and they are 
        // all aligned.
        TextureRegion[][] tmp = TextureRegion.split(walkSheet, 
                walkSheet.getWidth() / FRAME_COLS,
                walkSheet.getHeight() / FRAME_ROWS);

        // Place the regions into a 1D array in the correct order, starting from the top 
        // left, going across first. The Animation constructor requires a 1D array.
        TextureRegion[] walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
        int index = 0;
        for (int i = 0; i < FRAME_ROWS; i++) {
            for (int j = 0; j < FRAME_COLS; j++) {
                walkFrames[index++] = tmp[i][j];
            }
        }

        // Initialize the Animation with the frame interval and array of frames
        walkAnimation = new Animation<TextureRegion>(0.025f, walkFrames);

        // Instantiate a SpriteBatch for drawing and reset the elapsed animation
        // time to 0
        spriteBatch = new SpriteBatch();
        stateTime = 0f;
    }

    @Override
    public void render() {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear screen
        stateTime += Gdx.graphics.getDeltaTime(); // Accumulate elapsed animation time
        
        // Get current frame of animation for the current stateTime
        TextureRegion currentFrame = walkAnimation.getKeyFrame(stateTime, true);
        spriteBatch.begin();
        spriteBatch.draw(currentFrame, 50, 50); // Draw current frame at (50, 50)
        spriteBatch.end();
    }

    @Override
    public void dispose() { // SpriteBatches and Textures must always be disposed
        spriteBatch.dispose();
        walkSheet.dispose();
    }
}
Paste_Image.png

使用以下的構(gòu)造函數(shù)可以快速創(chuàng)建動(dòng)畫

Method signature Description
Animation (float frameDuration, TextureRegion... keyFrames) 第一個(gè)參數(shù)是幀時(shí)間走越,第二個(gè)參數(shù)是構(gòu)成動(dòng)畫的區(qū)域(幀)數(shù)組

最佳做法

將幀與其他精靈一起打包成一個(gè)紋理,以優(yōu)化渲染耻瑟。 這用TexturePacker很容易完成旨指。
根據(jù)游戲類型確定合理數(shù)量的幀赏酥。 對(duì)于復(fù)古的街機(jī)風(fēng)格,10 fps可能就足夠了谆构,而更逼真的運(yùn)動(dòng)需要更多的幀裸扶。

資源

在這里獲取 sprite-sheet 資源 here.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市搬素,隨后出現(xiàn)的幾起案子呵晨,更是在濱河造成了極大的恐慌,老刑警劉巖熬尺,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摸屠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡粱哼,警方通過(guò)查閱死者的電腦和手機(jī)季二,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)揭措,“玉大人胯舷,你說(shuō)我怎么就攤上這事“砗” “怎么了桑嘶?”我有些...
    開(kāi)封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)躬充。 經(jīng)常有香客問(wèn)我不翩,道長(zhǎng),這世上最難降的妖魔是什么麻裳? 我笑而不...
    開(kāi)封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任口蝠,我火速辦了婚禮,結(jié)果婚禮上津坑,老公的妹妹穿的比我還像新娘妙蔗。我一直安慰自己,他們只是感情好疆瑰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布眉反。 她就那樣靜靜地躺著,像睡著了一般穆役。 火紅的嫁衣襯著肌膚如雪寸五。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天耿币,我揣著相機(jī)與錄音梳杏,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛十性,可吹牛的內(nèi)容都是我干的叛溢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼劲适,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼楷掉!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起霞势,我...
    開(kāi)封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤烹植,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后愕贡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體刊橘,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年颂鸿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攒庵。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嘴纺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浓冒,到底是詐尸還是另有隱情栽渴,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布稳懒,位于F島的核電站闲擦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏场梆。R本人自食惡果不足惜墅冷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望或油。 院中可真熱鬧寞忿,春花似錦、人聲如沸顶岸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辖佣。三九已至霹抛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卷谈,已是汗流浹背杯拐。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人藕施。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓寇损,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親裳食。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矛市,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容