- 示例工程
【免费下载链接】godot-demo-projects
Demonstration and Template Projects
导读
本文基于 godot-demo-projects 仓库中的 misc/2.5d/README.md 及其配套源码,系统讲解一种在 Godot 中创建 2.5D 游戏的完整思路:通过自定义插件引入Node25D、YSort25D、ShadowMath25D三类节点,以「3D 节点算数学、2D 精灵做渲染」的方式混合使用 2D 与 3D,并配套一个 2.5D 专用编辑器视口用于直观地编辑关卡。读完本文,你将掌握 2.5D 变换矩阵的构成与六种视角模式(俯视、正面、45 度、等距、两种斜轴)的实现原理,以及如何用该插件快速搭建可运行、可排序、带阴影的 2.5D 场景。
项目概览:这是什么,以及它如何运行
这是一个使用 GDScript 编写、采用Compatibility(GL 兼容)渲染器的官方演示项目,工程配置见 project.godot(renderer/rendering_method="gl_compatibility")。它的核心观点非常明确:
2.5D 游戏 = 用 3D 节点做物理与数学计算,用 2D 节点做最终渲染。
具体来说,整个项目的摄像头是 2D 的,所有精灵(Sprite)也是 2D 的;而 3D 节点(CharacterBody3D、StaticBody3D等)只负责提供数学位置与碰撞计算,并不会被真正渲染。这种「借 3D 的算力、出 2D 的画面」的设计,让开发者能继续享受 2D 工作流(2D 相机、2D 精灵、2D 着色器)的同时,获得 3D 空间中的真实深度信息,用于排序与投影。
本项目的 GDScript 版本位于 misc/2.5d,仓库中还提供了对应的 C# 版本(mono/2.5d),供使用 Godot C# 的开发者对照学习。
插件结构:三类自定义节点是如何注册的
所有核心代码都封装在一个名为 Node25D 的编辑器插件中,目录结构如下:
- 插件入口:node25d_plugin.gd
- 插件声明:plugin.cfg
- 核心节点:node_25d.gd
- 排序节点:y_sort_25d.gd
- 阴影节点:shadow_math_25d.gd
- 编辑器视口:viewport_25d.gd
插件在进入编辑器时通过add_custom_type注册三个自定义类型(node25d_plugin.gd):
| 自定义类型 | 基类 | 作用 |
|---|---|---|
Node25D | Node2D | 所有 2.5D 对象的基类,负责 3D→2D 坐标换算 |
YSort25D | Node(注意不是 Node2D/Node25D) | 对父节点下所有 2D 子节点按深度排序 |
ShadowMath25D | ShapeCast3D | 向下发射形状投射,计算并放置阴影 |
同时插件注册了一个主屏幕(_has_main_screen()返回true),名为"2.5D",对应编辑器中的 2.5D 视口面板。
核心原理:Node25D 与 2.5D 变换矩阵
节点的层级约定
Node25D的用法遵循一个严格约定(README 明确说明):
- 第一个子节点必须是一个 3D 节点(如
Node3D、CharacterBody3D、StaticBody3D),它只用来计算位置; - 再添加一个 2D 精灵(
Sprite2D或类似节点)用来显示对象外观。
在 node_25d.gd 的Node25D_ready()中,节点会直接取get_child(0)作为_spatial_node,即第一个 3D 子节点;所有 2D 精灵则作为后续子节点,跟随父节点一起移动。
2.5D 变换矩阵
位置换算的核心是一组由三个Vector2构成的基向量(_basisX、_basisY、_basisZ),它们把 3D 世界坐标的 X、Y、Z 三个轴分别映射到屏幕上的 2D 方向。换算逻辑在Node25D_process()中(node_25d.gd):
var flat_pos = _spatial_position.x * _basisX flat_pos += _spatial_position.y * _basisY flat_pos += _spatial_position.z * _basisZ global_position = flat_pos其中SCALE常量定义了1 个 3D 单位对应多少 2D 像素,默认值为 32(node_25d.gd)。注释特别建议该值最好是整数(不强制),因为整数缩放能让精灵在不同视角下的投影更整齐。修改Node25D_ready()中的三个基向量即可改变所有Node25D实例的默认视角。
值得一提的是,源码注释还解释了为什么不用一个自定义结构体Basis25D而是用三个裸Vector2:早期 GDScript 无法把自定义类型用作内部成员结构(见 node_25d.gd 中引用的引擎 issue),因此这里采用了展开存储的写法,便于直接扩展。
六种视角模式
set_view_mode(view_mode_index)用match语句切换六套基向量(node_25d.gd):
| 索引 | 视角 | _basisX | _basisY | _basisZ |
|---|---|---|---|---|
| 0 | 45 度(Forty Five Degrees) | (1, 0) | (0, -0.7071) | (0, 0.7071) |
| 1 | 等距(Isometric) | (0.8660, 0.5) | (0, -1) | (-0.8660, 0.5) |
| 2 | 俯视(Top Down) | (1, 0) | (0, 0) | (0, 1) |
| 3 | 正面(Front Side) | (1, 0) | (0, -1) | (0, 0) |
| 4 | 斜轴 Y(Oblique Y) | (1, 0) | (-0.7071, -0.7071) | (0, 1) |
| 5 | 斜轴 Z(Oblique Z) | (1, 0) | (0, -1) | (-0.7071, 0.7071) |
注意表格中的数值均需乘以SCALE(32)。其中 45 度与等距视角大量使用0.70710678118(√2/2)与0.86602540378(√3/2)这类三角常数,这正是标准等距投影的几何基础。
_check_view_mode()(node_25d.gd)会在非编辑器环境下轮询输入动作(forty_five_mode、isometric_mode、top_down_mode、front_side_mode、oblique_y_mode、oblique_z_mode),实时切换视角。这些输入动作在 project.godot 的[input]段中定义,对应键盘快捷键分别为 U、I、O、J、K、L。README 强调:要实现自定义视角,只需在 Node25D 中定义一组新的基向量并应用到所有实例,再为对象准备对应视角的 2D 精灵即可——这在本项目中被反复验证(见下文精灵实现)。
深入实操:从精灵到角色再到阴影
2D 精灵如何适配多种视角
2.5D 的核心难点之一是同一对象在不同视角下应有不同的外观。仓库对此给出了完整解法:每个精灵节点都预加载全部六张视角贴图,并在视角切换时替换。
以平台精灵 platform_sprite.gd 为例,它预加载了 assets/platform/textures 下的forty_five.png、isometric.png、top_down.png、front_side.png、oblique_y.png、oblique_z.png六张贴图,set_view_mode()中通过match把texture换成对应贴图。角色精灵 player_sprite.gd 与阴影精灵 shadow_sprite.gd 采用相同的模式。
角色精灵更进一步:除了换贴图,它还会修改精灵自身的 2D 变换(transform.x/transform.y),让角色画面在俯视时压扁(y 缩放 0.5)、45 度视角时轻微压扁(y 缩放 0.75)等(player_sprite.gd),从而在多个视角下都显得自然。它还基于_check_movement()返回的八方向_direction与地面检测(move_and_collide向下探测)在「站立 / 奔跑 / 跳跃」三张贴图间切换动画帧(player_sprite.gd)。
3D 节点只做数学:角色移动与平台碰撞
角色的数学体是 player_math_25d.gd(class_name PlayerMath25D),它继承CharacterBody3D但自身永远不可见,仅承担移动计算:
- 水平移动:
Input.get_vector读取 WASD 输入,组合出 3D 方向后通过move_and_slide()驱动;速度默认 10,按住movement_modifier(Shift)时减半; - 垂直移动:跳跃时
vertical_speed = 60,每帧受重力240 * delta影响,再用move_and_collide(Vector3.UP * vertical_speed * delta)检测落地; - 特别地,等距视角下它会把 WASD 映射为斜 45 度的对角线方向(
isometric_controls逻辑,player_math_25d.gd),并可通过toggle_isometric_controls(T 键)切换为标准方向控制。
场景中的平台则使用StaticBody3D+BoxShape3D作为数学体,例如 demo_scene.tscn 中每个PlatformX节点下都有PlatformMath(StaticBody3D)与PlatformSprite(Sprite2D)两个子节点,严格遵循「3D 数学 + 2D 显示」的约定。这也印证了 README 的说法——任何 3D 节点都可以用来做数学计算。
2.5D 编辑器视口:边看 2D 边编辑 3D 坐标
README 提到项目「添加了一个 2.5D 编辑器视口,方便编辑 2.5D 关卡」。该视口由 viewport_25d.gd 实现,是插件主屏幕的核心:
- 共享 2D 世界:视口内的
SubViewport与当前编辑场景共用同一个world_2d,因此编辑器视口里看到的正是游戏运行时 2D 层的真实画面(viewport_25d.gd); - 视角按钮联动:顶栏的视角按钮组(45 Degree / Isometric / Top Down 等)切换后,
_recursive_change_view_mode会递归遍历整个场景树,调用每个节点的set_view_mode(viewport_25d.gd); - 缩放与平移:鼠标滚轮缩放(每级缩放倍率为 2 的 13 次根
1.05476607648,即 13 级翻倍),中键拖拽平移,且支持选中节点 gizmo 的同步缩放(viewport_25d.gd)。
由于Node25D暴露了spatial_position(@export var spatial_position: Vector3,见 node_25d.gd),在编辑器里修改该导出属性即可直接调整对象的 3D 坐标,随后 2D 位置会立即按当前基向量重新投影——这正是「2.5D 关卡编辑」的落地方式。
深度排序:YSort25D
为了让靠近屏幕下方的对象遮挡上方的对象(经典 2D 伪深度),插件提供了YSort25D。它直接继承Node,挂在某个 2D 父节点下,对该父节点的所有Node2D子节点排序(y_sort_25d.gd):
- 收集父节点下所有
Node2D子节点; - 用
Node25D.y_sort_slight_xz做自定义排序比较——该比较器以 Y 为主键,并叠加0.001 * (x + z)的微小权重来消解同高度歧义(node_25d.gd); - 按排序结果依次设置
z_index,从-4000 开始、每次递增 2。
关于步长与上限,源码注释给出了明确约束:Godot 的z_index取值范围是 -4096 到 4096,步长 2 是为了给阴影在相邻物体之间留出插入空间(阴影的z_index为 -3958,正好夹在物体之间,见 demo_scene.tscn),因此单个YSort25D最多可排序 4000 个节点,超过会打印错误并中止(y_sort_25d.gd)。
sort_enabled导出变量控制是否在_process中自动排序,也可以手动调用sort()方法。
阴影计算:ShadowMath25D
README 描述阴影为「一个试图向下投射的简单 CharacterBody」。实际实现 shadow_math_25d.gd 继承自ShapeCast3D,使用方式非常特殊:
- 它作为
Shadow25D的子节点,而Shadow25D位于目标对象之前的兄弟位置(不是子节点)——即在场景树中,阴影节点排在目标对象的下一个兄弟; _ready()中通过索引取前一个兄弟节点,再取其第一个 3D 子节点作为投射目标(shadow_math_25d.gd);若位置不对会输出push_error;_physics_process中把自身position对齐到目标 3D 位置,调用force_shapecast_update()强制更新形状投射,若is_colliding()则把阴影global_position移到碰撞点并显示,否则隐藏阴影(shadow_math_25d.gd)。
也就是说,阴影的「高度」由 ShapeCast3D 朝 -Y(向下)的射线命中决定,落地则显示、悬空则隐藏,从而实现了对角色跳跃/平台落差的实时响应。在 demo_scene.tscn 中,Player25D(z_index = -3956)与Shadow25D(z_index = -3958)紧邻,正好满足上述兄弟关系约定。
场景搭建实战:读懂 demo_scene
assets/demo_scene.tscn 是演示主场景,其结构完整展示了插件的全部用法,同时它也是 project.godot 中配置的主场景(run/main_scene="res://assets/demo_scene.tscn"):
DemoScene (Node2D) ├── Overlay (UI 操作提示, assets/ui/overlay.tscn) ├── Player25D (Node25D) z_index = -3956 │ ├── PlayerMath25D (CharacterBody3D) ← 数学 │ └── PlayerSprite (Sprite2D) ← 显示 ├── Shadow25D (Node25D) z_index = -3958 │ ├── ShadowMath25D (ShapeCast3D) ← 投射 │ └── ShadowSprite (Sprite2D) ├── Platform0 … Platform23 (Node25D) z_index = -3952 … -4000 │ ├── PlatformMath (StaticBody3D + CollisionShape3D) │ └── PlatformSprite (Sprite2D) ├── YSort25D (Node) └── AudioStreamPlayer (assets/mr_mrs_robot.ogg)从源码结构可以推断,各平台节点的z_index已被 YSort25D 按深度赋值为从 -3952 到 -4000 的递减序列,且阴影 z_index 恰好落在相邻平台之间——这与 YSort25D「步长 2 为阴影留位」的设计完全吻合。
主场景还包含一个立方体演示(assets/cube/cube.tscn + cube_math.gd):脚本在_ready()中生成 27 个Node3D数学点(坐标为 -1/0/1 的 3×3×3 组合乘以 5),_process中通过 Q/E、A/D、W/S 旋转整个立方体数学体,并把 27 个点同步给父节点的 2D 精灵(cube_math.gd),直观演示了「任意 3D 几何都能被投影成 2.5D 画面」。按 C 键可在主场景与立方体场景间切换,按 Esc 退出。
工程配置与运行方式
项目的主要工程配置(project.godot)要点如下:
- 渲染器:
gl_compatibility(桌面与移动端一致),纹理过滤关闭(default_texture_filter=0,保证像素风精灵锐利); - 物理:
physics_ticks_per_second=120,即物理运算以 120Hz 进行,配合 3D 数学体获得更平滑的碰撞与投射结果; - 窗口:1600×900,
canvas_items拉伸模式 +expand宽高比; - 输入映射:WASD/方向键移动、Shift 减速、Space 跳跃、R 复位、C 切换立方体演示、T 切换等距控制、U/I/O/J/K/L 切换六种视角、Esc 退出;
- 插件:
editor_plugins/enabled=PackedStringArray("res://addons/node25d/plugin.cfg")启用 Node25D 插件。
运行方式:用 Godot 4.x(工程特征为 4.7)导入本目录并直接运行主场景即可。若要在自己的项目中使用,只需把 addons/node25d 整个目录复制到项目的addons/下,并在 Project Settings → Plugins 中启用 Node25D,之后即可在场景中直接添加Node25D、YSort25D、ShadowMath25D节点。
运行效果一览
六种视角下游戏运行画面分别见 screenshots/forty_five.png、screenshots/isometric.png、screenshots/oblique_z.png、screenshots/oblique_y.png、screenshots/front_side.png 与 screenshots/cube.png。以下两张分别展示等距与 45 度视角下的实际运行场景(分层平台、角色与阴影):
总结:这套方案给你的启发
从 misc/2.5d/README.md 与配套源码可以提炼出三条可直接复用的设计经验:
- 职责分离是 2.5D 的灵魂:3D 节点(CharacterBody3D/StaticBody3D/ShapeCast3D)只负责数学与物理,2D 节点(Sprite2D/Node2D)只负责渲染,二者通过
Node25D的基向量矩阵桥接; - 视角是一种可插拔配置:六种视角本质只是三组
Vector2基向量 + 六套对应贴图,扩展新视角只需追加基向量与精灵资源; - 深度与阴影可以全自动:
YSort25D按 Y 坐标(含轻微 X/Z 扰动)排序并预留阴影层级,ShadowMath25D用形状投射实时计算落点,让 2.5D 场景保持 2D 式的简单组织方式。
该项目同时提供 GDScript(misc/2.5d)与 C#(mono/2.5d)两个版本,是学习 Godot 混合 2D/3D 工作流、实现伪 3D 视角游戏的良好参考起点。
附:资源许可
背景音乐assets/mr_mrs_robot.ogg版权归 Juan Linietsky(约 2008 年),采用 CC-BY 署名许可协议(见 misc/2.5d/README.md 的 Music license 一节),使用或再分发时需保留原作者署名。
- 示例工程
【免费下载链接】godot-demo-projects
Demonstration and Template Projects
相关推荐
Godot 2.5D 游戏开发实战:基于 mono/2.5d 演示项目的 C 插件实现解析
Godot 2.5D 游戏开发实战:基于 mono/2.5d 演示项目的 C 插件实现解析 2.5D 是经典而实用的视觉表现手法:让游戏对象拥有三维的空间逻辑,
示例工程从3.5到4.0:Godot引擎2.5D演示项目迁移实战指南
从3.5到4.0:Godot引擎2.5D演示项目迁移实战指南 Godot引擎从3.5版本到4.0版本的更新带来了显著的架构变化,特别是在2D/3D混合渲染系统和
示例工程melonJS 3D 功能初探:WebGL 基础与 2.5D 游戏实现
melonJS 3D 功能初探:WebGL 基础与 2.5D 游戏实现 melonJS 是一个轻量级的 HTML5 游戏引擎,专注于 2D 游戏开发。尽管主要定
游戏开发图形学
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考