关于 camera-systems
面向游戏开发者的引擎无关相机技能,涵盖 2D 和 3D 镜头设计。内容包括平滑跟随、边界限制、环绕碰撞及抖动和穿墙问题的处理。
主要功能
- 01帧率无关的平滑跟随
- 02死区、前视与边界限制
- 03第三人称环绕与碰撞
- 04第一人称及多目标取景
- 05相机震动偏移接口
适用场景
- 01构建受关卡边界限制的 2D 跟随镜头
- 02制作可避开墙壁的 3D 环绕镜头
- 03减少不同帧率下的抖动和跳动
- 04同时取景多个目标或叠加震动
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill camera-systems安装后在 Claude Code 中输入/camera-systems确认已加载。
附带文件references/follow-and-framing.md
详细介绍
摄像机系统
摄像机是玩家观察游戏的窗口;糟糕的摄像机控制会让好游戏变得令人难受。本技能涵盖与引擎无关的摄像机技术——平滑跟随、死区、视线提前量、边界钳制、带碰撞检测的第三人称环绕、第一人称视角,以及多目标取景——并将这些技术映射到各引擎的摄像机节点或机架上。
适用场景
- 当 2D 摄像机需要平滑跟随玩家、保持在关卡范围内、引导玩家的移动方向,或忽略微小移动(死区)时使用。
- 构建 3D 第三人称环绕摄像机(鼠标/摇杆视角控制、碰撞时拉近),或第一人称视角控制器,或同时为多个目标取景时使用。
- 修复摄像机抖动、突然跳动、晕动症,或摄像机显示到关卡边界之外的情况时使用。
不适用场景: 如需调整屏幕震动的幅度和触发条件,请使用 game-feel(本技能会提供它所驱动的震动偏移钩子)。如需了解引擎具体的摄像机节点/组件设置,请使用 godot-3d-essentials(Camera3D、环境)或对应的引擎技能。玩家移动本身请使用引擎移动技能(godot-2d-movement)。如需优化多个摄像机/渲染目标的性能,请参阅 performance-optimization。
核心工作流
- 确定摄像机的用途。 平台游戏(引导跳跃、观察危险)、俯视游戏(配合死区居中)、第三人称(环绕+碰撞检测)、第一人称(仅控制视角)。游戏类型决定规则。
- 平滑跟随,并确保与帧率无关。 使用指数平滑或弹簧(
SmoothDamp)让摄像机向目标移动,而非使用固定的lerp(a, b, 0.1)——其中的 0.1 是逐帧计算的,效果会随帧率变化。 - 添加死区, 避免目标的微小移动带动摄像机;只有目标离开框/区域后,摄像机才开始跟随。这能减少反应敏捷的游戏带来的恶心感。
- 通过视线提前量引导动作, 将摄像机目标沿移动方向或面朝方向偏移,并平滑地渐入/渐出,避免摄像机猛然转动。
- 将摄像机限制在关卡边界内, 避免显示可玩区域之外的内容;结合平滑处理,使摄像机在边缘平稳停止。
- 对于 3D,将视角控制与碰撞检测分开。 通过机架上的偏航/俯仰实现环绕;使用弹簧臂/射线在几何体阻挡视线时将摄像机拉近;限制俯仰角。
- 在目标移动后更新摄像机。 在延迟/后置步骤中跟随(待移动和物理处理完成后),避免一帧延迟造成抖动。
- 以低帧率和高帧率移动目标进行验证, 并让目标进入角落和墙边,以及移动到关卡边缘;确认没有抖动、没有越过边界的画面,且能平稳停止。报告观察结果。
模式
1. Godot 2D 内置跟随:平滑处理+边界(不要先手动实现)
# Godot 4.7 Camera2D. Engine-provided smoothing + hard limits + drag margins.
@onready var cam := $Camera2D
func _ready() -> void:
cam.make_current()
cam.position_smoothing_enabled = true
cam.position_smoothing_speed = 6.0 # higher = snappier; lower = floatier
cam.limit_left = 0; cam.limit_top = 0 # clamp to the level rect (pixels)
cam.limit_right = level_width; cam.limit_bottom = level_height
cam.drag_horizontal_enabled = true # built-in deadzone via drag margins
2. 与帧率无关的平滑跟随(手动实现时)
# RIGHT: exponential smoothing — same feel at any FPS. `rate` ~ 5..12.
func _follow(dt: float) -> void:
var t := 1.0 - exp(-rate * dt) # converges correctly regardless of dt
global_position = global_position.lerp(target.global_position, t)
# WRONG: global_position = global_position.lerp(target.global_position, 0.1)
# → faster smoothing at higher FPS; different feel on every machine.
# Unity 6.3 LTS: Vector3.SmoothDamp(transform.position, target.position, ref vel, smoothTime) in
# LateUpdate gives the same spring behavior with built-in frame-rate correction.
3. 死区+视线提前量(引导玩家,忽略抖动)
# Camera only chases once the target leaves the deadzone box, then aims AHEAD of motion.
func _camera_target(dt: float) -> Vector2:
var to := target.global_position - _focus
var dz := deadzone_half_extents # e.g. Vector2(48, 32)
# Only move the focus by the overflow beyond the deadzone (per axis).
_focus.x += clampf(absf(to.x) - dz.x, 0, INF) * signf(to.x)
_focus.y += clampf(absf(to.y) - dz.y, 0, INF) * signf(to.y)
var lead := target.velocity.normalized() * look_ahead_dist # aim ahead of travel
return _focus + lead
4. 带碰撞拉近的 3D 第三人称环绕
# Godot 4.7. Yaw/pitch a pivot; a SpringArm3D auto-pulls the camera in when blocked.
func _unhandled_input(e):
if e is InputEventMouseMotion:
_yaw -= e.relative.x * sensitivity
_pitch = clampf(_pitch - e.relative.y * sensitivity, -1.2, 0.4) # clamp pitch!
func _process(_dt):
pivot.rotation = Vector3(_pitch, _yaw, 0)
# $SpringArm3D handles wall collision: set spring_length + collision_mask; the child
# Camera3D slides in automatically. RIGHT: spring arm. WRONG: camera clips through walls.
# Unity 6.3 LTS: a Cinemachine 3 CinemachineCamera (namespace Unity.Cinemachine) with an Orbital
# Follow + Cinemachine Deoccluder; the CinemachineBrain on the Camera blends automatically.
5. 屏幕震动钩子(触发逻辑由 game-feel 负责)
# Expose an additive offset the game-feel trauma model writes to; follow + shake compose.
var shake_offset := Vector2.ZERO # set each frame by game-feel (trauma^2 * noise)
func _apply(final_focus: Vector2) -> void:
global_position = final_focus + shake_offset # shake rides ON TOP of smooth follow
# Unity Cinemachine: add a CinemachineBasicMultiChannelPerlin and set amplitude from trauma.
常见陷阱
- 每帧调用
lerp(pos, target, const)会受帧率影响:30 FPS 时运动更轻飘,144 FPS 时则更灵敏。请使用1 - exp(-rate*dt)或SmoothDamp。 - 在目标移动之前于常规更新中跟随 会造成一帧延迟抖动。请在
LateUpdate中跟随,或等移动/物理计算完成后再跟随。 - 不限制边界 会导致镜头在关卡边缘之外显示黑色区域。请将焦点限制在关卡矩形内(考虑视口的半尺寸,确保留在范围内的是整个 视图,而不只是中心点)。
- 抖动明显的游戏没有死区 会让镜头随着每个细微动作抖动 → 引发恶心感。
- 第三人称/第一人称视角不限制俯仰角 会让镜头翻过头顶。请将俯仰角限制在约 ±80°。
- 3D 中镜头穿墙:使用弹簧臂/遮挡射线将镜头拉近。
- 传送/重生时瞬间切换镜头 会让人感到突兀;可以有意硬切并重置平滑状态,也可以快速缓动。不要让
SmoothDamp因距离过大而甩过整个关卡。 - 让震动驱动跟随目标,而不是使用叠加偏移 会使跟随效果与震动相互冲突。组合方式:先平滑跟随,最后再添加震动偏移。
- 混淆逐轴死区和径向死区:方框死区的感觉与圆形死区不同,请有意选择。
参考资料
- 如需了解指数平滑/弹簧的推导、完整的含死区+前瞻+边界限制的 2D 镜头系统、3D 弹簧臂/环绕细节、第一人称视角、多个目标/群组取景与分屏、电影级镜头混合,以及 Cinemachine 3 / Godot Camera2D / PhantomCamera 的对应关系,请阅读
references/follow-and-framing.md。
相关技能
game-feel— 负责屏幕震动的创伤值/触发条件;此技能会公开其写入的偏移量。godot-2d-movement、godot-3d-essentials— 镜头取景的玩家/世界;Camera3D 设置。physics-tuning— 将镜头跟随与物理步进同步插值,以消除抖动。platformer、fps-shooter— 此技能实现其镜头规则的游戏类型。performance-optimization— 额外摄像机、渲染目标和分屏的成本。
评论
支持 Markdown