最近在折腾游戏 Demo 时,想快速生成一个六边形地块地图,刚好看到 Summer Engine(基于 Godot)和 Codex 这类 AI 编程工具的组合用法。网上资料比较零散,今天就把这套从环境准备到最终跑通的完整流程整理出来,包含 GDScript 代码、常用坐标系原理解析,以及 Codex CLI 在实际开发中的配置和排错思路。
如果你正在学习 Godot,想尝试程序化生成地图,或者打算用 AI 工具辅助写游戏逻辑,这篇教程都可以直接参考。
1. 背景与核心概念
1.1 什么是 Summer Engine,和 Godot 是什么关系
Summer Engine 是一套基于 Godot 的游戏开发框架。它复用了 Godot 的节点、场景和 GDScript 脚本体系,所以你在 Summer Engine 中写代码的方式和原生 Godot 几乎一致。本文中的示例以 Godot 4 的语法为主,Summer Engine 底层 API 与之兼容,因此你完全可以把这套流程迁移到 Summer Engine 项目里。
如果你只接触过 Unity 或 Cocos,可以把 Godot 理解成一个开源的游戏引擎,而 Summer Engine 更像是引擎之上的项目模板或扩展包。六边形地块生成这件事,核心并不依赖引擎本身,而是依赖游戏引擎提供的节点、渲染和坐标系统。
1.2 为什么需要程序化生成六边形地块
六边形地块在很多策略游戏、回合制战棋、模拟经营游戏里都很常见,比如《文明》系列中的地图。相比于正方形网格,六边形网格更接近“圆”,每个格子到相邻格子的距离是一致的,对角争议更少,地图视觉上更自然。
手动摆放六边形显然不现实,几十上百个地块一个个拖节点会让人崩溃。程序化生成就是通过代码按规则创建节点、计算坐标、设置样式,让地图可以无限扩展,也能在运行时动态变化。这也是当前游戏开发中比较常见的需求。
1.3 Codex 在开发流程中的角色
Codex 是 OpenAI 推出的编程智能体工具,可以通过自然语言指令生成代码、解释代码、修改文件,甚至直接运行命令。本文中我们用它来生成六边形地块的基础生成逻辑,然后人工校对和调整。
需要说明的是,Codex 只是一个辅助工具,它生成的代码需要你理解后接入项目,尤其是涉及坐标系、节点类型和场景结构时,要结合项目实际情况修改,不能无脑复制。
2. 环境准备与版本说明
2.1 准备 Godot / Summer Engine 环境
本文示例使用 Godot 4.x 版本,推荐使用 4.2 以上版本,因为部分 API 和编辑器体验更稳定。Summer Engine 如果安装了独立版本,请确认其内置的 Godot 版本,避免语法差异。
你可以从 Godot 官网下载标准版或 .NET 版。本文使用 GDScript,不需要 .NET 版本,标准版即可。
操作系统:Windows / macOS / Linux 均可。命令行操作以 Windows 示例为主,Mac/Linux 差异不大。
2.2 安装 Codex CLI
Codex CLI 是运行在终端中的编程助手。根据官方文档,安装方式通常是通过 npm 全局安装:
npm install -g @openai/codex安装前需要确保 Node.js 环境正常,建议使用 Node.js 18 以上版本。
安装完成后,需要配置 OpenAI API Key,或者通过 Codex 登录流程完成认证。不同版本的交互方式有差异,请以你安装的版本为准。
2.3 示例项目结构规划
为了后续演示方便,我们规划一个简单的项目结构:
hex-demo/ ├── project.godot ├── scenes/ │ └── Main.tscn ├── scripts/ │ ├── HexGrid.gd │ └── HexTile.gd └── assets/ └── icons/(可选)这里HexGrid.gd负责生成整个六边形网格,HexTile.gd负责单个地块的显示逻辑。
3. 六边形网格生成核心原理
在写代码之前,先理解六边形网格的坐标系统。这一步很关键,坐标系搞错了,生成的网格就会错位。
3.1 偏移坐标 vs 轴向坐标
最直观的六边形网格坐标是“偏移坐标”,类似二维数组的行列号,比如(col, row)。每个格子用整数坐标表示,实现简单,但计算相邻格子时需要区分“奇数行偏移”和“偶数行偏移”,容易出错。
另一种更优雅的方式是“轴向坐标”(axial coordinates),用(q, r)表示:q代表列,r代表行。轴向坐标的相邻格子计算很简单,数学性质更好,生成六边形地块时推荐使用。
3.2 轴向坐标与像素坐标转换
要把逻辑坐标变成屏幕上的像素位置,需要一个转换公式。对于点顶型(pointy-top)六边形,假设六边形的外接圆半径为size:
# 将轴向坐标 (q, r) 转换为像素位置 func axial_to_pixel(q: int, r: int, size: float) -> Vector2: var x = size * sqrt(3) * (q + r * 0.5) var y = size * 3.0 / 2.0 * r return Vector2(x, y)这里sqrt(3)来自正六边形的几何关系。如果你使用平顶型(flat-top)六边形,公式会不同。
3.3 六边形顺时针邻居方向
轴向坐标下,六边形的六个邻居方向固定为:
const axial_directions = [ Vector2i(1, 0), Vector2i(1, -1), Vector2i(0, -1), Vector2i(-1, 0), Vector2i(-1, 1), Vector2i(0, 1), ]这个方向表是后续实现寻路、区域判定、地块相邻判断的基础。
3.4 为什么程序化生成要优先使用轴向坐标
因为轴向坐标在计算六边形之间的距离、画线、旋转时,需要的数学公式更简洁。比如两个六边形格子(q1, r1)和(q2, r2)的立方体距离公式为:
func hex_distance(a: Vector2i, b: Vector2i) -> int: var ac = cube_from_axial(a) var bc = cube_from_axial(b) return max(abs(ac.x - bc.x), abs(ac.y - bc.y), abs(ac.z - bc.z))虽然看起来需要转换成立方体坐标,但整个逻辑非常清晰,出错的概率低。
4. 完整实战案例:Codex 辅助生成六边形地块
现在开始搭建完整 demo。为了让过程更贴近真实项目,我会把 Codex 的使用穿插其中,展示如何利用自然语言生成代码,并最终落实到 Godot 场景中。
4.1 创建 Godot 项目
打开 Godot,新建项目,项目名称写HexDemo,渲染器选择 Forward Plus 或 Mobile 都可以。如果你用的是 Summer Engine,请按 Summer Engine 的新建项目流程操作,本质是一样的。
创建完成后,在项目根目录创建scenes和scripts文件夹。
4.2 用 Codex 生成六边形网格脚本
在终端中进入项目目录,启动 Codex:
codex然后在 Codex 对话中,用自然语言描述需求:
请帮我写一个 Godot 4 的 GDScript 脚本,类名是 HexGrid。 要求: 1. 支持在场景中生成 n 圈的六边形地块。 2. 使用轴向坐标 (q, r)。 3. 每个地块是一个 Polygon2D 节点,正六边形形状,半径可配置。 4. 地块颜色随机。 5. 提供 axial_to_pixel 坐标转换函数。Codex 会生成一个类似下面的脚本。不过 AI 生成的结果可能不完美,你需要理解并手动修正。
我把常见的实现整理成了稳定的版本,你可以直接参考。
文件路径:scripts/HexGrid.gd
extends Node2D class_name HexGrid @export var grid_radius: int = 3 @export var hex_size: float = 50.0 @export var tile_color: Color = Color(0.6, 0.8, 1.0) var hex_points: PackedVector2Array func _ready() -> void: _build_hex_points() _generate_grid() # 根据半径计算六边形的六个顶点 func _build_hex_points() -> void: hex_points.clear() for i in range(6): var angle_deg = 60 * i - 30 var angle_rad = deg_to_rad(angle_deg) var point = Vector2(cos(angle_rad), sin(angle_rad)) * hex_size hex_points.append(point) # 在轴向坐标范围内生成地块 func _generate_grid() -> void: for q in range(-grid_radius, grid_radius + 1): var r_min = max(-grid_radius, -q - grid_radius) var r_max = min(grid_radius, -q + grid_radius) for r in range(r_min, r_max + 1): _create_tile(Vector2i(q, r)) # 创建单个六边形地块 func _create_tile(coords: Vector2i) -> void: var tile = Polygon2D.new() tile.polygon = hex_points tile.position = axial_to_pixel(coords.x, coords.y, hex_size) tile.color = tile_color.saturated(randf() * 0.3 + 0.7) add_child(tile) # 轴向坐标转像素坐标 func axial_to_pixel(q: int, r: int, size: float) -> Vector2: var x = size * sqrt(3) * (q + r * 0.5) var y = size * 3.0 / 2.0 * r return Vector2(x, y)核心逻辑说明:
_build_hex_points:预先计算正六边形的六个顶点,避免每个地块重复计算。_generate_grid:遍历轴向坐标。r_min和r_max的计算逻辑保证了生成的是一个六边形区域,而不是正方形。_create_tile:创建Polygon2D,设置多边形顶点和位置,并添加到当前节点下。saturated函数是 Godot 中 Color 的方法,用于调整颜色饱和度。这里是随机让地块颜色有些变化,让效果更清楚。
如果你希望在区块之间有间隔,可以调整hex_size,或者在坐标转换时乘以一个偏移系数。
4.3 创建主场景
在 Godot 编辑器中:
- 新建场景,根节点选择
Node2D,命名为Main。 - 添加子节点
HexGrid。 - 把根节点的脚本设置为
scripts/HexGrid.gd。
因为HexGrid.gd声明了grid_radius和hex_size作为导出变量,你可以在属性面板中调整数值。保存场景到scenes/Main.tscn。
4.4 运行验证
按下 F6 或点击运行按钮,你应该能看到一个由 3 圈六边形地块组成的蜂窝状地图。如果地图偏移到屏幕外,可以调整hex_size或修改Main节点的位置。
如果你想显示地块坐标,可以继续让 Codex 生成一个Label节点:
请帮我扩展 HexGrid,让每个地块显示自己的轴向坐标 (q, r),使用 Label 节点,字体大小 16,颜色黑色。生成代码后,你需要把Label挂到Polygon2D下面,并调整Label的偏移和大小。
4.5 用代码控制地块颜色
程序化生成不只是“摆出形状”,还要让每个地块具备独立的属性。下面扩展一个功能:根据坐标设置不同地块类型(比如草地、森林、水域),用颜色区分。
新增一个枚举和地图配置:
enum TileType { GRASS, FOREST, WATER } const type_colors := { TileType.GRASS: Color(0.4, 0.8, 0.3), TileType.FOREST: Color(0.2, 0.6, 0.1), TileType.WATER: Color(0.3, 0.6, 1.0), }然后在_create_tile中,通过一个函数判断地块类型:
func _get_tile_type(coords: Vector2i) -> TileType: var dist_from_center = max(abs(coords.x), abs(coords.y), abs(coords.x + coords.y)) if dist_from_center <= 1: return TileType.WATER elif (coords.x + coords.y * 2) % 3 == 0: return TileType.FOREST else: return TileType.GRASS这里的dist_from_center是简单的六边形距离计算,用来生成中心水域效果。你可以换成噪声函数、高度图或者随机数。
把TileType映射到颜色后,运行项目,就会得到有初步地形区分的地图。
5. 常见问题与排查思路
在实际操作中,我最常被问到的问题集中在两个方面:一是 Codex 工具本身的问题,二是 Godot 生成六边形地块的显示问题。
5.1 Codex CLI 相关错误
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
启动时报unable to locate the codex cli binary | Codex CLI 未安装,或 PATH 配置不正确 | 重新执行npm install -g @openai/codex,检查 npm 全局 bin 目录是否在 PATH 中 |
| Codex 在 IDE 插件中无法连接 | 插件配置中的 Codex CLI 路径不对 | 在插件设置中手动指定 codex 可执行文件的绝对路径 |
| 请求接口报模型不支持 | 账号未开通对应模型权限,或配置了不支持的自定义模型 | 检查 Codex 配置中的模型名称,换用当前账号支持的模型 |
| 网络请求失败或响应超时 | 本地网络环境、代理设置异常 | 检查网络连接,调整 CLI 的网络代理配置 |
对于unable to locate the codex cli binary,最常见的解决方法是:
# 查看 codex 安装位置 which codex # 如果 which 找不到,检查 npm 全局目录 npm prefix -g然后把这个目录加入系统 PATH。如果你在 IDE 插件中使用 Codex,直接把codex的绝对路径填到插件设置里。
如果遇到set codex cli path的提示,说明你使用的客户端(比如某些 AI 编辑器)没有自动发现 Codex,需要手动配置路径。
5.2 Godot 六边形生成相关问题
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 生成的地块重叠或间隙过大 | 坐标转换公式与六边形方向不匹配 | 检查是点顶型还是平顶型,使用对应公式 |
| 地块渲染锯齿严重 | 项目渲染设置或缩放问题 | 开启 MSAA,或把纹理过滤设置为线性,适当提高画面缩放 |
| 颜色随机但变化太刺眼 | 随机值直接赋给颜色,缺少约束 | 限制随机方差,或基于地块类型设置基础色 |
| 地块数量多时卡顿 | 每个地块生成独立 Polygon2D,节点过多 | 使用 MultiMeshInstance2D 或单节点绘制 |
如果地块数量达到几千甚至上万,建议不要为每个地块创建独立节点。可以使用MultiMeshInstance2D,或者直接用_draw()在单个节点上绘制所有多边形。这样性能会提升很多。
6. 最佳实践与工程建议
6.1 生成逻辑与渲染逻辑分离
在程序化生成中,我建议把“地块数据”和“地块显示”分开。比如定义HexTileData,只保存坐标、类型、高度、资源数量等逻辑数据;然后再用一个渲染器根据数据创建节点。这样后期如果要改成网格寻路、保存存档、网络同步,都不会被节点结构绑死。
6.2 使用代码生成而不是手摆节点
即使地图不大,也建议用脚本生成地块。理由:
- 可配置性强,改一个半径参数就能生成不同大小地图。
- 可复现性好,相同随机种子得到相同地图。
- 便于自动化测试。
6.3 合理使用 Codex,但不盲从
Codex 可以快速生成骨架代码,但你要有能力判断它的输出是否正确。尤其要注意:
- 是否使用了目标版本不存在的 API。
- 是否忽略了节点生命周期。
- 是否有内存泄漏风险(比如大量新建节点后没有释放)。
一个建议是:让 Codex 生成代码后,先在最小场景中运行一次,确认没有红色报错,再扩展功能。对于错误信息,直接贴给 Codex,让它解释和修复,这样效率非常高。
6.4 性能优化方向
如果以后要做大世界地图,优先考虑:
- 使用分块(chunk)加载,只渲染视野范围内的地块。
- 用
TileMapLayer或者MultiMesh渲染地块。 - 把地块数据保存在数组或字典中,用坐标
Vector2i作为 key,方便查询。
下面是一个简单的分块思路示例:
const CHUNK_SIZE := 8 var chunks := {} func _chunk_key(coords: Vector2i) -> Vector2i: return Vector2i( floori(coords.x / float(CHUNK_SIZE)), floori(coords.y / float(CHUNK_SIZE)) )按块管理后,可以只对可见块执行生成和渲染,同时保留整张地图的数据。
6.5 代码命名与结构规范
GDScript 中,类名使用大驼峰,函数名使用下划线小驼峰,常量使用全大写。这已经是 Godot 社区的主流规范。示例中的HexGrid、_generate_grid都遵循了这个习惯。
对于地图生成这类偏数据的系统,建议把脚本写在单独的scripts目录,并按功能模块分组,避免所有逻辑都堆在Main.gd中。
7. 总结与学习路线
到这里,你已经通过 Godot(Summer Engine)和 Codex 完成了一个可运行的六边形地块生成 Demo。整个过程覆盖了:
- 六边形网格的轴向坐标与像素坐标转换。
- 使用 GDScript 生成六边形地块并渲染。
- 通过 Codex CLI 辅助生成和扩展代码。
- 常见错误提示的排查思路。
下一步,你可以继续学习方向包括:
- 基于六边形网格的寻路算法(A* 是首选)。
- 地块地形类型、资源分布和随机种子系统。
- 使用噪声生成自然风格地图。
- 将地块数据导出为 JSON,用于关卡编辑器。
如果你对 Codex 的实际使用还有困惑,可以先从“让 Codex 解释一段代码”开始,不急着让它直接生成大模块。理解能力永远比生成速度更重要。
希望这篇教程能帮你少踩一些坑。如果你在实际操作中遇到了其他问题,欢迎在评论区留言,我们一起讨论。