返回 Skills 目錄
gamedev-skills/awesome-gamedev-agent-skills已通過檢查

SKILL DETAIL

platformer

gamedev-skills/awesome-gamedev-agent-skills/platformer

Build a 2D platformer: run/jump control with coyote time, jump buffering, and variable jump height, plus tiled levels and hazards. Use for a platformer or Mario/Celeste-like, or tuning jump feel.

安裝量 · 224查看來源

Installation

npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill platformer

技能檔案

SKILL.md

最近同步 · 2026年10月24日

references/feel-tuning.md›
# Platformer feel tuning (depth)

Deeper detail behind the controller in `SKILL.md`. All snippets are engine-neutral
pseudocode; the math is standard kinematics and ports to any engine. Tune by *outcome*
(tiles of height, seconds to apex), then read off the physics values.

## 1. Deriving jump physics

A jump is just projectile motion. Choose the two values a designer can actually feel —
**peak height** `h` and **time to reach the peak** `t` — and solve for the rest. With the
y-axis pointing down (most 2D engines):

```
gravity        g  = 2h / t²
jump_velocity  v0 = -2h / t          # negative = upward
peak reached after t seconds; total airtime ≈ 2t (symmetric gravity)
```

Asymmetric gravity makes the fall snappier than the rise without changing peak height:

```
rise_gravity = g
fall_gravity = g * fall_multiplier   # 1.5–2.0 feels good
# airtime shortens; the arc looks like a fast, weighty drop after a quick pop up.
```

If you instead know the jump velocity and want the height: `h = v0² / (2g)`.

## 2. Full feel knob reference

| Knob | What it changes | Typical range | Notes |
|------|-----------------|---------------|-------|
| Jump height | vertical reach | 2–5 tiles | Keep below the player's *commit* comfort. |
| Time to apex | weight/snappiness | 0.25–0.45 s | Lower = snappier, "tighter". |
| Fall multiplier | floatiness on descent | 1.3–2.2× | The single biggest "feel" lever. |
| Coyote time | post-ledge grace | 0.05–0.15 s | ~3–9 frames at 60 Hz. |
| Jump buffer | pre-land grace | 0.08–0.18 s | Forgive early presses. |
| Variable-jump cut | tap vs hold height | ×0.3–0.6 of vy | Cut only while rising. |
| Apex hang | air control at top | ×0.4–0.6 g near apex | Define apex as `|vy| < hang_threshold`. |
| Max fall speed | terminal velocity | clamp | Prevents tunneling and runaway speed. |
| Ground accel | time to top speed | 0.03–0.12 s | Instant = arcadey; longer = momentum. |
| Air control | steering mid-jump | 0.5–1.0× ground | <1 gives committed arcs. |
| Coyote-after-jump lockout | prevents double jumps | consume timers | Zero both timers on jump. |

## 3. Apex hang and fast-fall

```python
# Reduced gravity near the apex gives a moment of extra air control ("hang time").
if abs(velocity.y) < APEX_THRESHOLD and not on_floor:
    g = g * 0.5

# Optional fast-fall: holding Down past the apex increases downward gravity.
if holding_down and velocity.y > 0:
    g = g * 1.5
```

## 4. Corner correction (ceiling and ledge nudging)

When a rising jump clips a corner by a pixel or two, players read it as the game being
"sticky". Nudge them past it instead of stopping the jump dead:

```python
# On hitting a ceiling while rising, if only the outer 1–4 px are blocked,
# shift the body sideways into the free space and keep the upward velocity.
if blocked_overhead and velocity.y < 0:
    for offset in (1, 2, 3, 4):            # check small horizontal nudges
        if free_at(position + sideways * offset):
            position += sideways * offset
            break                          # keep rising; don't zero velocity.y
```

The same idea on landing edges (a few px of "ledge grab"/snap) makes platforms feel generous.

## 5. One-way platforms and drop-through

- Mark the platform's collision as one-directional (solid only when the player is above and
  moving down). Engines expose this directly — do not hand-roll it.
