关于 godot-2d-gameplay
godot-2d-gameplay 是在 Godot 项目既有规范内实现 2D 玩法的技能,面向开发移动、物理和战斗系统的开发者。它要求先检查项目,再按实际场景设计并验证,而非直接照搬代码片段。
主要功能
- 01检查 Godot 版本和项目配置
- 02沿用现有场景与输入规范
- 03按玩法职责选择物理节点
- 04构建移动与战斗交互
- 05验证碰撞、伤害和性能边界
- 06排查常见的 2D 玩法故障
适用场景
- 01实现平台跳跃或俯视角角色控制
- 02添加基于碰撞的攻击与伤害
- 03调试 TileMap 碰撞位置偏差
- 04检查不同物理条件下的玩法表现
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ pbzona/ godot-skills --skill godot-2d-gameplay安装后在 Claude Code 中输入/godot-2d-gameplay确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/animation-combat-game-feel.mdmovement-physics-tilemaps.mdverification-and-troubleshooting.md详细介绍
Godot 2D 游戏玩法
在项目现有的场景、输入、物理和组件约定中实现游戏玩法。将代码片段视为可调整的模式,而不是可以原样粘贴的文件。
从项目现状着手
在提出节点或代码之前:
- 找到最近的
project.godot。读取config/features;如果有可用的 Godot 可执行文件,则通过godot --version或项目文档中指定的二进制文件确认版本。 - 检查
application/run/main_scene、[input]、已命名的 2D 物理层、物理帧率、默认重力、窗口/拉伸设置和纹理过滤。 - 搜索现有的
.gd、.tscn和.tres文件,查找玩家物体、TileMap或TileMapLayer、动画节点、伤害 API、组、自动加载项和测试工具。 - 沿用现有的节点名称、类型化脚本风格、信号命名、场景所有权和碰撞约定。
- 不要只为匹配示例而迁移可正常工作的
TileMap。对于新内容,仅当检查到的 Godot 版本支持TileMapLayer时才优先使用它。
如果不存在项目文件,请先询问目标 Godot 4.x 次要版本和最简场景约定,再生成特定于项目的文件。
选择物理控制方
- 对于需要与世界碰撞并滑动的代码驱动角色,使用
CharacterBody2D。平台游戏使用贴地运动,俯视角角色使用浮空运动。 - 对于由模拟驱动的对象,使用
RigidBody2D。离散撞击使用冲量,持续加速使用力;不要每帧覆盖其变换。 - 对于脚本驱动、需要可预测地传递运动的平台和危险物,使用
AnimatableBody2D。 - 对于仅检测重叠的传感器、拾取物、受击框和大多数简单弹体,使用
Area2D。它不提供扫掠式物体碰撞。 - 在
_physics_process()中处理物理移动和查询。除非必须与物理结果完全同步,否则在_process()中更新表现效果。
实现工作流
- 用可衡量的指标定义行为。 记录速度、加速度、停止距离、跳跃高度或滞空时间、攻击频率、无敌时间以及预期的碰撞对象。
- 先创建输入。 重用语义化的 Input Map 动作。绝不要在角色逻辑中硬编码按键。若同时支持键盘和控制器,请检查死区。
- 搭建灰盒物理场景。 在添加美术、动画、摄像机或战斗前,先使用基础碰撞形状和平面地板。
- 实现一种移动模式。 速度以像素/秒为单位;
CharacterBody2D.move_and_slide()会在内部应用物理时间步长。 - 分层构建世界。 根据实际职责,将地面、带碰撞的地形、装饰、前景和导航分开。
- 根据游戏状态驱动视觉效果。 在移动后选择动画,并避免动画轨道覆盖权威物理变换。
- 将战斗实现为明确的交互。 为攻击、受击框、生命值、阵营、冷却时间和死亡分别定义约定。使用信号提供反馈。
- 最后再加入游戏手感效果。 围绕已确认的事件叠加清晰易读的效果;绝不要用屏幕抖动或动画掩盖不可靠的碰撞。
- 在边界情况和高负载下验证。 测试斜坡、拐角、低天花板、同时受击、场景重载、对象池复用,以及预期的最高角色/弹体数量。
类型化平台游戏核心
此控制器使用基于速率的加速度、跳跃缓冲、土狼时间和短跳松键机制。请根据项目的比例调整数值。
extends CharacterBody2D
@export_range(0.0, 2000.0, 1.0) var run_speed: float = 260.0
@export_range(0.0, 10000.0, 1.0) var ground_accel: float = 2200.0
@export_range(0.0, 10000.0, 1.0) var air_accel: float = 900.0
@export_range(0.0, 10000.0, 1.0) var gravity: float = 1800.0
@export_range(0.0, 5000.0, 1.0) var jump_speed: float = 560.0
@export_range(0.0, 5000.0, 1.0) var max_fall_speed: float = 1100.0
@export_range(0.0, 0.5, 0.01) var coyote_time: float = 0.10
@export_range(0.0, 0.5, 0.01) var jump_buffer_time: float = 0.12
var _coyote_left: float = 0.0
var _jump_buffer_left: float = 0.0
func _physics_process(delta: float) -> void:
if Input.is_action_just_pressed(&"jump"):
_jump_buffer_left = jump_buffer_time
else:
_jump_buffer_left = maxf(_jump_buffer_left - delta, 0.0)
var axis: float = Input.get_axis(&"move_left", &"move_right")
var accel: float = ground_accel if is_on_floor() else air_accel
velocity.x = move_toward(velocity.x, axis * run_speed, accel * delta)
if is_on_floor():
_coyote_left = coyote_time
else:
_coyote_left = maxf(_coyote_left - delta, 0.0)
velocity.y = minf(velocity.y + gravity * delta, max_fall_speed)
if _jump_buffer_left > 0.0 and _coyote_left > 0.0:
velocity.y = -jump_speed
_jump_buffer_left = 0.0
_coyote_left = 0.0
if Input.is_action_just_released(&"jump") and velocity.y < 0.0:
velocity.y *= 0.45
move_and_slide()
在调用 move_and_slide() 前,不要将 velocity 乘以 delta。如果必须精确控制跳跃高度,请根据目标高度和到达顶点所需时间推导重力和起跳速度,而不是分别调整两者。
设计规则
- 为了保证可玩性,碰撞尺寸应依据实际碰撞需求设定,而不是精灵图的透明区域。保持角色脚部稳定,并适当放宽战斗受击框。
- 将碰撞层视为接口。为每个图层命名,并记录哪些遮罩会使用它。
- 仅在语义状态变化时切换动画。空中状态和动作状态的优先级应高于待机/奔跑状态。
- 只在权威接收方处应用一次伤害。反馈监听器可以闪烁、抖动、生成粒子、更新 UI 或播放音频,但不得再次造成伤害。
- 冷却时间应使用计时器或累积游戏时间增量。墙上时钟时间戳不会自然遵循暂停或时间缩放。
- 仅在性能分析或规模确有需要时才使用对象池。池化节点需要明确的生成/回收重置逻辑,处理计时器、监控状态、速度、所有权和处理状态;仅设置可见性并不算完整的生命周期管理。
验证门槛
完成前:
- 运行仓库现有的测试命令;如果有兼容的 Godot 二进制文件,还要运行无头解析/导入检查。
- 确认所有引用的 Input Map 操作都已存在。
- 启用可见碰撞形状,并在运行中的场景里检查瓦片碰撞、物体形状和 Area2D 遮罩。
- 验证在已配置的物理帧率下,以及窗口或摄像机缩放发生变化后,移动是否正常。
- 验证伤害值会被限制、死亡信号只发出一次、不会攻击友方目标,并且无敌状态不会永久持续。
- 对于对象池,观察 Remote 场景树和性能分析器:对象数量应趋于稳定,复用对象的行为应与全新实例一致。
- 报告已更改的文件、已测试的场景、运行的命令,以及因缺少资源或 Godot 可执行文件而无法完成的检查。
常见故障模式
- **俯视角斜向移动更快:**使用
Input.get_vector()或限制向量长度。 - **角色速度随帧率变化:**在物理处理过程中进行移动,并且只在计算速率时使用
delta,不要将其用于最终的 CharacterBody 速度。 - **楼层状态始终为 false:**检查
up_direction、运动模式、遮罩、碰撞形状,以及move_and_slide()调用前后的顺序。 - **瓦片碰撞看起来有偏移:**对比 TileSet 瓦片尺寸、图集区域尺寸、图层变换和碰撞多边形。
- **动画闪烁:**多个分支调用了
play(),或状态优先级不明确。先确定唯一状态,再应用一次。 - **一次攻击造成多次命中:**禁用或消耗命中框、跟踪每次激活时被击中的目标,或添加接收方无敌状态。
- **快速子弹穿透目标:**使用扫掠物体/射线查询、缩短物理移动距离,或改用形状投射,而不要依赖最终位置的重叠检测。
- **抖动后摄像机未复位:**让偏移量逐渐衰减至零,并在效果结束时明确重置偏移量。
参考资料
评论
支持 Markdown