mcpField
G
godot

godot

github.com/randroids-dojo开发4542 次安装40 周前更新
代码仓库

关于 godot

用于开发、测试、构建和部署 Godot 4.x 游戏的技能,涵盖 GdUnit4 单元测试、PlayGodot 游戏自动化、Web 导出和 CI/CD 指引。

主要功能

  1. 01在 Godot 中运行 GdUnit4 测试
  2. 02使用 PlayGodot 自动化游戏
  3. 03模拟场景输入
  4. 04导出 Web 构建
  5. 05提供 CI/CD 指引

适用场景

  1. 01测试 GDScript 单元和场景
  2. 02自动执行游戏端到端测试
  3. 03将 Godot 游戏导出为 Web 版本
  4. 04在 CI 中添加 Godot 检查

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/randroids-dojo/godot-claude-skills --skill godot

安装后在 Claude Code 中输入/godot确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
assertions.md
ci-integration.md
deployment.md
gdunit4-quickstart.md
playgodot.md
scene-runner.md
scripts/
export_build.py
parse_results.py
run_tests.py
validate_project.py

详细介绍

Godot 技能

开发、测试、构建和部署 Godot 4.x 游戏。

快速参考

# GdUnit4 - Unit testing framework (GDScript, runs inside Godot)
godot --headless --path . -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --run-tests

# PlayGodot - Game automation framework (Python, like Playwright for games)
export GODOT_PATH=/path/to/godot-automation-fork
pytest tests/ -v

# Export web build
godot --headless --export-release "Web" ./build/index.html

# Deploy to Vercel
vercel deploy ./build --prod

测试概述

GdUnit4PlayGodot
类型单元测试游戏自动化
语言GDScriptPython
运行位置Godot 内部外部(类似 Playwright)
需要插件自定义 Godot 分支
适用场景单元/组件测试端到端/集成测试

GdUnit4(GDScript 测试)

GdUnit4 可直接在 Godot 内部运行以 GDScript 编写的测试。

项目结构
project/
├── addons/gdUnit4/          # GdUnit4 addon
├── test/                    # Test directory
│   ├── game_test.gd
│   └── player_test.gd
└── scripts/
    └── game.gd
设置
# Install GdUnit4
git clone --depth 1 https://github.com/MikeSchulze/gdUnit4.git addons/gdUnit4

# Enable plugin in Project Settings → Plugins
基本单元测试
# test/game_test.gd
extends GdUnitTestSuite

var game: Node

func before_test() -> void:
    game = auto_free(load("res://scripts/game.gd").new())

func test_initial_state() -> void:
    assert_that(game.is_game_active()).is_true()
    assert_that(game.get_current_player()).is_equal("X")

func test_make_move() -> void:
    var success := game.make_move(4)
    assert_that(success).is_true()
    assert_that(game.get_board_state()[4]).is_equal("X")
使用输入模拟进行场景测试
# test/game_scene_test.gd
extends GdUnitTestSuite

var runner: GdUnitSceneRunner

func before_test() -> void:
    runner = scene_runner("res://scenes/main.tscn")

func after_test() -> void:
    runner.free()

func test_click_cell() -> void:
    await runner.await_idle_frame()

    var cell = runner.find_child("Cell4")
    runner.set_mouse_position(cell.global_position + cell.size / 2)
    runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
    await runner.await_input_processed()

    var game = runner.scene()
    assert_that(game.get_board_state()[4]).is_equal("X")

func test_keyboard_restart() -> void:
    runner.simulate_key_pressed(KEY_R)
    await runner.await_input_processed()
    assert_that(runner.scene().is_game_active()).is_true()
运行 GdUnit4 测试
# All tests
godot --headless --path . -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --run-tests

# Specific test file
godot --headless --path . -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd \
  --run-tests --add res://test/my_test.gd

# Generate reports for CI
godot --headless --path . -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd \
  --run-tests --report-directory ./reports
GdUnit4 断言
# Values
assert_that(value).is_equal(expected)
assert_that(value).is_not_null()
assert_that(condition).is_true()

# Numbers
assert_that(number).is_greater(5)
assert_that(number).is_between(1, 100)

# Strings
assert_that(text).contains("expected")
assert_that(text).starts_with("prefix")

# Arrays
assert_that(array).contains(element)
assert_that(array).has_size(5)

# Signals
await assert_signal(node).is_emitted("signal_name")
场景运行器输入 API
# Mouse
runner.set_mouse_position(Vector2(100, 100))
runner.simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT)
runner.simulate_mouse_button_released(MOUSE_BUTTON_LEFT)

# Keyboard
runner.simulate_key_pressed(KEY_SPACE)
runner.simulate_key_pressed(KEY_S, false, true)  # Ctrl+S

# Input actions
runner.simulate_action_pressed("jump")
runner.simulate_action_released("jump")

# Waiting
await runner.await_input_processed()
await runner.await_idle_frame()
await runner.await_signal("game_over", [], 5000)

PlayGodot(游戏自动化)