- **Drop-through:** when the player holds Down + Jump on a one-way platform, disable that
  collision for ~0.1–0.2 s (or until the player's top passes below the platform), then re-enable.

## 6. Moving platforms

- Carry the player: add the platform's per-frame delta to the player's position while standing
  on it, so they ride it instead of sliding off.
- Apply the platform's velocity to the player on jump-off so leaps from a moving platform feel
  physical. Cap the inherited horizontal velocity so it can't fling the player uncontrollably.

## 7. Camera follow

- **Deadzone:** a rectangle the player can move within before the camera reacts; stops jitter.
- **Look-ahead:** offset the camera target in the direction of motion / facing so the player
  sees what's coming. Lerp the offset; don't snap it.
- **Smoothing:** move the camera toward its target with an exponential `lerp(cam, target,
  1 - exp(-k*dt))` rather than a fixed fraction, so it is frame-rate independent.
- **Clamp:** keep the camera rect inside the level bounds so you never show out-of-level space.
- **Vertical care:** lock or slow vertical follow during normal jumps; only follow Y on large
  height changes (falling into a pit, climbing) to avoid bobbing on every hop.

## 8. Teaching and pacing (hand-off to `level-design`)

- Introduce one mechanic in isolation, let the player practice it safely, *then* combine it
  with a known one. Never introduce two new things in the same hazard.
- Place the first instance of any lethal hazard where failure is cheap (near a checkpoint,
  no long re-traversal).
- Keep checkpoint-to-checkpoint segments short early, longer later; respawn must be instant.
SKILL.md›
---
name: platformer
description: >
  Build a 2D platformer: run/jump control with coyote time, jump buffering, and variable jump
  height, plus tiled levels and hazards. Use for a platformer or Mario/Celeste-like, or tuning jump feel.
---

# Platformer

A playbook for 2D platformers — the run/jump controller "feel", level structure, hazards,
and goals. This is a **compositional** skill: it wires an engine movement skill, a tilemap
skill, and design skills into a working game. It does **not** re-teach physics or tilemaps;
it tells you what to build and how to make jumping feel good.

## When to use

- Use when building a side-scrolling or single-screen platformer, a "Mario-like" /
  "Celeste-like", or any game whose core verb is **jump between surfaces**.
- Use when a jump feels floaty, unresponsive, or "unfair" and you need feel fixes
  (coyote time, jump buffering, variable height, corner correction).

**When *not* to use:** top-down movement with no gravity → use the engine movement skill
directly. 3D first-person traversal → `fps-shooter`. Grid/turn movement → `roguelike`.
For the raw kinematic body API, use `godot-2d-movement` (or your engine's controller skill).

## Core loop

**Observe a gap/hazard → commit to a jump or move → land safely (or die) → reach the next
checkpoint/goal.** A platformer lives or dies on the *moment-to-moment* feel of that single
jump, repeated thousands of times. Tighten the controller first; everything else is content.

## Must-have systems

1. **Run/jump controller** — horizontal accel/decel, gravity, jump, with the feel aids below.
2. **Solid + one-way collision** — ground, walls, and "jump-through" platforms.
3. **Level geometry** — a tilemap or hand-placed colliders; the playable space.
4. **Hazards + death/respawn** — spikes, pits, enemies; reset to the last checkpoint.
5. **Checkpoints / level goal** — progress markers and a win condition (flag, door, exit).
6. **Camera** — follows the player with a deadzone and look-ahead, clamped to level bounds.
7. **Juice** — landing dust, squash/stretch, hit-stop, sound. Cheap, huge feel payoff.

## Design knobs (make the jump feel right)

Tune these by **outcome** (height in tiles, time to apex in seconds), not by raw numbers.

| Knob | Effect | Sane starting point |
|------|--------|---------------------|
| Max jump height | reach | 3–4 tiles |
| Time to apex | "weight"/snappiness | 0.30–0.40 s |
| Fall gravity multiplier | snappy, non-floaty fall | 1.5–2.0× rise gravity |
| Coyote time | jump just after leaving a ledge | 0.08–0.12 s (~5–7 frames @60) |
| Jump buffer | press just before landing still jumps | 0.10–0.15 s |
| Variable jump cut | tap = short hop, hold = full | cut upward velocity ×0.4–0.5 on release |
| Apex hang | brief float at the top for air control | reduce gravity ×0.5 near `|vy|`<threshold |
| Ground accel / friction | responsiveness vs. ice | reach top speed in 0.05–0.1 s |
| Corner correction | nudge past a ledge clipped by 1–2 px | nudge up to ~4 px sideways |

Derive gravity and jump velocity from the *feel* values rather than guessing — see Pattern 1.

## Patterns

### 1. Solve jump physics from height + time (not magic numbers)

```python
# Pseudocode. Pick the FEEL you want, then derive the physics. y-axis points DOWN.
# From kinematics: h = (g * t^2) / 2  and  v0 = g * t.
JUMP_HEIGHT   = 3.5 * TILE      # how high, in world units
TIME_TO_APEX  = 0.35            # seconds to reach the top

gravity       = (2 * JUMP_HEIGHT) / (TIME_TO_APEX ** 2)   # rising gravity
jump_velocity = -(2 * JUMP_HEIGHT) / TIME_TO_APEX         # negative = upward
fall_gravity  = gravity * 1.8   # heavier on the way down → less floaty
```

### 2. Coyote time + jump buffer + variable height (the feel core)

```python
# Pseudocode in the per-frame update. dt = seconds since last frame.
# Timers count DOWN; refresh coyote while grounded, buffer on a fresh press.
if on_floor:
    coyote_timer = COYOTE_TIME           # 0.1
if jump_pressed_this_frame:
    buffer_timer = JUMP_BUFFER           # 0.12
coyote_timer -= dt
buffer_timer -= dt

# A jump is allowed if we pressed recently AND were grounded recently.
if buffer_timer > 0 and coyote_timer > 0:
    velocity.y   = jump_velocity
    buffer_timer = 0
    coyote_timer = 0                     # consume both so we can't double-jump

# Variable height: releasing jump early while still rising cuts the arc short.
if jump_released_this_frame and velocity.y < 0:
    velocity.y *= 0.45

# Asymmetric gravity: snappier fall than rise.
g = fall_gravity if velocity.y > 0 else gravity
velocity.y += g * dt
```

### 3. One-way platforms

Solid from above, pass-through from below. Most engines expose a "one-way collision" flag on
the tile/collider; enable it and let the player **drop through** by disabling that collision
for a few frames when the player holds Down + Jump. Do not re-implement collision math.

## Pitfalls / failure modes

- **Per-frame movement not scaled by `dt`** → speed changes with frame rate. Every velocity
  integration and timer must use `dt`. (See `physics-tuning`.)
- **Floaty jumps** → symmetric gravity. Make fall gravity heavier than rise gravity.
- **"The jump didn't register"** → no input buffering. Buffer presses for ~0.1 s before landing.
- **"I fell off and couldn't jump"** → no coyote time. Allow a jump for ~0.1 s after leaving ground.
- **Sticking to walls / catching on tile seams** → use a single capsule/box collider, not
  per-tile colliders, and add corner correction.
- **Tunneling through floors at high speed** → enable continuous collision / smaller fixed
  timestep for fast bodies (see `physics-tuning`).
- **Camera snaps and induces nausea** → smooth/lerp the follow, add a deadzone, clamp to bounds.
- **Difficulty wall from bad teaching** → introduce one mechanic per area before combining them.

## Composition (build it from these skills)

- **Controller body:** `godot-2d-movement` (Godot `CharacterBody2D`); for other engines use
  the engine core + physics skill (`unity-physics`, `phaser-arcade-physics`, `pygame-core`).
- **Levels:** `godot-tilemap` / `unity-tilemap-2d` for geometry; `level-design` for layout,
  pacing, and teaching order.
- **Feel/physics:** `physics-tuning` for timestep, CCD, and stability.
- **Input:** `input-systems` for buffering, rebinding, and gamepad support.
- **Polish:** `audio-design` for SFX/music; the engine animation skill for squash/stretch.
- **Process:** `prototype-fast` to greybox the controller before building content.

## References

- For jump math derivation, a full feel-tuning table, corner correction, moving/one-way
  platforms, and camera follow, read `references/feel-tuning.md`.