{“content”:”---\nname: godot-2d-rpg\ndescription: Godot Engine 2D RPG 开发 — 安装、项目结构、RPG 核心系统(GDScript)、CLI 导出、和 custom-cli-builder 结合\nversion: 1.0.0\nauthor: Hermes\nlicense: MIT\nmetadata:\n hermes:\n tags: [godot, gamedev, 2d, rpg, gdscript]\n trigger: “需要开发 2D RPG 游戏或 Godot Engine 相关任务时”\n---\n\n# Godot 2D RPG 开发\n\n## 核心定位\n\nGodot Engine — 109k ⭐,专用 2D 引擎,GDScript(类 Python)上手快,免费开源。\n\n## 安装\n\n### Windows\npowershell\n# 下载 Godot 4.x Windows 版本(无安装器,只是一个 .exe)\n# https://godotengine.org/download/windows\n# 下载后放在 D:\\Apps\\Godot\\\n# 无需安装,直接运行\n\n# 推荐同时下载 Godot Server(无头版本,用于 CLI 导出)\n# https://godotengine.org/download/server\n\n\n### Linux/Termux\nbash\n# 下载 Godot 4.x Linux HEADLESS\nwget https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip\nunzip Godot_v4.3-stable_linux.x86_64.zip\nchmod +x Godot_v4.3-stable_linux.x86_64\nmv Godot_v4.3-stable_linux.x86_64 ~/.local/bin/godot\n\n\n## Godot CLI 核心命令\n\nbash\n# 检查 Godot 版本\ngodot --version\n\n# 在无头模式(无编辑器)运行项目(用于测试)\ngodot --headless --script-respawn\n\n# 导出项目(需要 export_presets.cfg 配置)\ngodot --headless --export-release \"Windows Desktop\" ./build/mygame.exe\ngodot --headless --export-release \"Linux/X11\" ./build/mygame.x86_64\ngodot --headless --export-release \"Web\" ./build/index.html\n\n# 仅验证项目(检查脚本错误)\ngodot --headless --check-only --script-respawn\n\n# 快速运行(编辑器模式)\ngodot --path ~/my_rpg_game --editor\n\n\n## 2D RPG 核心系统(GDScript)\n\n### 项目结构\n\nmy_rpg/\n├── project.godot # 项目配置\n├── scenes/\n│ ├── main.tscn # 主场景\n│ ├── player.tscn # 玩家角色\n│ ├── world.tscn # 地图\n│ └── ui/\n│ └── hud.tscn # HUD\n├── scripts/\n│ ├── player.gd # 玩家控制器\n│ ├── world.gd # 地图逻辑\n│ ├── inventory.gd # 背包系统\n│ └── dialogue.gd # 对话系统\n├── assets/\n│ ├── sprites/\n│ ├── tilesets/\n│ └── fonts/\n└── export_presets.cfg # 导出配置\n\n\n### 基础 Player 控制器(复制到 scripts/player.gd)\ngdscript\nextends CharacterBody2D\n\n@export var speed: float = 200.0\n\nfunc _physics_process(delta: float) -> void:\n var direction := Input.get_vector(\"left\", \"right\", \"up\", \"down\")\n velocity = direction * speed\n move_and_slide()\n \n # 动画处理\n if direction.length() > 0:\n $AnimatedSprite2D.play(\"walk\")\n $AnimatedSprite2D.flip_h = direction.x < 0\n else:\n $AnimatedSprite2D.play(\"idle\")\n\n\n### 简易背包系统(scripts/inventory.gd)\ngdscript\nextends Node\n\nsignal inventory_changed\n\nvar items: Array[Dictionary] = []\n\nfunc add_item(item_name: String, quantity: int = 1) -> void:\n for item in items:\n if item[\"name\"] == item_name:\n item[\"quantity\"] += quantity\n inventory_changed.emit()\n return\n items.append({\"name\": item_name, \"quantity\": quantity})\n inventory_changed.emit()\n\nfunc remove_item(item_name: String, quantity: int = 1) -> bool:\n for i in items.size():\n if items[i][\"name\"] == item_name:\n items[i][\"quantity\"] -= quantity\n if items[i][\"quantity\"] <= 0:\n items.remove_at(i)\n inventory_changed.emit()\n return true\n return false\n\nfunc has_item(item_name: String) -> bool:\n return items.any(func(item): return item[\"name\"] == item_name)\n\n\n### 对话系统(scripts/dialogue.gd)\ngdscript\nextends Node\n\n@export var dialogue_lines: Array[String] = []\nvar current_line: int = 0\n\nsignal dialogue_finished\n\nfunc start() -> void:\n current_line = 0\n show_line()\n\nfunc next() -> void:\n current_line += 1\n if current_line >= dialogue_lines.size():\n dialogue_finished.emit()\n else:\n show_line()\n\nfunc show_line() -> void:\n # 连接 UI 层的 Label 节点显示对话\n var label = get_tree().get_first_node_in_group(\"dialogue_label\")\n if label:\n label.text = dialogue_lines[current_line]\n\n\n## RPG 框架推荐\n\n| 框架 | ⭐ | 用途 |\n|------|----|------|\n| skelerealms | 443 | 开放世界 RPG 框架 |\n| Rakugo | 325 | 叙事驱动游戏(类 Ren’Py) |\n| minenice55/Snowdon-Engine | 18 | Pokemon 风格 RPG 框架 |\n\n## CLI 自动化(custom-cli-builder 方法)\n\n用 custom-cli-builder 的思路封装 Godot CLI:\n\npython\n# godot_cli.py — Godot 项目管理 CLI\nimport click\nimport subprocess\nimport os\nfrom pathlib import Path\n\nGODOT_PATH = \"godot\" # 或完整路径\n\n@click.group()\ndef cli():\n \"\"\"Godot RPG 项目管理 CLI\"\"\"\n pass\n\n@cli.command()\n@click.argument(\"project_path\")\n@click.option(\"--preset\", default=\"Windows Desktop\", help=\"导出目标平台\")\n@click.option(\"--output\", default=\"./build\", help=\"输出目录\")\ndef export(project_path: str, preset: str, output: str) -> None:\n \"\"\"导出游戏到指定平台\"\"\"\n os.makedirs(output, exist_ok=True)\n output_file = f\"{output}/game\"\n result = subprocess.run(\n [GODOT_PATH, \"--headless\", \"--export-release\", preset, output_file],\n cwd=project_path,\n capture_output=True, text=True\n )\n if result.returncode == 0:\n click.echo(f\"✅ 导出成功: {output_file}\")\n else:\n click.echo(f\"❌ 导出失败: {result.stderr}\", err=True)\n\n@cli.command()\n@click.argument(\"project_path\")\ndef check(project_path: str) -> None:\n \"\"\"检查项目脚本错误\"\"\"\n result = subprocess.run(\n [GODOT_PATH, \"--headless\", \"--check-only\"],\n cwd=project_path,\n capture_output=True, text=True\n )\n click.echo(result.stdout or result.stderr)\n\n@cli.command()\n@click.argument(\"project_path\")\ndef run(project_path: str) -> None:\n \"\"\"在编辑器中运行项目\"\"\"\n subprocess.run([GODOT_PATH, \"--path\", project_path, \"--editor\"])\n\nif __name__ == \"__main__\":\n cli()\n\n\n## Windows 远程执行(SSH)\n\nbash\n# 通过 SSH 在 PC 上执行 Godot 导出(PC 上已安装 Godot)\nssh -i ~/.ssh/id_ed25519 sozo@100.83.112.84 \\\n \"powershell -Command 'D:\\\\Apps\\\\Godot\\\\Godot --headless --export-release \\\"Windows Desktop\\\" C:\\\\Users\\\\Sozo\\\\my_rpg\\\\build\\\\game.exe'\"\n\n\n## 验证步骤\n\n1. godot --version — 确认安装\n2. godot --path /path/to/project --editor — 打开编辑器\n3. 创建 2D 场景,添加 Sprite + CharacterBody2D\n4. 运行测试 — godot --headless --check-only\n5. 导出 — godot --headless --export-release \"Windows Desktop\" ./build/game.exe\n\n## 已知问题 & 解决\n\n- 导出失败: 确保 export_presets.cfg 存在于项目根目录\n- 中文路径问题: Godot 对中文路径支持一般,项目建议放在纯英文路径下\n- Windows HEADLESS: 下载 Godot_v4.x-stable_win.exe(server 版本)用于 CI 导出\n\n## ⚠️ 关键陷阱:Autoload 与场景节点路径\n\nAutoload singleton 不是场景的子节点。 如果 GameManager 是 autoload,它和 Main(场景根节点)是 平级 的,不能直接用相对路径访问 scene 节点。\n\n### ❌ 错误做法(GameManager autoload 中):\ngdscript\nfunc _ready() -> void:\n # 失败!TitleScreen 不是 GameManager 的子节点\n var btn = get_node(\"TitleScreen/StartButton\")\n btn.pressed.connect(_on_start_pressed) # btn 是 null,崩溃或静默失败\n\n\n### ✅ 正确做法(从场景根节点访问):\nGameManager 不需要直接持有 UI 引用,让 scene 自己处理:\ngdscript\n# GameManager.gd — 不要在 autoload 里 get_node 场景节点!\n# 用信号来解耦\nfunc _on_start_pressed() -> void:\n change_state(GameState.EXPLORING)\n\n\n让主场景的脚本连接按钮:\ngdscript\n# main.gd — Main 节点上挂的脚本\nfunc _ready() -> void:\n $TitleScreen/StartButton.pressed.connect(_on_start_pressed)\n\nfunc _on_start_pressed() -> void:\n GameManager.change_state(GameManager.GameState.EXPLORING)\n $TitleScreen.visible = false\n\n\n或者用 get_tree() 全局查找(不推荐,脆弱):\ngdscript\nvar btn = get_tree().get_first_node_in_group(\"start_button\")\n\n\n## Windows PC 远程调试(从 Termux 操作)\n\nbash\n# 1. 查看 PC 上 Godot 项目文件\nssh -i ~/.ssh/id_ed25519 sozo@100.83.112.84 \\\n \"powershell -Command \\\"Get-ChildItem 'D:\\\\games\\\\EchoesOfTheGreen' -Recurse -Include *.gd,*.tscn,project.godot | Format-Table FullName -AutoSize\\\"\"\n\n# 2. 读取玩家脚本\nssh -i ~/.ssh/id_ed25519 sozo@100.83.112.84 \\\n \"powershell -Command \\\"Get-Content 'D:\\\\games\\\\EchoesOfTheGreen\\\\scripts\\\\player.gd'\\\"\"\n\n# 3. 读取主场景\nssh -i ~/.ssh/id_ed25519 sozo@100.83.112.84 \\\n \"powershell -Command \\\"Get-Content 'D:\\\\games\\\\EchoesOfTheGreen\\\\scenes\\\\main.tscn'\\\"\"\n\n# 4. 远程执行 Godot 检查(PC 上需有 godot CLI)\nssh -i ~/.ssh/id_ed25519 sozo@100.83.112.84 \\\n \"powershell -Command \\\"& 'D:\\\\Apps\\\\Godot\\\\Godot.exe' --headless --check-only --path 'D:\\\\games\\\\EchoesOfTheGreen'\\\"\"\n\n\n## 调试移动 Bug 的思路\n\n玩家不移动 → 检查 player.gd_physics_process 是否被调用:\n1. 打印调试:print(\"EXPLORING:\", GameManager.current_state == GameManager.GameState.EXPLORING)\n2. 检查 GameManager.current_state 是否卡在 TITLE\n3. 如果是 TITLE → 回到 game_manager.gd 找 StartButton 连接是否成功\n4. 如果 StartButton 是 null → 参考上面的”Autoload 路径陷阱”\n\n## 角色美化工作流\n\n1. 用 Stable Diffusion 生成像素风格角色 sprite sheet\n2. 上传到 PC:scp -i ~/.ssh/id_ed25519 ./player_sprites.png sozo@100.83.112.84:\"D:/games/EchoesOfTheGreen/assets/sprites/\"\n3. 在 Godot Editor 里导入,设置 Sprite2D.texture 为新图片\n4. 添加 AnimatedSprite2D 子节点,配置 Idle/Walk 动画帧\n”}