platformer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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.
一份2D平台游戏的开发指南——涵盖跑跳控制器的「手感」、关卡结构、危险元素以及目标设计。这是一项组合式技能:它将引擎移动技能、tilemap技能和设计技能整合为可运行的游戏。本指南不会重新讲解物理或tilemap知识;它会告诉你要构建什么,以及如何让跳跃手感更出色。

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).
  • 适用于构建横向卷轴或单屏平台游戏、「类马里奥」/「类蔚蓝」游戏,或任何核心玩法为在平台间跳跃的游戏。
  • 当跳跃手感显得漂浮、反应迟缓或「不合理」,需要进行手感修复(coyote time、jump buffering、可变高度、拐角修正)时使用。
不适用场景: 无重力的俯视视角移动 → 直接使用引擎移动技能。3D第一人称移动 → 使用
fps-shooter
技能。网格/回合制移动 → 使用
roguelike
技能。如需原始运动学物体API,请使用
godot-2d-movement
(或对应引擎的控制器技能)。

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.
观察缺口/危险元素 → 决定跳跃或移动 → 安全着陆(或死亡) → 到达下一个 checkpoint/目标。 平台游戏的成败取决于单次跳跃的即时手感,而这个动作会被重复数千次。优先优化控制器;其他一切都只是内容。

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.
  1. 跑跳控制器 —— 水平加速/减速、重力、跳跃,搭配以下手感优化功能。
  2. 实体+单向碰撞 —— 地面、墙壁和「可跳跃穿过」的平台。
  3. 关卡几何结构 —— tilemap或手动放置的碰撞体;可游玩空间。
  4. 危险元素+死亡/重生 —— 尖刺、陷阱、敌人;重置到最近的checkpoint。
  5. Checkpoint / 关卡目标 —— 进度标记和胜利条件(旗帜、门、出口)。
  6. 相机 —— 跟随玩家,带有死区和前瞻功能,并限制在关卡边界内。
  7. 润色效果(Juice) —— 落地灰尘、挤压拉伸、击中停顿、音效。成本低,但对提升手感效果显著。

Design knobs (make the jump feel right)

设计调节项(优化跳跃手感)

Tune these by outcome (height in tiles, time to apex in seconds), not by raw numbers.
KnobEffectSane starting point
Max jump heightreach3–4 tiles
Time to apex"weight"/snappiness0.30–0.40 s
Fall gravity multipliersnappy, non-floaty fall1.5–2.0× rise gravity
Coyote timejump just after leaving a ledge0.08–0.12 s (~5–7 frames @60)
Jump bufferpress just before landing still jumps0.10–0.15 s
Variable jump cuttap = short hop, hold = fullcut upward velocity ×0.4–0.5 on release
Apex hangbrief float at the top for air controlreduce gravity ×0.5 near `
Ground accel / frictionresponsiveness vs. icereach top speed in 0.05–0.1 s
Corner correctionnudge past a ledge clipped by 1–2 pxnudge up to ~4 px sideways
Derive gravity and jump velocity from the feel values rather than guessing — see Pattern 1.
通过结果(以瓦片为单位的高度,到达顶点的时间(秒))来调节这些参数,而非原始数值。
调节项效果合理起始值
最大跳跃高度跳跃可达高度3–4个瓦片
到达顶点时间「重量感」/灵敏性0.30–0.40 秒
下落重力乘数让下落更灵敏、不漂浮上升重力的1.5–2.0倍
Coyote time刚离开边缘时仍可跳跃0.08–0.12秒(60帧下约5–7帧)
Jump buffer落地前提前按下跳跃键仍可触发跳跃0.10–0.15秒
可变跳跃高度轻按=短跳,按住=满跳松开按键时将上升速度乘以0.4–0.5
顶点悬浮在跳跃顶点短暂悬浮以提升空中控制当`
地面加速/摩擦力响应速度 vs 冰面效果在0.05–0.1秒内达到最高速度
拐角修正推动玩家越过被1–2像素卡住的边缘最多横向推动约4像素
从「手感」值推导重力和跳跃速度,而非凭空猜测——请参见模式1。

Patterns

模式

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

1. 从高度+时间推导跳跃物理(而非魔法数值)

python
undefined
python
undefined

Pseudocode. Pick the FEEL you want, then derive the physics. y-axis points DOWN.

伪代码。先确定你想要的手感,再推导物理参数。y轴向下。

From kinematics: h = (g * t^2) / 2 and v0 = g * t.

来自运动学公式:h = (g * t^2) / 2 以及 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
undefined
JUMP_HEIGHT = 3.5 * TILE # 跳跃高度,以世界单位计 TIME_TO_APEX = 0.35 # 到达顶点的时间(秒)
gravity = (2 * JUMP_HEIGHT) / (TIME_TO_APEX ** 2) # 上升阶段重力 jump_velocity = -(2 * JUMP_HEIGHT) / TIME_TO_APEX # 负值表示向上 fall_gravity = gravity * 1.8 # 下落阶段重力更大 → 减少漂浮感
undefined

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

2. Coyote time + Jump buffer + 可变高度(手感核心)

python
undefined
python
undefined

Pseudocode in the per-frame update. dt = seconds since last frame.

每帧更新中的伪代码。dt = 距上一帧的时间(秒)。

Timers count DOWN; refresh coyote while grounded, buffer on a fresh press.

计时器倒计时;在地面时刷新coyote计时器,按下跳跃键时刷新缓冲计时器。

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
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
if buffer_timer > 0 and coyote_timer > 0: velocity.y = jump_velocity buffer_timer = 0 coyote_timer = 0 # 消耗两个计时器,防止二段跳

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
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
undefined
g = fall_gravity if velocity.y > 0 else gravity velocity.y += g * dt
undefined

3. One-way platforms

3. 单向平台

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.
  • 每帧移动未按
    dt
    缩放
    → 速度随帧率变化。所有速度积分和计时器都必须使用
    dt
    。(参见
    physics-tuning
    。)
  • 漂浮感跳跃 → 对称重力。让下落重力大于上升重力。
  • 「跳跃未触发」 → 没有输入缓冲。在落地前约0.1秒内缓冲按键。
  • 「我掉下去了但没法跳」 → 没有coyote time。允许玩家离开地面后约0.1秒内仍可跳跃。
  • 粘墙 / 卡在瓦片接缝处 → 使用单个胶囊/盒形碰撞体,而非每个瓦片一个碰撞体,并添加拐角修正。
  • 高速下穿透地面 → 为快速移动的物体启用连续碰撞检测/更小的固定时间步长(参见
    physics-tuning
    )。
  • 相机突然移动导致恶心 → 使用平滑插值跟随,添加死区,限制在边界内。
  • 糟糕的教学导致难度陡增 → 在组合机制前,每个区域只引入一种机制。

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.
  • 控制器物体:
    godot-2d-movement
    (Godot的
    CharacterBody2D
    );对于其他引擎,使用引擎核心+物理技能(
    unity-physics
    phaser-arcade-physics
    pygame-core
    )。
  • 关卡: 使用
    godot-tilemap
    /
    unity-tilemap-2d
    构建几何结构;使用
    level-design
    进行布局、节奏和教学顺序设计。
  • 手感/物理:
    physics-tuning
    用于时间步长、CCD和稳定性。
  • 输入:
    input-systems
    用于缓冲、重绑定和手柄支持。
  • 润色:
    audio-design
    用于音效/音乐;引擎动画技能用于挤压拉伸效果。
  • 流程:
    prototype-fast
    用于在构建内容前快速制作控制器原型。

References

参考资料

  • For jump math derivation, a full feel-tuning table, corner correction, moving/one-way platforms, and camera follow, read
    references/feel-tuning.md
    .
  • 如需跳跃数学推导、完整的手感调节表、拐角修正、移动/单向平台以及相机跟随的相关内容,请阅读
    references/feel-tuning.md