CharacterBody2D/3D ใน Godot 4 — คู่มือฉบับสมบูรณ์

1. บทนำ

Godot 4 ได้นำการเปลี่ยนแปลงครั้งใหญ่มาสู่การเคลื่อนที่ของตัวละคร โหนดเดิม KinematicBody2D และ KinematicBody3D ถูกเปลี่ยนชื่อเป็น CharacterBody2D และ CharacterBody3D และ API ของ move_and_slide() ก็ได้รับการออกแบบใหม่ทั้งหมด ไม่ว่าคุณจะกำลังย้ายมาจาก Godot 3 หรือเริ่มต้นใหม่ คู่มือนี้ครอบคลุมทุกอย่างที่คุณจำเป็นต้องรู้

CharacterBody2D และ CharacterBody3D เป็นฟิสิกส์บอดีที่ออกแบบมาสำหรับตัวละครที่ควบคุมด้วยโค้ด ต่างจาก RigidBody ตรงที่มันไม่ตอบสนองต่อแรงโดยอัตโนมัติ — คุณควบคุมการเคลื่อนที่ของมันทั้งหมดผ่านสคริปต์ ทำให้มันเหมาะอย่างยิ่งสำหรับตัวละครผู้เล่น NPC และทุกสิ่งที่ต้องการการเคลื่อนที่ที่แม่นยำและคาดเดาได้

2. สิ่งที่เปลี่ยนไปจาก Godot 3

ต่อไปนี้คือการเปลี่ยนแปลงที่สำคัญที่สุดเกี่ยวกับการเคลื่อนที่ของตัวละครระหว่าง Godot 3 และ Godot 4:

ประเด็นสำคัญ

ใน Godot 3 move_and_slide() จะคืนค่าความเร็วที่ได้ ส่วนใน Godot 4 มันคืนค่าเป็น bool (ว่ามีการชนเกิดขึ้นหรือไม่) และความเร็วจะถูกอัปเดตในที่เดิมบนพร็อพเพอร์ตี velocity

3. คอนโทรลเลอร์แพลตฟอร์มเมอร์ 2D พื้นฐาน

นี่คือคอนโทรลเลอร์แพลตฟอร์มเมอร์แบบเลื่อนด้านข้างมาตรฐาน ตัวละครสามารถเคลื่อนที่ซ้าย/ขวา และกระโดดเมื่ออยู่บนพื้น นี่คือเทมเพลตที่ Godot สร้างให้เมื่อคุณสร้างสคริปต์ CharacterBody2D ใหม่

GDScript — platformer_controller.gd
extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

func _physics_process(delta: float) -> void:
    # Apply gravity when not on floor
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Jump when on floor and jump pressed
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Horizontal movement
    var direction := Input.get_axis("ui_left", "ui_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    move_and_slide()

คำอธิบายทีละบรรทัด

เคล็ดลับ: โครงสร้างโหนดที่จำเป็น

CharacterBody2D ของคุณต้องมีโหนดลูก CollisionShape2D อย่างน้อยหนึ่งโหนดที่กำหนดรูปทรงไว้ (เช่น RectangleShape2D หรือ CapsuleShape2D) หากไม่มี move_and_slide() จะไม่ตรวจจับการชนใดๆ

4. คอนโทรลเลอร์ท็อปดาวน์ 2D พื้นฐาน

สำหรับเกมท็อปดาวน์ (RPG, ทวินสติกชูตเตอร์ ฯลฯ) คุณเคลื่อนที่ได้ทั้งสี่ทิศทางโดยไม่มีแรงโน้มถ่วง โค้ดจะเรียบง่ายกว่าแพลตฟอร์มเมอร์

GDScript — topdown_controller.gd
extends CharacterBody2D

const SPEED = 200.0

func _physics_process(delta: float) -> void:
    var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    velocity = input_direction * SPEED
    move_and_slide()

วิธีการทำงาน

การเพิ่มความเร่งและแรงเสียดทาน

เพื่อให้รู้สึกนุ่มนวลขึ้นด้วยการเร่งและการชะลอตัว:

GDScript — topdown_smooth.gd
extends CharacterBody2D

const SPEED = 200.0
const ACCELERATION = 1200.0
const FRICTION = 1000.0

func _physics_process(delta: float) -> void:
    var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

    if input_direction != Vector2.ZERO:
        velocity = velocity.move_toward(input_direction * SPEED, ACCELERATION * delta)
    else:
        velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)

    move_and_slide()

5. คอนโทรลเลอร์ 3D มุมมองบุคคลที่สาม

เวอร์ชัน 3D ใช้รูปแบบเดียวกัน ความแตกต่างหลักคือการทำงานกับ Vector3 และการใช้ transform.basis เพื่อแปลงอินพุต 2D ให้เป็นการเคลื่อนที่ในพื้นที่โลก 3D

GDScript — character_3d.gd
extends CharacterBody3D

