Godot程序化生成六边形地块:从轴向坐标到Codex AI辅助实践
游戏地图里的六边形地块看起来是典型的“硬核算法”话题。网格坐标、邻接关系、噪声、随机种子每一步都劝退一波人。但换个角度想如果你只是想快速看到一个能跑的六边形地图 demo这件事并没有想象中那么难。尤其在 Godot 这类引擎里六边形生成的核心代码甚至可以压到一百行以内。真正麻烦的反而是工程流程环境怎么配、脚本挂到哪个节点、AI 编程工具怎么参与进来而不是帮倒忙。这篇文章就围绕“用 Summer EngineGodot Codex 制作程序化生成六边形地块的 demo”展开把算法实现和 AI 辅助开发两条线串起来。读完你会得到三样东西一个可以直接跑起来的六边形地块生成器一套用 Codex CLI 辅助游戏 demo 开发的工作方法以及一张常见问题的避坑清单。如果你是刚接触 Godot、又对 AI 辅助编程感兴趣这篇文章应该能帮你少走不少弯路。1. 这篇文章真正要解决的问题先聊痛点。程序化生成地形在很多开发者心里的印象是“算法门槛高、调试成本大”。你想做一张不重样的地图过去得先翻 Red Blob Games 那篇著名的六边形网格教程再自己推导坐标变换最后还要处理边缘、颜色、噪声。等代码跑通半天已经过去了。现在有了 Codex 这类 AI 编程助手流程可以压缩很多。但 AI 辅助开发有一个隐藏问题如果你自己都不知道要什么AI 生成的代码也很难对。它可能给你一段看起来很完整、一运行却报错的脚本也可能生成一个在 Godot 3 里能跑、在 Godot 4 里直接崩溃的版本。所以这篇文章要解决的不只是“怎么生成六边形地块”而是三个叠加的问题第一六边形网格的数学模型怎么落到 GDScript 里第二Codex CLI 怎么安装、怎么配置、怎么让它生成可用的脚本第三AI 生成的代码如何验证、调试和演进。最应该读这篇文章的读者有两类。一类是刚接触 Godot 的开发者想快速做出一个“看起来还行”的程序化地图 demo另一类是已经在用 AI 辅助编程但总在环境配置和任务拆解上浪费时间的工程实践者。前者可以学到基础算法后者可以学到一套更稳妥的 AI 协作流程。2. Summer Engine、Godot、Codex 与程序化生成的核心概念2.1 Summer Engine 是什么从项目命名和使用方式来看Summer Engine 是一个以 Godot 为底层的游戏开发工程或发行版项目。它延续了 Godot 的 GDScript API、场景树和导出流程因此在 Summer Engine 里写六边形地块生成本质上就是在写 Godot 脚本。这篇文章不打算深挖 Summer Engine 与 Godot 的底层差异因为对一个 demo 项目而言真正的运行环境仍然是 Godot 编辑器与 GDScript 运行时。你只需要关注两点第一引擎版本是否基于 Godot 4第二GDScript 语法是否与 Godot 4 一致。只要这两点成立本文的代码在 Summer Engine 中就能直接复用。如果后续遇到引擎差异最稳妥的验证方式是打开 Summer Engine 的项目设置检查脚本语言插件和版本信息。不要盲目相信“引擎兼容所有 Godot 版本”这句话项目文件之间的差异往往就藏在细节里。2.2 Codex CLI 是什么Codex CLI 是 OpenAI 推出的命令行编程代理工具目前主要以 npm 包形式分发。安装后你可以直接在终端里执行codex命令启动一个交互式会话通过自然语言描述需求它会读取工作区文件、生成代码 diff、执行命令甚至把结果直接写入项目文件。它的价值不在于“帮你写一段代码”而在于“帮你完成一个需要上下文连贯的工程任务”。比如你给它一个需求“在 scripts 目录下创建 hex_grid.gd挂到 Node2D 上用 Polygon2D 画六边形”它会先理解项目结构再生成适合当前引擎版本的脚本最后尽量保证代码和项目目录风格一致。但 Codex 也有明显的边界。它不理解你公司的规范也不理解游戏设计的隐性需求。如果 prompt 里没有写清楚“地图半径是多少、地块颜色怎么分配、坐标怎么换算”它生成的代码大概率只是“能跑”而不是“符合你的预期”。这也是这篇文章反复强调“任务拆解”的原因。2.3 程序化生成六边形地块的基本原理程序化生成地块可以拆成三层理解。第一层是“坐标系统”。六边形网格有两种常见方向尖顶pointy-top和平顶flat-top。尖顶六边形的左侧和右侧是顶点平顶六边形的上下是顶点。本文采用尖顶六边形因为它在纵向排列上更符合常规地图的视觉习惯。第二层是“网格布局”。六边形网格不能像矩形网格那样用二维数组直接表示因为相邻行的六边形会发生错位。标准做法是用轴向坐标axial coordinates表示也就是用(q, r)两个整数标记格子同时隐含第三个坐标s -q - r。这样相邻格子的判断、距离计算、地图范围裁剪都变得非常简洁。第三层是“地块类型”。在网格坐标确定之后你可以根据坐标生成一个伪随机数把地块分成草地、森林、水域、沙地、岩石等类型。为了让每次运行结果保持一致可以使用确定性哈希而不是真正的随机数。这样调试时地图不会因为一次刷新而完全变化。三层逻辑对应三段代码坐标转换函数、网格循环逻辑、颜色分配函数。后面第 5 章的完整脚本就是把这三段组合起来。3. 环境准备与前置条件3.1 安装 Godot 与准备项目本文以 Godot 4.x 为基准环境。在动手之前请先确认自己的 Godot 版本。Godot 4 和 Godot 3 在 GDScript 类型系统和部分 API 上有差异比如PackedVector2Array、export等特性都是 Godot 4 引入或强化的。安装完成后新建一个空项目项目名称可以叫HexDemo。创建成功后建议在项目根目录下先建好两个文件夹scenes用来放场景文件scripts用来放 GDScript 脚本。结构如下HexDemo/ ├── project.godot ├── scenes/ └── scripts/这个结构不复杂但对后期维护很重要。AI 生成的代码通常只会写脚本本身不会帮你规划目录所以目录结构最好由你先定好。3.2 安装并配置 Codex CLICodex CLI 需要 Node.js 环境。如果你本地还没有 Node.js需要先安装 LTS 版本。安装完成后通过 npm 全局安装 Codexnpm install -g openai/codex安装完成后验证是否成功codex --version如果命令找不到说明 npm 的全局 bin 目录还没有加到系统 PATH 中。在 Windows 上可以检查用户环境变量在 macOS 和 Linux 上可以检查 shell 配置文件。接下来需要配置 API Key。Codex CLI 运行时需要读取认证信息一般通过环境变量OPENAI_API_KEY提供export OPENAI_API_KEY你的 API Key注意API Key 属于敏感信息不要写进项目代码或提交到 Git 仓库。更推荐的方式是放在本地 shell 配置文件中或者 Codex 支持的配置文件里。3.3 验证 Codex 是否可用配置完成后可以先运行一次最小测试确认 Codex 能正常调用。最简单的验证方式是启动一个交互会话codex进入交互模式后输入一句非常明确的话用 Python 打印 hello codex然后退出。如果配置正常Codex 会创建或修改文件、执行命令并显示运行结果。如果这一步就报错先不要急着进入 Godot 项目因为问题大概率出在环境变量、网络连通性或依赖安装上。验证通过后再把 Codex 的工作目录切换到 HexDemo 项目目录中。建议用cd HexDemo后再启动 Codex这样它读取的就是我们这个项目的文件结构。4. 用 Codex 拆解六边形地块 demo 的任务4.1 先写人话需求很多人在使用 AI 编程工具时上来就问“帮我做一个六边形地图”然后抱怨生成结果不理想。问题不在 AI而在需求太模糊。正确的拆法是把最终目标拆成三个独立步骤第一步生成六边形网格第二步绘制每个六边形第三步给不同坐标分配不同颜色。每一步都是一个可以单独验证的小任务。在给 Codex 的第一次 prompt 中我建议先只提第一步和第二步codex 在 Godot 4 项目中创建 scripts/hex_grid.gd挂在 Node2D 上使用 Polygon2D 渲染一个半径为 5 的六边形网格每个六边形半径为 48。这个 prompt 里包含了足够的技术约束脚本路径、节点类型、渲染方式、地图半径和六边形尺寸。Codex 生成后先运行一次看网格是否正常再升级需求。4.2 让 Codex 生成核心算法网格能正常显示后再让 Codex 加颜色分配逻辑。这个阶段的关键是“一次只加一个功能”。不要在一个 prompt 里要求它同时完成颜色、噪声、边缘高亮和点击交互因为功能越多出错后越难定位。第二次 prompt 可以这样写codex 在 hex_grid.gd 中补充 pick_color 函数按轴向坐标 q、r、s 取哈希值把 0-99 映射到 5 种地块颜色草地、森林、水域、沙地、岩石。如果 Codex 生成的代码不符合 Godot 4 的语法比如用了 Godot 3 的写法你可以直接告诉它“请使用 Godot 4 的 GDScript 语法”它会重新生成。4.3 把 AI 生成结果收进项目Codex 可以直接修改项目文件也可以只输出代码片段。对 demo 项目来说更稳妥的方式是让它把脚本写到scripts/hex_grid.gd然后你在 Godot 编辑器中手动创建一个 Node2D 场景把脚本挂上去。这个“手动挂载”的步骤很关键。AI 能生成脚本但在 Godot 中创建一个场景并完成节点绑定仍然需要你对引擎操作足够熟悉。换句话说Codex 负责解决“算法怎么表达”的问题你负责解决“游戏引擎怎么组织内容”的问题。两者结合才能跑通整个 demo。5. 六边形地块生成的完整代码实现5.1 项目结构与场景准备在 Godot 编辑器中新建一个场景根节点选择Node2D命名为Main。然后在scripts目录下新建脚本hex_grid.gd并把脚本挂载到Main节点上。场景结构如下Main (Node2D) └── 脚本: hex_grid.gd脚本挂载后运行场景即可看到生成结果。如果你的项目还没有scenes目录可以先把场景保存到scenes/main.tscn。5.2 轴向坐标与六边形顶点计算先说坐标转换。在尖顶六边形布局中六边形的中心点坐标可以由轴向坐标(q, r)换算得到。设六边形的外接圆半径为radius中心坐标的计算公式为x sqrt(3) * radius * (q r * 0.5) y 1.5 * radius * r这个公式的含义是每一行的六边形在垂直方向只移动半径的 1.5 倍而水平方向因为有错位所以r会使中心点额外偏移一半的横向间距。绘制单个六边形时需要计算六个顶点。以中心点为中心每隔 60 度取一个顶点。起始角度选择 -30 度可以让尖顶六边形的上方出现一个尖角视觉上更符合常见的策略游戏地图。GDScript 中对应的函数如下。# 文件路径scripts/hex_grid.gd片段 func axial_to_world(q: int, r: int, radius: float) - Vector2: var x : radius * sqrt(3.0) * (q r * 0.5) var y : radius * 1.5 * r return Vector2(x, y) func hex_vertices(center: Vector2, radius: float) - PackedVector2Array: var vertices : PackedVector2Array() for i in range(6): var angle : deg_to_rad(60 * i) - deg_to_rad(30) var offset : Vector2(radius * cos(angle), radius * sin(angle)) vertices.append(center offset) return verticesdeg_to_rad是 Godot 内置函数负责把角度转成弧度避免手写PI / 180带来的精度问题。5.3 生成随机地块类型有了坐标和顶点下一步就是生成整片地块。地图的形状是一个正六边形范围为-map_radius到map_radius。判断一个格子是否在地图范围内的条件很简单abs(q r) map_radius。在范围内遍历所有轴向坐标为每个坐标创建一个Polygon2D节点设置其polygon属性为六边形顶点然后根据坐标分配颜色。为了让地图在多次运行之间保持不变这里采用确定性的坐标哈希函数而不是直接调用randi()。哈希函数会基于q、r、s产生一个介于 0 到 99 之间的值再映射到不同的地块类型。# 文件路径scripts/hex_grid.gd片段 func pick_color(q: int, r: int) - Color: var s : -q - r var value : (q * 383 r * 719 s * 151 color_seed) % 100 if value 40: return color_pool[0] # 草地 elif value 60: return color_pool[4] # 森林 elif value 75: return color_pool[3] # 水域 elif value 90: return color_pool[1] # 沙地 else: return color_pool[2] # 岩石这里的color_seed是一个可调参数默认取 42。修改它可以在保持“确定性”的前提下生成一张完全不同的地图。5.4 完整 hex_grid.gd 脚本把前面的函数组合起来再加上必要的导出变量就是一个可以直接运行的完整脚本。# 文件路径scripts/hex_grid.gd extends Node2D export var map_radius: int 5 export var hex_radius: float 48.0 export var color_seed: int 42 var color_pool: Array[Color] [ Color(0.44, 0.72, 0.42), # 草地 Color(0.78, 0.75, 0.55), # 沙地 Color(0.52, 0.52, 0.58), # 岩石 Color(0.25, 0.55, 0.78), # 水域 Color(0.20, 0.50, 0.25) # 森林 ] func _ready() - void: generate_grid() func axial_to_world(q: int, r: int, radius: float) - Vector2: var x : radius * sqrt(3.0) * (q r * 0.5) var y : radius * 1.5 * r return Vector2(x, y) func hex_vertices(center: Vector2, radius: float) - PackedVector2Array: var vertices : PackedVector2Array() for i in range(6): var angle : deg_to_rad(60 * i) - deg_to_rad(30) var offset : Vector2(radius * cos(angle), radius * sin(angle)) vertices.append(center offset) return vertices func generate_grid() - void: for q in range(-map_radius, map_radius 1): for r in range(-map_radius, map_radius 1): if abs(q r) map_radius: continue var center : axial_to_world(q, r, hex_radius) var hex : Polygon2D.new() hex.polygon hex_vertices(center, hex_radius) hex.color pick_color(q, r) add_child(hex) func pick_color(q: int, r: int) - Color: var s : -q - r var value : (q * 383 r * 719 s * 151 color_seed) % 100 if value 40: return color_pool[0] elif value 60: return color_pool[4] elif value 75: return color_pool[3] elif value 90: return color_pool[1] else: return color_pool[2]这段代码的关键逻辑有三处axial_to_world负责坐标换算hex_vertices负责把坐标变成可见的六个顶点generate_grid负责把整片六边形地块实例化到场景树中。三者之间没有复杂耦合理解和修改都很直观。如果你使用的是 Godot 3.x需要把Array[Color]改为普通数组写法例如var color_pool [...]。这是两个版本之间比较明显的语法差异。6. 运行结果与效果验证6.1 运行项目在 Godot 编辑器中打开scenes/main.tscn点击运行按钮或者按 F6 直接运行当前场景。如果一切正常你会看到一片由 91 个六边形组成的彩色地图整体轮廓呈现为一个标准正六边形。运行结果可以这样判断第一地图中央有一颗六边形周围按 6、12、18、24、30 的数量逐层向外扩展第二相邻六边形之间没有明显缝隙或重叠第三颜色分布看起来随机但每次运行结果一致。6.2 通过参数调整验证如果在编辑器中修改hex_grid.gd上的导出变量再运行场景效果会立刻变化。这是验证脚本是否正常工作的最快方式。建议做三个实验第一把map_radius从 5 改成 8观察地块数量是否明显增加第二把hex_radius从 48 改成 32观察地块是否变小、间距是否变小第三把color_seed从 42 改成 100观察整片地图的颜色分布是否发生变化。如果所有实验都符合预期说明脚本的“坐标系统、网格循环、颜色分配”三个环节都已经打通。6.3 运行失败时先看的三个位置如果地图没有出现建议按顺序检查第一Godot 编辑器底部的输出面板是否有脚本报错第二场景面板中Main节点下是否生成了多个Polygon2D子节点第三脚本文件是否成功挂载到节点上。绝大多数运行失败都是因为脚本没有挂载、或者脚本文件与场景不在同一层目录导致的。这类问题与算法无关优先排查工程组织层面的错误。7. 常见问题与排查思路问题现象可能原因排查方式解决方案终端执行 codex 提示 unable to locate the codex cli binary某些桌面集成工具或编辑器插件在调用 Codex CLI 时没有找到可执行文件路径在终端执行 codex --version 确认 CLI 是否已安装检查集成工具中的 Codex 路径设置重新安装 Codex CLI确认 bin 目录已加入 PATH在集成工具中手动指定 codex 可执行文件路径codex 命令不存在npm 全局 bin 目录未加入 PATH执行 npm prefix -g 查看全局目录将全局 bin 目录加入系统 PATH或重装 Node.js 后重新安装Godot 脚本报错 “Cannot assign property ‘polygon’”可能使用了 Godot 3 语法或 Polygon2D 节点未正确初始化查看输出面板的完整错误行确认脚本使用 Godot 4 语法确认变量类型是 Polygon2D而不是 Node2D六边形之间有明显缝隙顶点角度计算错误或者中心坐标换算公式用错打印 hex_vertices 输出对照公式检查确认起始角度为 -30 度横向间距使用 sqrt(3) * radius每次运行地图颜色变化使用了随机数生成器且没有固定种子检查 pick_color 中是否使用了 randi改用基于 q、r、s 的确定性哈希Codex 生成代码一直用 Godot 3 语法prompt 中没有明确指定引擎版本检查提示中是否写明 Godot 4在 prompt 中追加“请使用 Godot 4 的 GDScript 语法”地图太大导致运行卡顿Polygon2D 节点数量过多检查地图半径和性能监视器改用 TileMap、MultiMesh 或自定义绘制减少场景树节点数量从社区反馈看最容易被忽视的是第一行问题。“unable to locate the codex cli binary”这句话通常不是 Codex 本身报错而是某个桌面工具在尝试调用 Codex CLI 时找不到二进制文件。排查重点不是“Codex 能不能用”而是“调用方有没有从正确的路径找到 Codex”。8. 最佳实践与工程建议8.1 AI 辅助开发的任务颗粒度与 Codex 协作时任务拆得越小成功率越高。核心经验是一次只让 AI 完成一个可验证的功能点而不是让它一次性生成整个游戏系统。以本文的六边形地块为例正确的任务顺序是先让它生成一个“只画六边形网格”的脚本运行通过后再加颜色逻辑再加地图半径参数最后才考虑交互或生成噪声。每加一个功能都手动运行一次把问题控制在最小范围内。还有一个容易踩坑的地方是让 AI “优化整个项目结构”。这种任务通常会让 Codex 动很多文件改出一些你完全没预料到的东西。更稳妥的做法是给它明确的文件路径和函数名让它只修改指定范围。8.2 命名、目录与场景组织Godot 项目虽然灵活但在 AI 辅助开发的背景下目录和命名规范反而更重要。因为 Codex 没有全局记忆它判断上下文主要依赖当前工作区的文件结构。一个杂乱的项目AI 生成代码时经常猜错路径。建议在项目一开始就固定三个规则脚本统一放scripts目录场景统一放scenes目录脚本文件名与主要功能保持一致。这样你给 Codex 的 prompt 里可以直接写路径减少歧义。导出变量也建议统一使用export而不是写死在代码里。这样你可以不修改脚本就在编辑器里调节地图半径、地块尺寸、颜色种子等参数。对于 demo 项目来说能随时调整参数比代码写得多漂亮更重要。8.3 性能与扩展方向当前脚本用Polygon2D节点表示每个六边形优点是直观、易调试缺点是节点数量太多会影响性能。当map_radius达到 10 以上时六边形数量会超过 300 个达到 30 时数量接近 2800 个。对于 demo 来说可以接受但如果是正式项目需要换成更高效的渲染方式。更推荐的路线是继续使用轴向坐标做逻辑层但把渲染层换为TileMap或MultiMesh。逻辑层和渲染层分离是程序化生成项目扩展的基本思路。后续可以继续深挖的方向包括六边形邻居查询与寻路、地块高度与噪声结合、地块点击选中与高亮、地图导出与存档序列化。每一条都可以用“先拆任务再交给 Codex最后手动验证”的方式继续推进。9. 总结整个 demo 做下来最值得记住的不是某一行算法而是“AI 辅助开发”这件事的正确打开方式。Codex 擅长把模糊的需求翻译成代码但它不知道你的引擎版本、项目结构和审美偏好。你必须负责把需求描述清楚把结果验证到位。六边形地块生成本身是一个很好的练习项目因为它涉及坐标系统、数学变换、场景树组织、渲染节点和随机分布等多个知识点但每个知识点又不会复杂到让人崩溃。当你跑通这个 demo 后相当于同时掌握了 Godot 程序化生成的基础流程以及 Codex CLI 的基本使用方法。建议你把这份脚本保存成自己的模板下次需要做网格类、地图类或策略类游戏原型时可以直接基于这个结构继续开发。对于 AI 辅助编程我的建议只有一句话不要让它替你思考要让它替你节省把想法变成代码的时间。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →