1. 程式人生 > >title: Godot3遊戲引擎入門之四:給主角新增動畫(下)

title: Godot3遊戲引擎入門之四:給主角新增動畫(下)

一、前言

本篇是上一節文章:Godot3遊戲引擎入門之四:給主角新增動畫(上)的繼續。在這兩篇文章裡,我會詳細講述 Godot 3 中製作簡單精靈動畫的三種方法,其中上部分包含兩種,下部分討論第三種方式。 :smile:

二、正文

本篇目標

  1. 使用動畫精靈 AnimatedSprite 節點建立 Sprite 騎士動畫(上篇)
  2. 使用 Sprite 節點和 GDScript 指令碼程式碼共同建立背景滾動效果(上篇)
  3. 使用 AnimationPlayer 節點製作天鵝飛舞的關鍵幀動畫(下篇)

建立動畫

首先,簡單回顧一下本篇上節內容中的兩種遊戲動畫製作方式:

第一種方法:使用 AnimatedSprite 製作騎士動畫

非常簡單又符合直覺的一種方法,最適合於打造單個人物或物件的精靈動畫特效。AnimatedSprite 製作動畫的原理相當簡單,只需要提前準備好必須的圖片資源即可,具體操作參考上節的內容。

godot_4_result1.gif

第二種方法:使用程式碼控制背景天空滾動

這種方式相對第一種可以說是最符合*程式設計師*的思維習慣的的:通過程式碼直接控制並移動背景圖片的位置就能達到我們所想要的動畫特效。在上一節內容中,我們還了解到了 Godot 中圖片的座標原點位置的相關設定。

godot_4_result2.gif

第三種方法:使用 AnimationPlayer 關鍵幀製作天鵝動畫

上文介紹的兩種動畫製作方式簡單也不失靈活性,在實際遊戲開發過程中使用的也會比較多,但是,如果你認為 Godot 就這點能耐的話,那你也太小看它了,哈哈。接下來我們開始探討第三種動畫製作方式:關鍵幀動畫!現在,隆重請出我們今天的主角:AnimationPlayer

 ! :sunglasses:

godot_animation_keyframe.jpg

在深入討論之前,我們先了解一下 SpriteSheet 相關知識,如果你有使用過 LibGDX跨平臺遊戲框架開發遊戲的經驗,或者熟悉 Unity 中的 2D 遊戲動畫製作,那麼你肯定對 SpriteSheet 會非常瞭解。我們想象一下第一種動畫方式,使用 AnimatedSprite製作動畫雖然簡單,但是如果涉及到人物多種狀態,比如攻擊、跳躍、行走、死亡等,那麼圖片資源是不是會多如牛毛?而且操作過程中還容易出錯,這就是 SpriteSheet 的由來之處了!簡而言之, SpriteSheet 就是把很多圖片,甚至不同型別的圖片資源,放到一個大圖片裡,方便管理操作和使用,聽說過 

TexturePacker 這個軟體嗎?它就是專門幹這事的。

理論到此結束,我們來瞻仰一下我們要實現的天鵝動畫的圖片資源 SpriteSheet 精靈圖集:

godot_4_swansheet.png

圖片結構很單一,可以看得出是由 8 張連續的小圖拼接而成的,怎麼使用呢?首先,我們還是和往常一樣使用一個 Sprite 精靈節點來顯示天鵝圖片,改名為 Swan ,但是這裡還需要進行一些簡單的設定:

godot_4_hframes.jpg

如上圖,我們設定屬性 Vframes 值為 1 , Hframes 為 8 ,意思很明確,即縱向分 1 幀,橫向分 8 幀,然後總共 1x8 幀,而第三個屬性 Frame 就表示當前顯示第幾幀畫面,可以設定為 0-7 共 8 幀畫面,操作瀏覽一下效果試試,你會發現 Frame 值從 0 到 1 然後慢慢設定到 7 的時候,天鵝圖片就產生了一種不連續的動畫效果,對,動畫原理就是這麼簡單!這個時候你會想:我如果在程式碼中獲取 Swan 的 Frame 屬性,然後把它的值每次往前加 1 不就可以生成動畫了嗎?的確可以!程式碼如下:

func _process(delta):
    if $Swan.frame == 7:
        $Swan.frame = 0
    else:
        $Swan.frame += 1

這和第二種方法的道理完全相同,也很值得一試!不過運行遊戲場景後,你會發現天鵝飛舞的動畫太快了!當然,這並不是什麼大問題,新增一個時間控制的變數,讓幀屬性慢點往前加 1 就可以了。不過這不是我們要討論的重點,我所要給大家介紹的是 Godot 中強大到能夠控制一切的關鍵幀動畫節點工具: AnimationPlayer !

對,在 Godot 中 AnimationPlayer 的確能操縱一切,簡單的如位置、旋轉、縮放的控制,還有其他節點的任意屬性值的控制,甚至連方法的呼叫都能在 AnimationPlayer 中進行動畫設定!同時,不僅強大,使用起來也非常簡單。如何實現天鵝動畫,這裡我做了一個簡單的操作示意圖,大家可以感受下 AnimationPlayer 節點的使用步驟:

