godot-characterbody-2d by thedivergentai/gd-agentic-skills
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-characterbody-2d使用 Godot 物理系统实现玩家控制的 2D 移动的专家指南。
RigidBody2D 作为标准玩家控制器 — RigidBody 适用于物理模拟的对象。对于响应灵敏、手感驱动的玩家移动,请始终使用 CharacterBody2D。move_and_slide() 之前将 velocity 乘以 delta — move_and_slide() 内部会处理 delta。手动乘法会使移动依赖于帧率 [12]。global_position 更新来进行移动 — 请使用 velocity 和 。直接更新位置会绕过碰撞检测和地面吸附。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
move_and_slide()move_and_slide() 的返回值 — 虽然可选,但在调用后立即检查 is_on_floor() 或 get_last_motion() 对于状态逻辑至关重要。floor_snap_length 来实现快速爬楼梯 — 默认的吸附距离对于高速角色来说太小了。请使用基于自定义射线投射的楼梯逻辑来实现平滑过渡。is_on_floor() 为 true 时应用重力 — 在地面上持续施加向下的力可能导致“微抖动”或阻止地面吸附正常工作。将 velocity.y 重置为 0 或一个小的常数。Area2D 进行地面检测 — 真实的碰撞(射线/形状投射)更精确。is_on_floor() 是高度优化的;仅在必要时才增强它。is_on_ceiling() 时没有将 velocity.y 重置为 0,玩家将“漂浮”在天花板上,直到重力将其拉下。_process 中四舍五入你的 Sprite 节点位置,以避免视觉上的亚像素抖动。queue_free() — 对于子弹或敌人,请使用对象池来避免 SceneTree 性能峰值。强制要求:在实现相应模式之前,请先阅读适当的脚本。
专业的平台游戏机制:土狼时间(下落后的跳跃)和输入缓冲。
高级的程序化爬楼梯和平滑斜坡吸附逻辑。
基于输入持续时间的可定制“短跳”与“全跳”实现。
响应灵敏的墙壁滑行和墙壁跳跃机制,带有适当的推开力。
基于状态的冲刺逻辑,包含无敌帧和可定制的冷却时间。
在保持平滑物理的同时,维持低分辨率游戏中像素完美视觉效果的专家模式。
使用基于可见性的物理切换来优化 100 多个活动角色的逻辑。
与 move_and_slide 集成的外部力(击退、吹飞、风力)的专家级处理。
用于专业平台游戏手感的精确空中控制和加速逻辑。
通过正确处理天花板碰撞时的垂直动量来修复“粘头”问题。
完整的平台游戏移动,包含土狼时间、跳跃缓冲、平滑加速/摩擦和亚像素稳定。使用 move_toward 进行精确控制。
帧级完美的冲刺,包含无敌帧、冷却时间和动量保持。
墙壁滑行、吸附和带有自动修正的方向性墙壁跳跃。
首要任务:在添加冲刺/墙壁跳跃之前,请先阅读 expert_physics_2d.gd 以了解平台游戏基础。
使用 CharacterBody2D 用于:
使用 RigidBody2D 用于:
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.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
# 处理跳跃
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()
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
const ACCELERATION := 1500.0
const FRICTION := 1200.0
const AIR_RESISTANCE := 200.0
# 土狼时间:离开平台后的宽限期
const COYOTE_TIME := 0.1
var coyote_timer := 0.0
# 跳跃缓冲:在落地前稍微记住跳跃输入
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:
# 重力
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
# 跳跃(包含土狼时间和缓冲)
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()
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()
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()
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")
func _physics_process(delta: float) -> void:
move_and_slide()
# 处理每个碰撞
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())
# 示例:从墙壁弹开
if collision.get_collider().is_in_group("bouncy"):
velocity = velocity.bounce(collision.get_normal())
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()
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()
# ✅ 良好 - 易于调整
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
# ❌ 不好 - 魔法数字
velocity.x = 300
velocity.y = -400
@export 以便设计师控制@export var speed: float = 300.0
@export var jump_velocity: float = -400.0
@export_range(0, 2000) var acceleration: float = 1500.0
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 = true
func _ready() -> void:
# 设置地面参数
floor_max_angle = deg_to_rad(45) # 最大斜坡角度
floor_snap_length = 8.0 # 吸附到地面的距离
motion_mode = MOTION_MODE_GROUNDED # 相对于 MOTION_MODE_FLOATING
问题:角色在斜坡上滑动
# 解决方案:增加摩擦力
const FRICTION := 1200.0
问题:角色在移动平台上卡顿
# 解决方案:启用平台吸附
func _physics_process(delta: float) -> void:
move_and_slide()
# 吸附到平台速度
if is_on_floor():
var floor_velocity := get_platform_velocity()
velocity += floor_velocity
问题:二段跳漏洞
# 解决方案:跟踪是否已使用跳跃
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 = false
每周安装次数
73
仓库
GitHub 星标数
59
首次出现
2026年2月10日
安全审计
安装于
gemini-cli72
codex72
opencode72
github-copilot70
amp69
kimi-cli69
Expert guidance for player-controlled 2D movement using Godot's physics system.
RigidBody2D for standard player controllers — RigidBody is for physics-simulated objects. For responsive, feel-driven player movement, always use CharacterBody2D.velocity by delta before move_and_slide() — move_and_slide() handles delta internally. Manual multiplication makes movement framerate-dependent [12].global_position updates for movement — Use velocity and move_and_slide(). Direct position updates bypass collision detection and floor snapping.move_and_slide() — While optional, checking is_on_floor() or get_last_motion() immediately after is critical for state logic.floor_snap_length for fast stair-climbing — Default snapping is too small for high-velocity characters. Use custom raycast-based stair logic for smooth transitions.is_on_floor() is true — Constant downward force on the floor can cause "micro-jitter" or prevent floor-snap from working correctly. Reset velocity.y to 0 or a small constant.Area2D for ground detection — Real collisions (rays/shapecasts) are more precise. is_on_floor() is highly optimized; only augment it if necessary.velocity.y to 0 when is_on_ceiling(), the player will "float" against the ceiling until gravity pulls them down._process to avoid visual sub-pixel jitter.queue_free() on characters every frame — Use object pooling for bullets or enemies to avoid SceneTree performance spikes.MANDATORY : Read the appropriate script before implementing the corresponding pattern.
Professional platformer mechanics: Coyote Time (jump after fall) and Input Buffering.
Advanced procedural stair-climbing and smooth slope snapping logic.
Customizable 'Short Hop' vs 'Full Jump' implementation based on input duration.
Responsive Wall Slide and Wall Jump mechanics with proper push-back forces.
State-based dash logic with invincibility frames and customizable cooldowns.
Expert pattern for maintaining pixel-perfect visuals in low-res games while keeping smooth physics.
Logic for optimizing 100+ active characters using visibility-based physics toggling.
Expert handling of external forces (Knockback, Blow-back, Wind) integrated with move_and_slide.
Precise air control and acceleration logic for professional platformer feel.
Fixing 'sticky head' syndrome by correctly handling vertical momentum on ceiling hits.
Complete platformer movement with coyote time, jump buffering, smooth acceleration/friction, and sub-pixel stabilization. Uses move_toward for precise control.
Frame-perfect dash with I-frames, cooldown, and momentum preservation.
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.
Use CharacterBody2D For:
Use RigidBody2D For:
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
# Get 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()
extends CharacterBody2D
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
const ACCELERATION := 1500.0
const FRICTION := 1200.0
const AIR_RESISTANCE := 200.0
# Coyote time: grace period after leaving platform
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()
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()
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()
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")
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())
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()
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()
# ✅ Good - easy to tweak
const SPEED := 300.0
const JUMP_VELOCITY := -400.0
# ❌ Bad - magic numbers
velocity.x = 300
velocity.y = -400
@export for Designer Control@export var speed: float = 300.0
@export var jump_velocity: float = -400.0
@export_range(0, 2000) var acceleration: float = 1500.0
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 = true
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_FLOATING
Issue : Character slides on slopes
# Solution: Increase friction
const FRICTION := 1200.0
Issue : Character stutters on moving platforms
# Solution: 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
# Solution: 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 = false
Weekly Installs
73
Repository
GitHub Stars
59
First Seen
Feb 10, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli72
codex72
opencode72
github-copilot70
amp69
kimi-cli69
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,700 周安装
Bun FFI 教程:JavaScript 调用 C/C++ 原生库的完整指南
12 周安装
Bun React SSR 教程:使用 Bun 构建服务器端渲染的 React 应用
12 周安装
小跃虚拟伴侣Skill - 为OpenClaw AI助手添加温暖对话与情感陪伴能力
12 周安装
Bun HTTP Server 高性能服务器教程 - Bun.serve() 快速搭建与请求处理指南
16 周安装
Bun 包管理器完整指南:比 npm 快 25 倍的现代 JavaScript 包管理工具
17 周安装
Bun Nuxt 快速开发指南:使用 Bun 运行 Nuxt 3 提升开发效率与性能
16 周安装