const SPEED = 5.0
const JUMP_VELOCITY = 4.5

func _physics_process(delta: float) -> void:
    # Apply gravity
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Jump
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Get input and convert to 3D direction
    var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()

    if direction:
        velocity.x = direction.x * SPEED
        velocity.z = direction.z * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)
        velocity.z = move_toward(velocity.z, 0, SPEED)

    move_and_slide()

ความแตกต่างสำคัญจาก 2D

คำเตือน: get_gravity() ต้องการ Godot 4.4+

เมธอด get_gravity() ถูกเพิ่มเข้ามาใน Godot 4.4 สำหรับเวอร์ชันเก่ากว่านี้ ให้ใช้ Vector2(0, ProjectSettings.get_setting("physics/2d/default_gravity")) สำหรับ 2D หรือ Vector3(0, -ProjectSettings.get_setting("physics/3d/default_gravity"), 0) สำหรับ 3D

6. อ้างอิงพร็อพเพอร์ตีสำคัญ

ทั้ง CharacterBody2D และ CharacterBody3D ใช้พร็อพเพอร์ตีสำคัญเหล่านี้ร่วมกัน ปรับได้ในอินสเปกเตอร์หรือผ่านโค้ด

พร็อพเพอร์ตี ประเภท ค่าเริ่มต้น คำอธิบาย
velocity Vector2 / Vector3 Vector2.ZERO ความเร็วของตัวละคร กำหนดค่านี้ก่อนเรียก move_and_slide() หลังการเรียกจะถูกอัปเดตด้วยความเร็วที่ได้
floor_snap_length float 1.0 แทนที่ move_and_slide_with_snap() ระยะทางในการสแนปตัวละครติดกับพื้น ตั้งเป็น 0 เพื่อปิดใช้งาน มีประโยชน์สำหรับทางลาดและบันได
up_direction Vector2 / Vector3 Vector2.UP กำหนดว่าทิศทางใดคือ "ขึ้น" สิ่งนี้เป็นตัวกำหนดว่าอะไรนับเป็นพื้น ผนัง หรือเพดาน ค่าเริ่มต้นคือ (0, -1) ใน 2D และ (0, 1, 0) ใน 3D
floor_stop_on_slope bool true เมื่อเป็น true ตัวละครจะไม่ไถลลงทางลาดขณะยืนนิ่ง จำเป็นอย่างยิ่งสำหรับแพลตฟอร์มเมอร์
floor_max_angle float 0.785 (45°) มุมความชันสูงสุดที่เดินได้หน่วยเป็นเรเดียน พื้นผิวที่ชันกว่านี้จะถูกจัดการเป็นผนัง ใช้ deg_to_rad(60) เพื่อตั้งค่า 60 องศา
max_slides int 6 จำนวนรอบการวนตรวจการชนสูงสุดต่อการเรียก move_and_slide() หนึ่งครั้ง ค่าที่สูงกว่าจะแม่นยำกว่าแต่ช้ากว่า
wall_min_slide_angle float 0.262 (15°) มุมต่ำสุดสำหรับการไถลไปตามผนัง ป้องกันไม่ให้ตัวละครติดค้างอยู่กับผนังที่เกือบขนานกัน
platform_on_leave PlatformOnLeave ADD_VELOCITY พฤติกรรมเมื่อออกจากแพลตฟอร์มที่เคลื่อนที่ ADD_VELOCITY รักษาโมเมนตัมไว้ ADD_UPWARD_VELOCITY เพิ่มเฉพาะองค์ประกอบทิศขึ้น DO_NOTHING ละเว้นความเร็วของแพลตฟอร์ม
slide_on_ceiling bool true เมื่อเป็น true จะอนุญาตให้ไถลบนเพดาน เมื่อเป็น false จะหยุดความเร็วแนวนอนเมื่อชนเพดาน

7. การตรวจจับการชนหลัง move_and_slide()

หลังจากเรียก move_and_slide() คุณสามารถตรวจสอบการชนที่เกิดขึ้นได้ สิ่งนี้มีประโยชน์ในการตอบสนองต่อประเภทคอลไลเดอร์เฉพาะ การเล่นเสียงเอฟเฟกต์เมื่อลงพื้น หรือการสร้างกลไกการกระโดดผนัง

GDScript — collision_detection.gd
func _physics_process(delta: float) -> void:
    # ... set velocity here ...
    move_and_slide()

    # Check all collisions from this frame
    for i in get_slide_collision_count():
        var collision := get_slide_collision(i)
        var collider := collision.get_collider()
        print("Collided with: ", collider.name)
        print("Normal: ", collision.get_normal())
        print("Position: ", collision.get_position())

    # Practical example: bounce off enemies
    for i in get_slide_collision_count():
        var collision := get_slide_collision(i)
        if collision.get_collider().is_in_group("enemies"):
            velocity = collision.get_normal() * 300
            break

เมธอด KinematicCollision ที่มีประโยชน์