PlayGodot 是一个适用于 Godot 的游戏自动化框架——类似 Playwright,但面向游戏。它通过原生 RemoteDebugger 协议实现端到端测试、自动化游戏操作,以及对 Godot 游戏的外部控制。

要求:

设置
# Install PlayGodot
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install playgodot

# Build custom Godot fork
git clone https://github.com/Randroids-Dojo/godot.git
cd godot && git checkout automation
scons platform=macos arch=arm64 target=editor -j8  # macOS Apple Silicon
# scons platform=macos arch=x86_64 target=editor -j8  # macOS Intel
# scons platform=linuxbsd target=editor -j8  # Linux
# scons platform=windows target=editor -j8  # Windows
测试配置(conftest.py)
import os
import pytest_asyncio
from pathlib import Path
from playgodot import Godot

GODOT_PROJECT = Path(__file__).parent.parent
GODOT_PATH = os.environ.get("GODOT_PATH", "/path/to/godot-fork")

@pytest_asyncio.fixture
async def game():
    async with Godot.launch(
        str(GODOT_PROJECT),
        headless=True,
        timeout=15.0,
        godot_path=GODOT_PATH,
    ) as g:
        await g.wait_for_node("/root/Game")
        yield g
编写 PlayGodot 测试
import pytest

GAME = "/root/Game"

@pytest.mark.asyncio
async def test_game_starts_empty(game):
    board = await game.call(GAME, "get_board_state")
    assert board == ["", "", "", "", "", "", "", "", ""]

@pytest.mark.asyncio
async def test_clicking_cell(game):
    await game.click("/root/Game/VBoxContainer/GameBoard/GridContainer/Cell4")
    board = await game.call(GAME, "get_board_state")
    assert board[4] == "X"

@pytest.mark.asyncio
async def test_game_win(game):
    for pos in [0, 3, 1, 4, 2]:  # X wins top row
        await game.call(GAME, "make_move", [pos])

    is_active = await game.call(GAME, "is_game_active")
    assert is_active is False
运行 PlayGodot 测试
export GODOT_PATH=/path/to/godot-automation-fork
pytest tests/ -v
pytest tests/test_game.py::test_clicking_cell -v
PlayGodot API
# Node interaction
node = await game.get_node("/root/Game")
await game.wait_for_node("/root/Game", timeout=10.0)
exists = await game.node_exists("/root/Game")
result = await game.call("/root/Node", "method", [arg1, arg2])
value = await game.get_property("/root/Node", "property")
await game.set_property("/root/Node", "property", value)

# Node queries
paths = await game.query_nodes("*Button*")
count = await game.count_nodes("*Label*")

# Mouse input
await game.click("/root/Button")
await game.click(300, 200)
await game.double_click("/root/Button")
await game.right_click(100, 100)
await game.drag("/root/Item", "/root/Slot")

# Keyboard input
await game.press_key("space")
await game.press_key("ctrl+s")
await game.type_text("hello")

# Input actions
await game.press_action("jump")
await game.hold_action("sprint", 2.0)

# Touch input
await game.tap(300, 200)
await game.swipe(100, 100, 400, 100)
await game.pinch((200, 200), 0.5)

# Screenshots
png_bytes = await game.screenshot()
await game.screenshot("/tmp/screenshot.png")
similarity = await game.compare_screenshot("expected.png")
await game.assert_screenshot("reference.png", threshold=0.99)

# Scene management
scene = await game.get_current_scene()
await game.change_scene("res://scenes/level2.tscn")
await game.reload_scene()

# Game state
await game.pause()
await game.unpause()
is_paused = await game.is_paused()
await game.set_time_scale(0.5)
scale = await game.get_time_scale()

# Waiting
await game.wait_for_node("/root/Game/SpawnedEnemy", timeout=5.0)
await game.wait_for_visible("/root/Game/UI/GameOverPanel", timeout=10.0)
await game.wait_for_signal("game_over")
await game.wait_for_signal("health_changed", source="/root/Game/Player")

构建与部署

Web 导出
# Requires export_presets.cfg with Web preset
godot --headless --export-release "Web" ./build/index.html
导出预设(export_presets.cfg)
[preset.0]
name="Web"
platform="Web"
runnable=true
export_path="build/index.html"
部署到 Vercel
npm i -g vercel
vercel deploy ./build --prod

CI/CD

GitHub Actions 示例
- name: Setup Godot
  uses: chickensoft-games/setup-godot@v2
  with:
    version: 4.3.0
    include-templates: true

- name: Run GdUnit4 Tests
  run: |
    godot --headless --path . \
      -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd \
      --run-tests --report-directory ./reports

- name: Upload Results
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: test-results
    path: reports/

参考资料

  • references/gdunit4-quickstart.md - GdUnit4 设置
  • references/scene-runner.md - 输入模拟 API
  • references/assertions.md - 断言方法
  • references/playgodot.md - PlayGodot 指南
  • references/deployment.md - 部署指南
  • references/ci-integration.md - CI/CD 设置

评论

支持 Markdown