mcpField
G
godot-project-setup

godot-project-setup

github.com/jame581开发889184 次安装4 天前更新
代码仓库

关于 godot-project-setup

面向 Godot 4.3+ 开发者的项目搭建技能,提供目录结构、项目设置、自动加载节点和版本控制配置指南,并兼顾 GDScript 与 C# 项目。

主要功能

  1. 01拆分式与按功能组织目录
  2. 02项目显示与拉伸设置
  3. 03可重绑定的输入映射
  4. 04GameManager 等自动加载节点
  5. 05Git 忽略与属性规则
  6. 06C# 项目配置检查项

适用场景

  1. 01为新游戏项目创建基础目录
  2. 02配置输入操作和窗口显示
  3. 03规划全局管理器与事件总线
  4. 04为 Git 设置文本和二进制规则

安装

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

$npx skills add https://github.com/jame581/godotprompter --skill godot-project-setup

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

详细介绍

Godot 项目设置

此技能用于搭建一个新的 Godot 4.3+ 项目,包含推荐的目录结构、项目设置、自动加载项和版本控制配置。

相关技能: scene-organization 用于组织场景树,event-bus 用于 EventBus 自动加载项模式,save-load 用于 SaveManager 自动加载项模式。

推荐目录结构(分离式布局)

分离式布局将资源、场景和脚本分别放在顶层目录中。这种布局适用于中大型项目,并且便于按类型查找资源。

res://
├── assets/
│   ├── audio/
│   │   ├── music/
│   │   └── sfx/
│   ├── fonts/
│   ├── shaders/
│   ├── sprites/
│   │   ├── characters/
│   │   ├── environment/
│   │   └── ui/
│   └── textures/
├── scenes/
│   ├── autoloads/
│   ├── characters/
│   ├── environment/
│   ├── levels/
│   ├── screens/
│   └── ui/
├── scripts/
│   ├── autoloads/
│   ├── characters/
│   ├── components/
│   ├── resources/
│   └── ui/
├── resources/
│   ├── items/
│   ├── levels/
│   └── themes/
└── addons/