8. ชีตสรุปการย้ายโค้ด

อ้างอิงฉบับย่อสำหรับการแปลงโค้ด Godot 3 เป็น Godot 4:

Godot 3 Godot 4
KinematicBody2D CharacterBody2D
KinematicBody3D CharacterBody3D
velocity = move_and_slide(velocity, Vector2.UP) velocity = ...
move_and_slide()
move_and_slide_with_snap(vel, snap, up) floor_snap_length = 4.0
move_and_slide()
var vel = move_and_slide(...)
คืนค่า velocity
move_and_slide()
พร็อพเพอร์ตี velocity ถูกอัปเดตในที่เดิม
var gravity = ProjectSettings.get("physics/2d/default_gravity") get_gravity() (4.4+)
move_and_slide(..., up_direction, ...) up_direction = Vector2.UP (กำหนดเป็นพร็อพเพอร์ตี)
move_and_slide(..., stop_on_slope, ...) floor_stop_on_slope = true (กำหนดเป็นพร็อพเพอร์ตี)
ตัวแปลงอัตโนมัติของ Godot

เมื่อเปิดโปรเจกต์ Godot 3 ใน Godot 4 เอนจินจะเสนอให้แปลงโปรเจกต์ของคุณ มันจะเปลี่ยนชื่อโหนดและพยายามอัปเดตสคริปต์ แต่ไม่ได้แปลงการเรียก move_and_slide() ให้ถูกต้องเสมอไป คุณอาจต้องแก้ไขโค้ดการเคลื่อนที่ด้วยตนเอง

9. ข้อผิดพลาดที่พบบ่อย

ข้อผิดพลาดที่ 1: ส่งอาร์กิวเมนต์เข้า move_and_slide()

ผิด
# ERROR: move_and_slide() takes no arguments in Godot 4
velocity = move_and_slide(velocity, Vector2.UP)
ถูก
# Set velocity, then call move_and_slide() with no arguments
velocity.x = direction * SPEED
move_and_slide()

ข้อผิดพลาดที่ 2: ลืมกำหนด velocity ก่อน move_and_slide()

ผิด — velocity ไม่เคยถูกกำหนด จึงไม่มีอะไรเคลื่อนที่
func _physics_process(delta: float) -> void:
    move_and_slide()  # velocity is Vector2.ZERO — nothing happens

ข้อผิดพลาดที่ 3: ใช้ _process() แทน _physics_process()

move_and_slide() ต้องถูกเรียกใน _physics_process() ซึ่งทำงานที่อัตราคงที่ (ค่าเริ่มต้น 60 Hz) การใช้ _process() จะผูกฟิสิกส์เข้ากับเฟรมเรตของการเรนเดอร์ ทำให้พฤติกรรมไม่สม่ำเสมอ

ข้อผิดพลาดที่ 4: ไม่ตั้งค่า CollisionShape

CharacterBody2D/CharacterBody3D ที่ไม่มีโหนดลูก CollisionShape จะทะลุผ่านทุกสิ่ง Godot จะแสดงไอคอนเตือนในเอดิเตอร์หากขาดรูปทรงการชน

ข้อผิดพลาดที่ 5: เขียนทับ velocity.y ด้วยแรงโน้มถ่วงทุกเฟรม

ผิด — รีเซ็ต velocity.y ทำให้การกระโดดไม่เคยทำงาน
# This overwrites any jump velocity!
velocity.y = gravity * delta  # should be +=, not =
ถูก — สะสมแรงโน้มถ่วง
# Gravity accumulates over time
velocity += get_gravity() * delta

ข้อผิดพลาดที่ 6: ใช้แรงโน้มถ่วงขณะอยู่บนพื้น

ควรครอบแรงโน้มถ่วงด้วย if not is_on_floor() เสมอ หากไม่มีการตรวจสอบนี้ แรงโน้มถ่วงจะสะสมต่อเนื่องขณะอยู่บนพื้น เมื่อตัวละครเดินตกขอบ มันจะดิ่งลงด้วยความเร็วสูงผิดปกติแทนที่จะตกลงอย่างเป็นธรรมชาติ

10. ตั้งค่าคอนโทรลเลอร์ตัวละครด้วย AI

อยากให้ AI ตั้งค่าคอนโทรลเลอร์ตัวละครของคุณไหม?

Godot MCP Pro ช่วยให้ AI ผู้ช่วยสามารถสร้างโหนด CharacterBody กำหนดค่าพร็อพเพอร์ตีฟิสิกส์ ตั้งค่ารูปทรงการชน เขียนสคริปต์การเคลื่อนที่ เปิดเกมของคุณ และทดสอบการเคลื่อนที่ — ทั้งหมดจากพรอมต์ภาษาธรรมชาติ

add_node setup_physics_body setup_collision set_physics_layers create_script simulate_key play_scene capture_frames
รับ Godot MCP Pro — $15