1. Pengantar
Godot 4 memperkenalkan perubahan besar pada pergerakan karakter. Node lama KinematicBody2D dan KinematicBody3D diganti namanya menjadi CharacterBody2D dan CharacterBody3D, dan API move_and_slide() dirancang ulang sepenuhnya. Baik kamu bermigrasi dari Godot 3 maupun memulai dari awal — panduan ini membahas semua yang perlu kamu ketahui.
CharacterBody2D dan CharacterBody3D adalah physics body yang dirancang untuk karakter yang dikendalikan lewat kode. Berbeda dengan RigidBody, keduanya tidak bereaksi terhadap gaya secara otomatis — kamu mengendalikan pergerakannya sepenuhnya lewat script. Ini menjadikannya ideal untuk karakter pemain, NPC, dan apa pun yang membutuhkan gerakan yang presisi dan deterministik.
2. Apa yang Berubah dari Godot 3
Berikut adalah perubahan terpenting pada pergerakan karakter antara Godot 3 dan Godot 4:
-
KinematicBody2Dsekarang menjadiCharacterBody2D -
KinematicBody3Dsekarang menjadiCharacterBody3D -
velocitykini menjadi properti bawaan — kamu tidak lagi meneruskannya kemove_and_slide() -
move_and_slide()tidak menerima argumen lagi — ia membaca langsung dari propertivelocity -
move_and_slide_with_snap()telah dihapus — gunakan propertifloor_snap_lengthsebagai gantinya -
is_on_floor(),is_on_wall(),is_on_ceiling()tetap berfungsi dengan cara yang sama -
get_gravity()ditambahkan di Godot 4.4 untuk membaca gravitasi default proyek sebagai sebuah Vector — sangat praktis
Di Godot 3, move_and_slide() mengembalikan kecepatan hasilnya. Di Godot 4, ia mengembalikan sebuah bool (apakah terjadi tabrakan), dan kecepatan diperbarui langsung pada properti velocity.
3. Controller Platformer 2D Dasar
Ini adalah controller platformer side-scrolling standar. Karakter dapat bergerak ke kiri/kanan dan melompat saat berada di tanah. Ini adalah template yang dihasilkan Godot ketika kamu membuat script CharacterBody2D baru.
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()
Penjelasan Baris demi Baris
-
extends CharacterBody2D— Script mewarisi dari CharacterBody2D, memberi kita akses kevelocity,move_and_slide(),is_on_floor(), dsb. -
SPEED = 300.0— Kecepatan gerak horizontal dalam piksel per detik. -
JUMP_VELOCITY = -400.0— Negatif karena sumbu Y menunjuk ke bawah di 2D. Nilai negatif menggerakkan karakter ke atas. -
get_gravity() * delta— Menerapkan gravitasi proyek di setiap frame.get_gravity()mengembalikan sebuahVector2yang menunjuk ke bawah (mis.Vector2(0, 980)). Mengalikannya dengandeltamembuatnya independen terhadap framerate. -
Input.get_axis("ui_left", "ui_right")— Mengembalikan sebuah float dari -1.0 hingga 1.0 tergantung tombol arah mana yang ditekan. Mendukung input analog. -
move_toward(velocity.x, 0, SPEED)— Memperlambat dengan halus hingga nol saat tidak ada input. Argumen ketiga adalah perubahan maksimum per pemanggilan. -
move_and_slide()— Menggerakkan body menggunakanvelocitysaat ini, menangani tabrakan, meluncur di sepanjang permukaan, dan memperbaruivelocitysecara otomatis.
CharacterBody2D-mu membutuhkan setidaknya satu node anak CollisionShape2D dengan shape yang ditetapkan (mis. RectangleShape2D atau CapsuleShape2D). Tanpa itu, move_and_slide() tidak akan mendeteksi tabrakan apa pun.
4. Controller Top-Down 2D Dasar
Untuk game top-down (RPG, twin-stick shooter, dsb.), kamu bergerak ke keempat arah tanpa gravitasi. Kodenya lebih sederhana daripada platformer.
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()
Cara Kerjanya
-
Input.get_vector()mengembalikan sebuahVector2ternormalisasi dari empat aksi input. Ini menangani gerakan diagonal dengan benar — panjang vektor selalu 1.0 atau 0.0, sehingga gerakan diagonal tidak lebih cepat daripada gerakan searah sumbu. -
Tidak ada gravitasi yang diterapkan karena ini adalah tampilan top-down. Karakter berhenti seketika saat tidak ada input, karena kita menyetel
velocitysecara langsung (tanpa inersia).
Menambahkan Akselerasi dan Gesekan
Untuk nuansa yang lebih halus dengan akselerasi dan perlambatan:
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. Controller Third-Person 3D
Versi 3D mengikuti pola yang sama. Perbedaan utamanya adalah bekerja dengan Vector3 dan menggunakan transform.basis untuk mengubah input 2D menjadi gerakan di ruang dunia 3D.
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()
Perbedaan Utama dari 2D
-
Satuan: Di 3D, 1 satuan = 1 meter (konvensi). Jadi
SPEED = 5.0berarti 5 meter per detik — angka yang jauh lebih kecil dibanding nilai piksel 2D. -
Kecepatan lompat bernilai positif: Di 3D, sumbu Y menunjuk ke atas (berbeda dengan 2D), maka
JUMP_VELOCITY = 4.5bernilai positif. -
Transformasi arah:
transform.basis * Vector3(input_dir.x, 0, input_dir.y)mengubah input 2D menjadi arah 3D relatif terhadap arah hadap karakter. Nilai Y dari input dipetakan ke sumbu Z (depan/belakang di 3D). -
Hanya X dan Z yang dikendalikan: Kita menyetel
velocity.xdanvelocity.zsecara terpisah, menyisakanvelocity.yuntuk gravitasi dan lompatan.
Metode get_gravity() ditambahkan di Godot 4.4. Untuk versi yang lebih lama, gunakan Vector2(0, ProjectSettings.get_setting("physics/2d/default_gravity")) untuk 2D atau Vector3(0, -ProjectSettings.get_setting("physics/3d/default_gravity"), 0) untuk 3D.
6. Referensi Properti Utama
Baik CharacterBody2D maupun CharacterBody3D berbagi properti-properti penting ini. Sesuaikan di Inspector atau lewat kode.
| Properti | Tipe | Default | Deskripsi |
|---|---|---|---|
velocity |
Vector2 / Vector3 | Vector2.ZERO |
Kecepatan karakter. Setel ini sebelum memanggil move_and_slide(). Setelah pemanggilan, ia diperbarui dengan kecepatan hasilnya.
|
floor_snap_length |
float | 1.0 |
Menggantikan move_and_slide_with_snap(). Jarak untuk men-snap karakter ke lantai. Setel ke 0 untuk menonaktifkannya. Berguna untuk kemiringan dan tangga.
|
up_direction |
Vector2 / Vector3 | Vector2.UP |
Menentukan arah mana yang dianggap "atas". Ini menentukan apa yang dihitung sebagai lantai, dinding, atau langit-langit. Default-nya adalah (0, -1) di 2D, (0, 1, 0) di 3D.
|
floor_stop_on_slope |
bool | true |
Bila true, karakter tidak akan meluncur turun di kemiringan saat diam. Penting untuk platformer. |
floor_max_angle |
float | 0.785 (45°) |
Sudut kemiringan maksimum yang bisa dilalui, dalam radian. Permukaan yang lebih curam dari ini diperlakukan sebagai dinding. Gunakan deg_to_rad(60) untuk menyetel 60 derajat.
|
max_slides |
int | 6 |
Jumlah maksimum iterasi tabrakan per pemanggilan move_and_slide(). Nilai lebih tinggi lebih akurat tetapi lebih lambat.
|
wall_min_slide_angle |
float | 0.262 (15°) |
Sudut minimum untuk meluncur di dinding. Mencegah karakter tersangkut pada dinding yang nyaris sejajar. |
platform_on_leave |
PlatformOnLeave | ADD_VELOCITY |
Perilaku saat meninggalkan platform yang bergerak. ADD_VELOCITY mempertahankan momentum, ADD_UPWARD_VELOCITY hanya menambahkan komponen ke atas, DO_NOTHING mengabaikan kecepatan platform.
|
slide_on_ceiling |
bool | true |
Bila true, meluncur di langit-langit diizinkan. Bila false, kecepatan horizontal dihentikan saat menyentuh langit-langit. |
7. Deteksi Tabrakan setelah move_and_slide()
Setelah memanggil move_and_slide(), kamu dapat memeriksa tabrakan yang terjadi. Ini berguna untuk bereaksi terhadap tipe collider tertentu, memainkan efek suara saat mendarat, atau mengimplementasikan mekanik wall-jump.
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
Metode KinematicCollision yang Berguna
get_collider()— Objek yang tertabrak.get_normal()— Normal permukaan tabrakan. Menunjuk menjauhi permukaan.get_position()— Titik di ruang dunia tempat tabrakan terjadi.get_travel()— Seberapa jauh body bergerak sebelum bertabrakan.get_remainder()— Sisa gerakan yang tidak diterapkan.get_collider_velocity()— Kecepatan collider (berguna untuk platform yang bergerak).
8. Contekan Migrasi
Referensi cepat untuk menulis ulang kode Godot 3 ke Godot 4:
| Godot 3 | Godot 4 |
|---|---|
KinematicBody2D |
CharacterBody2D |
KinematicBody3D |
CharacterBody3D |
velocity = move_and_slide(velocity, Vector2.UP) |
velocity = ... |
move_and_slide_with_snap(vel, snap, up) |
floor_snap_length = 4.0 |
var vel = move_and_slide(...)mengembalikan velocity |
move_and_slide()properti velocity diperbarui langsung |
var gravity = ProjectSettings.get("physics/2d/default_gravity") |
get_gravity() (4.4+) |
move_and_slide(..., up_direction, ...) |
up_direction = Vector2.UP (disetel sebagai properti) |
move_and_slide(..., stop_on_slope, ...) |
floor_stop_on_slope = true (disetel sebagai properti) |
Ketika kamu membuka proyek Godot 3 di Godot 4, engine menawarkan untuk mengonversi proyekmu. Ia mengganti nama node dan mencoba memperbarui script, tetapi tidak selalu menangani pemanggilan move_and_slide() dengan benar. Kemungkinan besar kamu perlu memperbaiki kode pergerakanmu secara manual.
9. Kesalahan Umum
Kesalahan 1: Meneruskan argumen ke 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()
Kesalahan 2: Lupa menyetel velocity sebelum move_and_slide()
func _physics_process(delta: float) -> void:
move_and_slide() # velocity is Vector2.ZERO — nothing happens
Kesalahan 3: Menggunakan _process() alih-alih _physics_process()
move_and_slide() harus dipanggil di _physics_process(), yang berjalan pada laju tetap (60 Hz secara default). Menggunakan _process() mengaitkan fisika ke framerate render dan menyebabkan perilaku yang tidak konsisten.
Kesalahan 4: Tidak menyiapkan CollisionShape
Sebuah CharacterBody2D/CharacterBody3D tanpa anak CollisionShape akan menembus segalanya. Godot menampilkan ikon peringatan di editor bila collision shape hilang.
Kesalahan 5: Menimpa velocity.y dengan gravitasi di setiap frame
# This overwrites any jump velocity!
velocity.y = gravity * delta # should be +=, not =
# Gravity accumulates over time
velocity += get_gravity() * delta
Kesalahan 6: Menerapkan gravitasi saat berada di tanah
Selalu bungkus gravitasi dengan if not is_on_floor(). Tanpa pemeriksaan ini, gravitasi terus terakumulasi selama berada di tanah. Ketika karakter berjalan turun dari tepi, ia akan jatuh dengan kecepatan ekstrem, alih-alih jatuh secara alami.