godot-characterbody-2d
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCharacterBody2D Implementation
CharacterBody2D 实现
Expert guidance for player-controlled 2D movement using Godot's physics system.
基于Godot物理系统的玩家可控2D移动专家指南。
NEVER Do
绝对不要做的事
- NEVER multiply velocity by delta when using —
move_and_slide()already accounts for delta time. Multiplying causes slow, frame-dependent movement.move_and_slide() - NEVER forget to check before jump — Allows mid-air jumps without double-jump mechanic.
is_on_floor() - NEVER use without friction — Character slides infinitely without friction in else branch. Use
velocity.x = direction * SPEED.move_toward(velocity.x, 0, FRICTION * delta) - NEVER set to exact value when falling — Overwrites gravity accumulation. Use
velocity.yinstead ofvelocity.y += gravity * delta.velocity.y = gravity - NEVER use floor_snap_length > 16px — Large snap values cause "sticking" to slopes and walls.
- 使用时,切勿将velocity乘以delta —
move_and_slide()已经考虑了delta时间,相乘会导致移动缓慢且依赖帧率。move_and_slide() - 跳跃前切勿忘记检查— 会导致没有二段跳机制却能在空中跳跃。
is_on_floor() - 切勿在无摩擦的情况下使用— 角色会在else分支中无限滑动。请使用
velocity.x = direction * SPEED。move_toward(velocity.x, 0, FRICTION * delta) - 下落时切勿将设为固定值 — 这会覆盖重力的累积效果。请使用
velocity.y而非velocity.y += gravity * delta。velocity.y = gravity - 切勿将floor_snap_length设为大于16px的值 — 较大的吸附值会导致角色“粘”在斜坡和墙上。
Available Scripts
可用脚本
MANDATORY: Read the appropriate script before implementing the corresponding pattern.
强制要求:在实现对应模式前,请先阅读相应的脚本。
expert_physics_2d.gd
expert_physics_2d.gd
Complete platformer movement with coyote time, jump buffering, smooth acceleration/friction, and sub-pixel stabilization. Uses move_toward for precise control.
完整的平台跳跃移动实现,包含coyote time、跳跃缓冲、平滑加速/减速以及亚像素稳定。使用move_toward实现精准控制。
dash_controller.gd
dash_controller.gd
Frame-perfect dash with I-frames, cooldown, and momentum preservation.
帧完美的冲刺功能,包含无敌帧、冷却时间和动量保留。
wall_jump_controller.gd
wall_jump_controller.gd
Wall slide, cling, and directional wall jump with auto-correction.
Do First: Read expert_physics_2d.gd for platformer foundation before adding dash/wall-jump.
墙面滑动、吸附和可定向的墙跳功能,带自动修正。
优先操作:在添加冲刺/墙跳功能前,请先阅读expert_physics_2d.gd以掌握平台跳跃基础。
When to Use CharacterBody2D
何时使用CharacterBody2D
Use CharacterBody2D For:
- Player characters (platformer, top-down, side-scroller)
- NPCs with custom movement logic
- Enemies with non-physics-based movement
Use RigidBody2D For:
- Physics-driven objects (rolling boulders, vehicles)
- Objects affected by forces and impulses
适合使用CharacterBody2D的场景:
- 玩家角色(平台跳跃、俯视角、横版卷轴)
- 带有自定义移动逻辑的NPC
- 非物理驱动的敌人
适合使用RigidBody2D的场景:
- 物理驱动的物体(滚动的巨石、载具)
- 受外力和冲量影响的物体
Platformer Movement Pattern
平台跳跃移动模式
Basic Platformer Controller
基础平台跳跃控制器
gdscript
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0gdscript
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0Get the gravity from the project settings
从项目设置中获取重力值
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
# Apply gravity
if not is_on_floor():
velocity.y += gravity * delta
# Handle jump
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get input direction
var direction := Input.get_axis("move_left", "move_right")
# Apply movement
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()undefinedvar gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
# 应用重力
if not is_on_floor():
velocity.y += gravity * delta
# 处理跳跃
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# 获取输入方向
var direction := Input.get_axis("move_left", "move_right")
# 应用移动
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()undefinedAdvanced Platformer with Coyote Time & Jump Buffer
包含Coyote Time与跳跃缓冲的进阶平台跳跃
gdscript
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
const ACCELERATION := 1500.0
const FRICTION := 1200.0
const AIR_RESISTANCE := 200.0gdscript
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
const ACCELERATION := 1500.0
const FRICTION := 1200.0
const AIR_RESISTANCE := 200.0Coyote time: grace period after leaving platform
Coyote time:离开平台后的 grace period
const COYOTE_TIME := 0.1
var coyote_timer := 0.0
const COYOTE_TIME := 0.1
var coyote_timer := 0.0
Jump buffering: remember jump input slightly before landing
跳跃缓冲:在落地前提前记录跳跃输入
const JUMP_BUFFER_TIME := 0.1
var jump_buffer_timer := 0.0
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
# Gravity
if not is_on_floor():
velocity.y += gravity * delta
coyote_timer -= delta
else:
coyote_timer = COYOTE_TIME
# Jump buffering
if Input.is_action_just_pressed("jump"):
jump_buffer_timer = JUMP_BUFFER_TIME
else:
jump_buffer_timer -= delta
# Jump (with coyote time and buffer)
if jump_buffer_timer > 0 and coyote_timer > 0:
velocity.y = JUMP_VELOCITY
jump_buffer_timer = 0
coyote_timer = 0
# Variable jump height
if Input.is_action_just_released("jump") and velocity.y < 0:
velocity.y *= 0.5
# Movement with acceleration/friction
var direction := Input.get_axis("move_left", "move_right")
if direction:
velocity.x = move_toward(velocity.x, direction * SPEED, ACCELERATION * delta)
else:
var friction_value := FRICTION if is_on_floor() else AIR_RESISTANCE
velocity.x = move_toward(velocity.x, 0, friction_value * delta)
move_and_slide()undefinedconst JUMP_BUFFER_TIME := 0.1
var jump_buffer_timer := 0.0
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
# 重力
if not is_on_floor():
velocity.y += gravity * delta
coyote_timer -= delta
else:
coyote_timer = COYOTE_TIME
# 跳跃缓冲
if Input.is_action_just_pressed("jump"):
jump_buffer_timer = JUMP_BUFFER_TIME
else:
jump_buffer_timer -= delta
# 跳跃(支持coyote time和缓冲)
if jump_buffer_timer > 0 and coyote_timer > 0:
velocity.y = JUMP_VELOCITY
jump_buffer_timer = 0
coyote_timer = 0
# 可变跳跃高度
if Input.is_action_just_released("jump") and velocity.y < 0:
velocity.y *= 0.5
# 带加速/减速的移动
var direction := Input.get_axis("move_left", "move_right")
if direction:
velocity.x = move_toward(velocity.x, direction * SPEED, ACCELERATION * delta)
else:
var friction_value := FRICTION if is_on_floor() else AIR_RESISTANCE
velocity.x = move_toward(velocity.x, 0, friction_value * delta)
move_and_slide()undefinedTop-Down Movement Pattern
俯视角移动模式
8-Directional Top-Down
八方向俯视角移动
gdscript
extends CharacterBody2D
const SPEED := 200.0
const ACCELERATION := 1500.0
const FRICTION := 1000.0
func _physics_process(delta: float) -> void:
# Get input direction (normalized for diagonal movement)
var input_vector := Input.get_vector(
"move_left", "move_right",
"move_up", "move_down"
)
if input_vector != Vector2.ZERO:
# Accelerate toward target velocity
velocity = velocity.move_toward(
input_vector * SPEED,
ACCELERATION * delta
)
else:
# Apply friction
velocity = velocity.move_toward(
Vector2.ZERO,
FRICTION * delta
)
move_and_slide()gdscript
extends CharacterBody2D
const SPEED := 200.0
const ACCELERATION := 1500.0
const FRICTION := 1000.0
func _physics_process(delta: float) -> void:
# 获取输入方向(归一化以处理斜向移动)
var input_vector := Input.get_vector(
"move_left", "move_right",
"move_up", "move_down"
)
if input_vector != Vector2.ZERO:
# 向目标速度加速
velocity = velocity.move_toward(
input_vector * SPEED,
ACCELERATION * delta
)
else:
# 应用减速
velocity = velocity.move_toward(
Vector2.ZERO,
FRICTION * delta
)
move_and_slide()Top-Down with Rotation (Tank Controls)
带旋转的俯视角移动(坦克式操控)
gdscript
extends CharacterBody2D
const SPEED := 200.0
const ROTATION_SPEED := 3.0
func _physics_process(delta: float) -> void:
# Rotation
var rotate_direction := Input.get_axis("rotate_left", "rotate_right")
rotation += rotate_direction * ROTATION_SPEED * delta
# Forward/backward movement
var move_direction := Input.get_axis("move_backward", "move_forward")
velocity = transform.x * move_direction * SPEED
move_and_slide()gdscript
extends CharacterBody2D
const SPEED := 200.0
const ROTATION_SPEED := 3.0
func _physics_process(delta: float) -> void:
# 旋转控制
var rotate_direction := Input.get_axis("rotate_left", "rotate_right")
rotation += rotate_direction * ROTATION_SPEED * delta
# 前后移动
var move_direction := Input.get_axis("move_backward", "move_forward")
velocity = transform.x * move_direction * SPEED
move_and_slide()Collision Handling
碰撞处理
Detecting Floor/Walls/Ceiling
检测地面/墙面/天花板
gdscript
func _physics_process(delta: float) -> void:
move_and_slide()
if is_on_floor():
print("Standing on ground")
if is_on_wall():
print("Touching wall")
if is_on_ceiling():
print("Hitting ceiling")gdscript
func _physics_process(delta: float) -> void:
move_and_slide()
if is_on_floor():
print("站在地面上")
if is_on_wall():
print("接触墙面")
if is_on_ceiling():
print"撞到天花板")Get Collision Information
获取碰撞信息
gdscript
func _physics_process(delta: float) -> void:
move_and_slide()
# Process each collision
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
print("Collided with: ", collision.get_collider().name)
print("Collision normal: ", collision.get_normal())
# Example: bounce off walls
if collision.get_collider().is_in_group("bouncy"):
velocity = velocity.bounce(collision.get_normal())gdscript
func _physics_process(delta: float) -> void:
move_and_slide()
# 处理每次碰撞
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
print("碰撞对象: ", collision.get_collider().name)
print("碰撞法线: ", collision.get_normal())
# 示例:从弹性物体反弹
if collision.get_collider().is_in_group("bouncy"):
velocity = velocity.bounce(collision.get_normal())One-Way Platforms
单向平台
gdscript
extends CharacterBody2D
func _physics_process(delta: float) -> void:
# Allow falling through platforms by pressing down
if Input.is_action_pressed("move_down") and is_on_floor():
position.y += 1 # Move slightly down to pass through
velocity.y += gravity * delta
move_and_slide()gdscript
extends CharacterBody2D
func _physics_process(delta: float) -> void:
# 按下向下键时允许穿过平台
if Input.is_action_pressed("move_down") and is_on_floor():
position.y += 1 # 稍微向下移动以穿过平台
velocity.y += gravity * delta
move_and_slide()Movement States with State Machine
基于状态机的移动状态管理
gdscript
extends CharacterBody2D
enum State { IDLE, RUNNING, JUMPING, FALLING, DASHING }
var current_state := State.IDLE
var dash_velocity := Vector2.ZERO
const DASH_SPEED := 600.0
const DASH_DURATION := 0.2
var dash_timer := 0.0
func _physics_process(delta: float) -> void:
match current_state:
State.IDLE:
_state_idle(delta)
State.RUNNING:
_state_running(delta)
State.JUMPING:
_state_jumping(delta)
State.FALLING:
_state_falling(delta)
State.DASHING:
_state_dashing(delta)
func _state_idle(delta: float) -> void:
velocity.x = move_toward(velocity.x, 0, FRICTION * delta)
if Input.is_action_pressed("move_left") or Input.is_action_pressed("move_right"):
current_state = State.RUNNING
elif Input.is_action_just_pressed("jump"):
current_state = State.JUMPING
move_and_slide()
func _state_dashing(delta: float) -> void:
dash_timer -= delta
velocity = dash_velocity
if dash_timer <= 0:
current_state = State.IDLE
move_and_slide()gdscript
extends CharacterBody2D
enum State { IDLE, RUNNING, JUMPING, FALLING, DASHING }
var current_state := State.IDLE
var dash_velocity := Vector2.ZERO
const DASH_SPEED := 600.0
const DASH_DURATION := 0.2
var dash_timer := 0.0
func _physics_process(delta: float) -> void:
match current_state:
State.IDLE:
_state_idle(delta)
State.RUNNING:
_state_running(delta)
State.JUMPING:
_state_jumping(delta)
State.FALLING:
_state_falling(delta)
State.DASHING:
_state_dashing(delta)
func _state_idle(delta: float) -> void:
velocity.x = move_toward(velocity.x, 0, FRICTION * delta)
if Input.is_action_pressed("move_left") or Input.is_action_pressed("move_right"):
current_state = State.RUNNING
elif Input.is_action_just_pressed("jump"):
current_state = State.JUMPING
move_and_slide()
func _state_dashing(delta: float) -> void:
dash_timer -= delta
velocity = dash_velocity
if dash_timer <= 0:
current_state = State.IDLE
move_and_slide()Best Practices
最佳实践
1. Use Constants for Tuning
1. 使用常量进行参数调优
gdscript
undefinedgdscript
undefined✅ Good - easy to tweak
✅ 良好实践 - 便于调整
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
❌ Bad - magic numbers
❌ 不良实践 - 魔法数值
velocity.x = 300
velocity.y = -400
undefinedvelocity.x = 300
velocity.y = -400
undefined2. Use @export
for Designer Control
@export2. 使用@export
让设计师可控参数
@exportgdscript
@export var speed: float = 300.0
@export var jump_velocity: float = -400.0
@export_range(0, 2000) var acceleration: float = 1500.0gdscript
@export var speed: float = 300.0
@export var jump_velocity: float = -400.0
@export_range(0, 2000) var acceleration: float = 1500.03. Separate Movement from Animation
3. 将移动与动画分离
gdscript
func _physics_process(delta: float) -> void:
_handle_movement(delta)
_handle_animation()
move_and_slide()
func _handle_movement(delta: float) -> void:
# Movement logic only
pass
func _handle_animation() -> void:
# Animation state changes only
if velocity.x > 0:
$AnimatedSprite2D.flip_h = false
elif velocity.x < 0:
$AnimatedSprite2D.flip_h = truegdscript
func _physics_process(delta: float) -> void:
_handle_movement(delta)
_handle_animation()
move_and_slide()
func _handle_movement(delta: float) -> void:
# 仅包含移动逻辑
pass
func _handle_animation() -> void:
# 仅包含动画状态切换
if velocity.x > 0:
$AnimatedSprite2D.flip_h = false
elif velocity.x < 0:
$AnimatedSprite2D.flip_h = true4. Use Floor Detection Parameters
4. 设置地面检测参数
gdscript
func _ready() -> void:
# Set floor parameters
floor_max_angle = deg_to_rad(45) # Max slope angle
floor_snap_length = 8.0 # Distance to snap to floor
motion_mode = MOTION_MODE_GROUNDED # Vs MOTION_MODE_FLOATINGgdscript
func _ready() -> void:
# 设置地面参数
floor_max_angle = deg_to_rad(45) # 最大斜坡角度
floor_snap_length = 8.0 # 地面吸附距离
motion_mode = MOTION_MODE_GROUNDED # 对比MOTION_MODE_FLOATINGCommon Gotchas
常见问题
Issue: Character slides on slopes
gdscript
undefined问题:角色在斜坡上滑动
gdscript
undefinedSolution: Increase friction
解决方案:增加摩擦力
const FRICTION := 1200.0
**Issue**: Character stutters on moving platforms
```gdscriptconst FRICTION := 1200.0
**问题**:角色在移动平台上卡顿
```gdscriptSolution: Enable platform snap
解决方案:启用平台吸附
func _physics_process(delta: float) -> void:
move_and_slide()
# Snap to platform velocity
if is_on_floor():
var floor_velocity := get_platform_velocity()
velocity += floor_velocity
**Issue**: Double jump exploit
```gdscriptfunc _physics_process(delta: float) -> void:
move_and_slide()
# 吸附到平台速度
if is_on_floor():
var floor_velocity := get_platform_velocity()
velocity += floor_velocity
**问题**:二段跳漏洞
```gdscriptSolution: Track if jump was used
解决方案:跟踪跳跃是否已使用
var can_jump := true
func _physics_process(delta: float) -> void:
if is_on_floor():
can_jump = true
if Input.is_action_just_pressed("jump") and can_jump:
velocity.y = JUMP_VELOCITY
can_jump = falseundefinedvar can_jump := true
func _physics_process(delta: float) -> void:
if is_on_floor():
can_jump = true
if Input.is_action_just_pressed("jump") and can_jump:
velocity.y = JUMP_VELOCITY
can_jump = falseundefinedReference
参考资料
Related
相关内容
- Master Skill: godot-master
- 大师技能:godot-master