godot_4_keyframes.gif

下面進入細節部分,首選我們需要在遊戲根節點下建立一個 AnimationPlayer 節點,這裡要強調一下:我們要對 Swan 節點進行動畫,所以他們需要放置在同一級別上!當然,AnimationPlayer 完全可以同時對其他節點比如*天空背景*或者*主角騎士*節點進行動畫,你可以嘗試一下。接下來,選擇 AnimationPlayer 節點,新建一個動畫軌道:

godot_4_create_animation.jpg

然後對我們新建的動畫軌道進行設定:自動播放、重複播放、動畫時長等,部分細節如下圖:

godot_4_keyframes_setting.jpg

OK ,大功告成,執行結果:

godot_4_result3.gif

最後,雖然動畫有了但是天鵝並不能移動位置,我們需要讓它隨著時間不斷移動位置就可以了。這裡介紹一個小技巧:我們可以直接在節點上新增指令碼! Godot 推薦我們這麼做,儘量讓每一個節點獨立,也就是和整個遊戲場景解耦,在大專案中讓合作開發更高效。

Talk is cheap, show me the code! 選擇 Swan 節點,點選新增指令碼,編寫程式碼:

extends Sprite

# 速度常量
const SPEED = 100
# 最左邊界和最右邊界
var minX = -100
var maxX = 800

func _process(delta):
    position.x -= SPEED * delta
    # 如果天鵝飛到左邊邊界,把它的x座標置為最右邊界
    if position.x < minX:
        position.x = maxX

最終效果:

godot_4_result4.gif

所有程式碼

我們的遊戲終於完成了,這裡我附上所有的程式碼,如果你已經閱讀過前面兩篇文章:Godot3遊戲引擎入門之三:移動我們的主角,那麼請跳過。

# 繼承於Node2D
extends Node2D

# 常量,表示速度(畫素)
const SPEED = 200
const SKY_SPEED = 50
# 定義一些變數,不需要型別
var maxX = 600 # 角色運動右邊界
var minX = 0 # 角色運動左邊界
# onready關鍵詞使變數在場景載入完後賦值,保證不為null
onready var knight = self.get_node("Knight")
# 在Godot中$符號可以直接加子節點名字獲得子節點物件,相當於get_node方法
onready var sky1 = $Sky1
onready var sky2 = $Sky2

# 節點進入場景開始時呼叫此方法,常用作初始化
func _ready():
    maxX -= knight.frames.get_frame('idle', 0).get_size().x / 2
    minX += knight.frames.get_frame('idle', 0).get_size().x / 2

# 每一幀執行此方法,delta表示每幀間隔
func _process(delta):
    # 移動背景天空位置,生成滾動動畫
    updateSkyAnimation(SKY_SPEED * delta)
    
    # Input表示裝置輸入,這裡D和右光標表示往右動
    if Input.is_key_pressed(KEY_D) or Input.is_key_pressed(KEY_RIGHT):
        moveKnightX(1, SPEED, delta)
        return
    elif Input.is_key_pressed(KEY_A) or Input.is_key_pressed(KEY_LEFT):
        moveKnightX(-1, SPEED, delta)
        return
    # 沒有鍵盤控制,讓騎士動畫為idle狀態
    if knight.animation != 'idle':
        knight.animation = 'idle'

func updateSkyAnimation(speed):
    # 移動,更新背景的位置
    sky1.position.x -= speed
    sky2.position.x -= speed
    # 如果滾動到最左邊,那麼移動到右邊來
    if sky1.position.x <= -1200:
        sky1.position.x += 2400
    elif sky2.position.x <= -1200:
        sky2.position.x += 2400
    
# 自定義函式,direciton表示方向,speed表示速度,delta是幀間隔
func moveKnightX(direction, speed, delta):
    # 有鍵盤控制,讓騎士動畫為run狀態,跑起來
    if knight.animation != 'run':
        knight.animation = 'run'
    
    if direction == 0:
        return
    # position屬性為節點當前置,Vector2向量簡單乘法
    knight.position += Vector2(speed, 0) * delta * direction
    # 越界檢測
    if knight.position.x > maxX:
        knight.position = Vector2(maxX, knight.position.y)
    elif knight.position.x < minX:
        knight.position = Vector2(minX, knight.position.y)
    
    knight.scale = Vector2(direction, 1)

三、小結(下)

三種方式已經全部講解完畢,這裡簡單總結一下 Godot 3 中動畫製作三種方式的優缺點:

節點名 AnimatedSprite Sprite + GDScript AnimationPlayer
優點 簡單明瞭,最適合製作主角多種狀態動畫 思路清晰,適合簡單的動畫,程式碼可控度高 最強大的動畫系統,幾乎能操縱一切元素來實現複雜的動畫
缺點 只能使用圖片,而且必須使用很多張圖片,資原始檔數量大增 對於複雜的屬性動畫很難使用程式碼達到理想效果 僅僅操作稍複雜點,節點的位置必須同級別

本篇上下節內容結束,還是那句話:原創不易啊,希望大家喜歡! :smile: