Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

運動學角色(2D)

前言

是的,名字聽起來很奇怪。“運動學角色”是什麼東西?使用這個名稱的原因是物理引擎問世之處,它們被稱為“動力學(Dynamics)”引擎(因為它們主要處理碰撞回應)。人們做了許多嘗試,想使用動力學引擎建立角色控制器,但它並不像看起來那麼容易。Godot 擁有您能找到的最好的動力學角色控制器(可以在 2d/platformer 演示中查看),但使用它需要相當高水平的技能和對物理引擎的理解(或者對試驗和試錯有足夠的耐心)。

像 Havok 這樣的物理引擎似乎認為力學角色控制器是最好的選擇,而其他物理引擎(PhysX)則更願意推廣運動學(Kinematic)的角色控制器。

那麼區別是什麼呢?:

  • **動力學角色控制器**使用的是一個具有無限慣性張量的剛體。這是一個不能旋轉的剛體. 物理引擎總是讓物體移動和碰撞, 然後一併解決它們的碰撞. 這使得動態角色控制器能夠與其他物理物件無縫互動, 就像在平臺遊戲演示中看到的那樣. 然而, 這些互動並不總是可預測的. 碰撞可能需要多於一影格的時間來解決, 所以幾個碰撞可能看起來會有很小的位移. 這些問題是可以解決的, 但需要一定的技巧.

  • **運動學角色控制器**總是假設以非碰撞狀態開始,並將總是移動到非碰撞狀態。如果它開始時處於碰撞狀態, 將像剛體一樣嘗試釋放自己, 但這是特例, 而不是規則. 這使得它們的控制和運動更可預測, 更容易程式設計. 然而, 有一個缺點, 它們不能直接與其他物理物件互動, 除非在程式碼中手動完成.

這個簡短的教學將重點介紹運動學角色控制器。基本上,傳統處理衝突的方法(它並不一定在底層更簡單,但隱蔽性很好,並且呈現為一個簡潔漂亮的 API)。

物理過程處理

為了管理運動物體或角色的邏輯, 總是建議使用物理過程處理, 因為它在物理步驟之前被呼叫並且它的執行與物理伺服器同步, 它也被以被每秒相同的次數呼叫. 這使得物理和運動計算以比使用常規過程處理更可預測的方式工作, 如果畫面播放速率太高或太低, 則可能具有尖峰或丟失精度.

extends CharacterBody2D

func _physics_process(delta):
    pass

場景設定

要進行測試, 這裡有場景(來自tilemap教學): kbscene.zip. 我們將為角色創造一個新場景. 使用機器人精靈並建立一個這樣的場景:

../../_images/kbscene.webp

您會注意到, 在 "二維碰撞形狀 "(CollisionShape2D)節點旁邊有一個警告圖示;那是因為我們還沒有定義它的形狀. 在" 二維碰撞形狀"(CollisionShape2D)的形狀屬性中建立一個新的二維圓形形狀(CircleShape2D). 點擊 <二維圓形形狀>(CircleShape2D)進入選項, 將半徑設定為30:

../../_images/kbradius.webp

注意: 正如之前在物理教學中提到的, 物理引擎無法處理大多數型別形狀的縮放, 只有碰撞多邊形, 平面和段才有效, 所以, 總是改變形狀的半徑等參數, 而不是縮放它. 對於運動體或剛性體或靜態體本身也是如此, 因為它們的比例會影響形狀的比例.

現在, 為這個角色建立一個腳本, 上面作為例子的那個腳本可以作為基礎.

最後, 產生實體tilemap中的角色場景, 並使地圖場景成為主場景, 因此在按下播放時運作.

../../_images/kbinstance.webp

移動動態角色

回到角色場景, 打開腳本, 魔法開始了!動態物體預設不會做任何事情, 但它有一個有用的函式, 叫做 KinematicBody2D.move_and_collide() . 該函式以一個 Vector2 作為參數, 並嘗試將該運動應用到動態物體. 如果發生了碰撞, 它就在碰撞的瞬間停止.

所以, 讓我們向下移動我們的精靈, 直到它撞上地板:

extends CharacterBody2D

func _physics_process(delta):
    move_and_collide(Vector2(0, 1)) # Move down 1 pixel per physics frame

結果是角色會移動, 但在擊中地板時會停止. 很酷, 對吧?

下一步將加入重力, 這樣一來, 它的行為就更像一個常規的遊戲角色:

extends CharacterBody2D

const GRAVITY = 200.0

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    var motion = velocity * delta
    move_and_collide(motion)

現在人物平滑下落. 我們讓它向兩邊行走, 在按下方向鍵時向左或向右. 記住, 正在使用的值(至少對於速度)單位是像素/秒.

通過向左和向右按下可以增加簡單的步行支援:

extends CharacterBody2D

const GRAVITY = 200.0
const WALK_SPEED = 200

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    if Input.is_action_pressed("ui_left"):
        velocity.x = -WALK_SPEED
    elif Input.is_action_pressed("ui_right"):
        velocity.x =  WALK_SPEED
    else:
        velocity.x = 0

    # "move_and_slide" already takes delta time into account.
    move_and_slide()

試一試.

這是平臺遊戲的良好起點. 可以在隨引擎分發的演示zip中找到更完整的演示, 或者在https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character中找到.