Loading...
Loading...
Expert blueprint for platformer games including precision movement (coyote time, jump buffering, variable jump height), game feel polish (squash/stretch, particle trails, camera shake), level design principles (difficulty curves, checkpoint placement), collectible systems (progression rewards), and accessibility options (assist mode, remappable controls). Based on Celeste/Hollow Knight design research. Trigger keywords: platformer, coyote_time, jump_buffer, game_feel, level_design, precision_movement.
npx skill4agent add thedivergentai/gd-agentic-skills godot-genre-platformerMANDATORY: Read the appropriate script before implementing the corresponding pattern.
Jump → Navigate Obstacles → Reach Goal → Next Levelgodot-project-foundationsgodot-characterbody-2dgodot-input-handlinganimationsound-managertilemap-setupcamera-2d# Instant direction changes - no acceleration on ground
func _physics_process(delta: float) -> void:
var input_dir := Input.get_axis("move_left", "move_right")
# Ground movement: instant response
if is_on_floor():
velocity.x = input_dir * MOVE_SPEED
else:
# Air movement: slightly reduced control
velocity.x = move_toward(velocity.x, input_dir * MOVE_SPEED, AIR_ACCEL * delta)var coyote_timer: float = 0.0
const COYOTE_TIME := 0.1 # 100ms grace period
func _physics_process(delta: float) -> void:
if is_on_floor():
coyote_timer = COYOTE_TIME
else:
coyote_timer = max(0, coyote_timer - delta)
# Can jump if on floor OR within coyote time
if Input.is_action_just_pressed("jump") and coyote_timer > 0:
velocity.y = JUMP_VELOCITY
coyote_timer = 0var jump_buffer: float = 0.0
const JUMP_BUFFER_TIME := 0.15
func _physics_process(delta: float) -> void:
if Input.is_action_just_pressed("jump"):
jump_buffer = JUMP_BUFFER_TIME
else:
jump_buffer = max(0, jump_buffer - delta)
if is_on_floor() and jump_buffer > 0:
velocity.y = JUMP_VELOCITY
jump_buffer = 0const JUMP_VELOCITY := -400.0
const JUMP_RELEASE_MULTIPLIER := 0.5
func _physics_process(delta: float) -> void:
# Cut jump short when button released
if Input.is_action_just_released("jump") and velocity.y < 0:
velocity.y *= JUMP_RELEASE_MULTIPLIERconst GRAVITY := 980.0
const FALL_GRAVITY_MULTIPLIER := 1.5 # Faster falls feel better
const MAX_FALL_SPEED := 600.0
func apply_gravity(delta: float) -> void:
var grav := GRAVITY
if velocity.y > 0: # Falling
grav *= FALL_GRAVITY_MULTIPLIER
velocity.y = min(velocity.y + grav * delta, MAX_FALL_SPEED)Easy → Easy → Medium → CHECKPOINT → Medium → Hard → CHECKPOINT → Boss# Look-ahead camera for platformers
extends Camera2D
@export var look_ahead_distance := 100.0
@export var look_ahead_speed := 3.0
var target_offset := Vector2.ZERO
func _process(delta: float) -> void:
var player_velocity: Vector2 = target.velocity
var desired_offset := player_velocity.normalized() * look_ahead_distance
target_offset = target_offset.lerp(desired_offset, look_ahead_speed * delta)
offset = target_offsetgodot-genre-metroidvania| Pitfall | Solution |
|---|---|
| Floaty jumps | Increase gravity, especially on descent |
| Imprecise landings | Add coyote time and visual landing feedback |
| Unfair deaths | Ensure hazards are clearly visible before encountered |
| Blind jumps | Camera look-ahead or zoom out during falls |
| Boring mid-game | Introduce new mechanics every 2-3 levels |
CharacterBody2Dset_collision_mask_value()is_on_wall()get_wall_normal()