为什么使用分离式布局?

  • 艺术家管理的资源可以独立更新,无需改动脚本目录。
  • 导出预设中的 glob 模式更简单(assets/** 与 scripts/** 保持分离)。
  • 更容易按目录配置 .gitattributes 二进制规则。
  • 适用于艺术家和程序员分工协作的团队。

替代方案:共置式结构

对于个人项目或小型团队,可以按功能将场景和脚本放在一起。整体迁移某个功能更容易,但应用二进制 gitattributes 规则更困难。

res://
├── assets/
│   ├── audio/
│   ├── fonts/
│   └── textures/
├── entities/
│   ├── player/
│   │   ├── player.tscn
│   │   ├── player.gd          # or Player.cs
│   │   └── player_state.gd
│   └── enemy/
│       ├── enemy.tscn
│       └── enemy.gd
├── levels/
│   ├── level_01/
│   │   ├── level_01.tscn
│   │   └── level_01.gd
│   └── main_menu/
│       ├── main_menu.tscn
│       └── main_menu.gd
├── systems/
│   ├── inventory/
│   └── dialogue/
├── autoloads/
├── resources/
└── addons/

.gitignore

# Godot editor data — never commit
.godot/

# Export artifacts
*.apk
*.aab
*.ipa
*.exe
*.x86_64
*.x86_32
*.arm32
*.arm64
*.pck
*.zip
export/

# C# / Mono build output
.mono/
.import/
bin/
obj/
*.csproj.user
*.sln.user
*.user

# IDE and OS files
.vs/
.vscode/settings.json
.idea/
*.swp
.DS_Store
Thumbs.db

# GodotPrompter (if used in-project)
.godot-prompter-cache/

.gitattributes

规范文本文件的行尾格式,并将二进制资源标记出来,避免 Git 尝试对它们执行文本差异比较。

# Default: normalize line endings to LF on commit
* text=auto eol=lf

# Godot-specific text files
*.gd text eol=lf
*.gdshader text eol=lf
*.gdshaderinc text eol=lf
*.tscn text eol=lf
*.tres text eol=lf
*.godot text eol=lf
*.cfg text eol=lf
*.import text eol=lf

# C# source
*.cs text eol=lf
*.csproj text eol=lf
*.sln text eol=lf

# Binary assets — no diff, no merge, no EOL conversion
*.png binary
*.jpg binary
*.jpeg binary
*.webp binary
*.svg binary
*.psd binary
*.aseprite binary
*.wav binary
*.ogg binary
*.mp3 binary
*.ttf binary
*.otf binary
*.woff binary
*.woff2 binary
*.glb binary
*.gltf binary
*.blend binary
*.fbx binary
*.mp4 binary
*.ogv binary

项目设置

在 Project > Project Settings 中配置这些设置,或直接编辑 project.godot。

显示
设置推荐值说明
display/window/size/viewport_width1920基础分辨率 — 美术参考尺寸
display/window/size/viewport_height1080
display/window/stretch/modecanvas_items缩放 2D 内容;如需像素级精准显示,请使用 viewport
display/window/stretch/aspectkeep添加信箱框/柱箱框;expand 则填满屏幕
display/window/size/resizabletrue允许在桌面端调整窗口大小

像素艺术项目请使用 stretch/mode = viewport,并在根 CanvasItem 上设置 texture_filter = nearest,或通过 rendering/textures/canvas_textures/default_texture_filter 全局设置。

Godot 4.7+: 在 Godot 4.7 中新建的项目默认已将 display/window/stretch/mode 设为 canvas_items,将 display/window/stretch/aspect 设为 expand(之前分别为 disabled/keep),因此只有在想要使用 keep 的信箱框效果时才需要更改 aspect。在旧版本中创建的项目会保留现有值 — 升级时请明确设置这两项。

输入映射

请在 Project > Project Settings > Input Map 中定义操作,而不是硬编码按键常量。这样玩家就能在运行时重新绑定控制按键。

GDScript — 读取输入操作:

# Good: action-based (rebindable)
func _process(delta: float) -> void:
    var direction := Input.get_axis("move_left", "move_right")
    if Input.is_action_just_pressed("jump"):
        _jump()

# Avoid: hard-coded key checks
func _input(event: InputEvent) -> void:
    if event is InputEventKey and event.keycode == KEY_SPACE:
        _jump()

C# — 读取输入操作:

// Good: action-based (rebindable)
public override void _Process(double delta)
{
    float direction = Input.GetAxis("move_left", "move_right");
    if (Input.IsActionJustPressed("jump"))
        Jump();
}

// Avoid: hard-coded key checks
public override void _Input(InputEvent @event)
{
    if (@event is InputEventKey key && key.Keycode == Key.Space)
        Jump();
}

在运行时保存和还原自定义绑定(GDScript):

func save_bindings() -> void:
    var config := ConfigFile.new()
    for action in InputMap.get_actions():
        if action.begins_with("ui_"):
            continue  # skip built-in UI actions
        var events := InputMap.action_get_events(action)
        config.set_value("bindings", action, events)
    config.save("user://bindings.cfg")

func load_bindings() -> void:
    var config := ConfigFile.new()
    if config.load("user://bindings.cfg") != OK:
        return
    for action in config.get_section_keys("bindings"):
        InputMap.action_erase_events(action)
        for event in config.get_value("bindings", action):
            InputMap.action_add_event(action, event)

在运行时保存和还原自定义绑定(C#):

public void SaveBindings()
{
    var config = new ConfigFile();
    foreach (StringName action in InputMap.GetActions())
    {
        if (((string)action).StartsWith("ui_"))
            continue; // skip built-in UI actions
        var events = InputMap.ActionGetEvents(action);
        config.SetValue("bindings", action, events);
    }
    config.Save("user://bindings.cfg");
}

public void LoadBindings()
{
    var config = new ConfigFile();
    if (config.Load("user://bindings.cfg") != Error.Ok)
        return;
    foreach (string action in config.GetSectionKeys("bindings"))
    {
        InputMap.ActionEraseEvents(action);
        var events = (Godot.Collections.Array)config.GetValue("bindings", action);
        foreach (InputEvent @event in events)
            InputMap.ActionAddEvent(action, @event);
    }
}

自动加载项

在 Project > Project Settings > Globals > Autoload 中注册自动加载项。自动加载项是可通过其注册名称全局访问的单例节点。

常见自动加载项
名称路径用途
GameManagerautoloads/game_manager.gd游戏状态、场景切换、暂停
EventBusautoloads/event_bus.gd解耦的信号中继
AudioManagerautoloads/audio_manager.gd音乐、音效、音量控制
SaveManagerautoloads/save_manager.gd保存/加载游戏数据

保持自动加载项精简。将逻辑移到独立类中,再从自动加载项调用它们。

最简 GameManager — GDScript
# autoloads/game_manager.gd
extends Node

signal scene_changed(scene_path: String)
signal game_paused(is_paused: bool)

var current_level: String = ""
var is_paused: bool = false


func change_scene(path: String) -> void:
    current_level = path
    scene_changed.emit(path)
    get_tree().change_scene_to_file(path)


func set_paused(paused: bool) -> void:
    is_paused = paused
    get_tree().paused = paused
    game_paused.emit(paused)


func quit_game() -> void:
    get_tree().quit()
最简 GameManager — C#
// autoloads/GameManager.cs
using Godot;

public partial class GameManager : Node
{
    [Signal]
    public delegate void SceneChangedEventHandler(string scenePath);

    [Signal]
    public delegate void GamePausedEventHandler(bool isPaused);

    public string CurrentLevel { get; private set; } = "";
    public bool IsPaused { get; private set; }

    public void ChangeScene(string path)
    {
        CurrentLevel = path;
        EmitSignal(SignalName.SceneChanged, path);
        GetTree().ChangeSceneToFile(path);
    }

    public void SetPaused(bool paused)
    {
        IsPaused = paused;
        GetTree().Paused = paused;
        EmitSignal(SignalName.GamePaused, paused);
    }

    public void QuitGame() => GetTree().Quit();
}
最简 EventBus — GDScript
# autoloads/event_bus.gd
extends Node

# Declare all cross-system signals here.
# Systems emit to EventBus; listeners connect to EventBus.

signal player_died
signal item_collected(item_id: String, quantity: int)
signal score_changed(new_score: int)
signal level_completed(level_id: String)

节点可通过以下方式连接:

EventBus.player_died.connect(_on_player_died)
EventBus.player_died.emit()

C# 项目设置

.csproj

启用 C# 支持后,Godot 会生成一个 .csproj。请保持其精简,并将目标框架设为 net8.0:

<Project Sdk="Godot.NET.Sdk/4.3.0">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net8.0</TargetFramework>
    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <RootNamespace>MyGame</RootNamespace>
  </PropertyGroup>
</Project>

将 MyGame 替换为你的项目名称。命名空间可自由定义;Godot 要求的是类名与文件名相同(Player.cs → class Player)。

partial class 要求

所有继承 Godot 类型的 C# 类都必须声明为 partial。Godot 的源代码生成器会在配套的 partial 文件中添加注册代码。

// Correct
public partial class Player : CharacterBody2D { }

// Wrong — build error GD0001: missing partial modifier
public class Player : CharacterBody2D { }
命名空间约定

项目使用单一根命名空间。子命名空间可选,但应保持层级简洁:

namespace MyGame.Characters;   // OK
namespace MyGame.UI;           // OK
namespace MyGame.Systems.Inventory.Data.Containers;  // Too deep — flatten
在 C# 中声明信号

信号必须使用 [Signal] 特性,委托名称必须以 EventHandler 结尾:

[Signal]
public delegate void HealthChangedEventHandler(int newHealth, int maxHealth);

// Emit
EmitSignal(SignalName.HealthChanged, health, maxHealth);

// Connect
someNode.HealthChanged += OnHealthChanged;

// Disconnect
someNode.HealthChanged -= OnHealthChanged;

项目设置检查清单

创建新项目并完成脚手架搭建后,使用此清单检查所有设置是否就绪。

  • 已创建目录结构(assets/、scenes/、scripts/,或文件共置布局)
  • 已创建 .gitignore,并包含 .godot/、.mono/、bin/、obj/
  • 已创建 .gitattributes,并设置 LF 规范化和二进制资源规则
  • project.godot — 已设置视口分辨率(1920x1080 或项目目标分辨率)
  • project.godot — 已配置拉伸模式(canvas_items 或 viewport)
  • 已为所有玩家输入定义 Input Map 动作(未硬编码按键常量)
  • 已注册自动加载项:GameManager、EventBus、AudioManager、SaveManager
  • 已在 autoloads/(或 scripts/autoloads/)下创建自动加载脚本
  • 如果自动加载项必须在暂停期间运行,其处理模式已设为 Always
  • 对于 C# 项目:.csproj 以 net8.0 为目标,已设置 RootNamespace,并启用 Nullable
  • 对于 C# 项目:所有节点脚本均使用 partial class
  • 已在添加游戏内容前于 main 分支上创建初始提交
  • 项目的 Agent 指令文件(CLAUDE.md,或仓库所维护的 AGENTS.md / GEMINI.md)包含 ## GodotPrompter 部分,其中写明技能调用规则(内容参见 godot-prompter:godot-brainstorming)
  • CI 流水线(可选,但建议配置):对 GDScript 文件运行 godot --headless --check-only

评论

支持 Markdown