Godot 4 GDScript 教程 / 编辑器界面与工作流
编辑器界面与工作流
熟练掌握 Godot 编辑器界面和工作流能显著提升开发效率。本章详细介绍各个面板功能、常用编辑器操作、快捷键以及高效工作流技巧。
1. 编辑器主界面
Godot 4 编辑器由以下核心面板组成:
┌─────────────────────────────────────────────────────────────┐
│ 菜单栏:场景 | 项目 | 调试 | 编辑器 | 帮助 │
├──────────┬──────────────────────────────┬───────────────────┤
│ │ │ │
│ 场景面板 │ 2D/3D 视口 │ 检查器 │
│ Scene │ Viewport │ Inspector │
│ │ │ │
│ │ │ │
├──────────┼──────────────────────────────┤ │
│ │ │ │
│ 文件系统 │ 脚本编辑器 / 着色器编辑器 │ │
│ FileSystem│ │ │
│ │ │ │
└──────────┴──────────────────────────────┴───────────────────┘
│ 底部面板:输出 | 调试器 | 音频 | 动画 | 瓦片地图 │
└─────────────────────────────────────────────────────────────┘
1.1 场景面板(Scene Dock)
| 功能 | 操作 | 说明 |
|---|
| 添加节点 | 点击 “+” 或按 Ctrl+A | 从节点列表选择 |
| 删除节点 | 选中后按 Delete | 删除节点及其子节点 |
| 复制节点 | Ctrl+D | 复制选中节点 |
| 右键菜单 | 右键点击节点 | 更多操作选项 |
| 改变父子关系 | 拖拽节点 | 重新组织场景树 |
| 重命名 | 双击节点名称 | 为节点命名 |
# 通过代码操作场景树
func _ready() -> void:
# 获取场景树根节点
var tree = get_tree()
# 获取当前场景根节点
var current_scene = tree.current_scene
print("当前场景: %s" % current_scene.name)
# 获取节点数量
var node_count = current_scene.get_child_count()
print("子节点数量: %d" % node_count)
# 遍历场景树
print_tree()
💡 提示: 给节点起有意义的名称(如 Player、Enemy、UI)比使用默认名称(Sprite2D、Node2D)更便于管理。
1.2 检查器面板(Inspector Dock)
| 功能 | 说明 |
|---|
| 属性编辑 | 修改选中节点的属性 |
| 资源分配 | 将资源拖拽到对应属性 |
| 分组显示 | 按类别折叠/展开属性 |
| 重置属性 | 右键 → 重置为默认值 |
| 复制/粘贴 | 右键 → 复制/粘贴属性值 |
| 脚本变量 | 显示 @export 导出的变量 |
# 使用 @export 让变量在检查器中可见
extends Sprite2D
@export var move_speed: float = 200.0
@export var health: int = 100
@export var sprite_texture: Texture2D
@export var enemy_color: Color = Color.RED
# 分组导出
@export_group("Movement")
@export var max_speed: float = 300.0
@export var acceleration: float = 50.0
@export var friction: float = 0.1
@export_group("Combat")
@export var attack_damage: int = 25
@export var attack_range: float = 50.0
# 子分组
@export_group("Advanced")
@export_subgroup("Physics")
@export var gravity_scale: float = 1.0
@export var bounce_factor: float = 0.5
⚠️ 注意: 检查器中修改的值是实例属性,只影响当前节点实例;脚本中的默认值影响所有实例。
1.3 文件系统面板(FileSystem Dock)
| 操作 | 方法 |
|---|
| 创建文件夹 | 右键 → 新建文件夹 |
| 创建脚本 | 右键 → 新建脚本 |
| 创建场景 | 右键 → 新建场景 |
| 创建资源 | 右键 → 新建资源 |
| 导入文件 | 直接拖拽文件到面板 |
| 重新导入 | 右键 → 重新导入 |
| 设为默认导入 | 右键 → 新建导入预设 |
推荐的文件系统组织:
res://
├── scenes/ # .tscn 场景文件
├── scripts/ # .gd 脚本文件(无场景的纯脚本)
├── resources/ # .tres 自定义资源
├── assets/
│ ├── sprites/ # 图片
│ ├── audio/ # 音频
│ ├── fonts/ # 字体
│ └── animations/ # 动画
├── shaders/ # 着色器
└── addons/ # 插件
2. 2D 视口操作
2.1 导航操作
| 操作 | 快捷键/方式 | 说明 |
|---|
| 平移 | 鼠标中键拖拽 | 移动视口 |
| 缩放 | 滚轮 | 放大/缩小视口 |
| 框选 | 拖拽选择 | 选中多个节点 |
| 聚焦选中 | F | 将视口中心对准选中节点 |
| 全部显示 | Shift+F | 在视口中显示所有内容 |
| 切换网格 | 显示菜单 | 显示/隐藏编辑器网格 |
2.2 2D 变换工具
| 工具 | 快捷键 | 功能 |
|---|
| 移动 | W | 移动选中节点 |
| 旋转 | E | 旋转选中节点 |
| 缩放 | S | 缩放选中节点 |
| 自由变换 | Ctrl+Shift+T | 综合变换 |
# 代码中的 2D 变换
extends Node2D
func _ready() -> void:
# 位置
position = Vector2(100, 200)
# 旋转(弧度)
rotation = deg_to_rad(45)
# 缩放
scale = Vector2(2, 2)
# 全局变换
global_position = Vector2(500, 300)
# 使用 Transform2D
var transform = Transform2D(deg_to_rad(30), Vector2(200, 100))
3. 3D 视口操作
3.1 导航操作
| 操作 | 快捷键/方式 | 说明 |
|---|
| 环绕旋转 | Alt + 鼠标左键 | 围绕焦点旋转 |
| 平移 | 鼠标中键拖拽 | 平移视口 |
| 缩放 | 滚轮 / Alt + 右键 | 前后缩放 |
| 飞行模式 | Shift+鼠标中键 | 自由飞行 |
| 聚焦选中 | F | 聚焦到选中物体 |
| 切换视角 | 数字键 1/3/7 | 正面/侧面/顶部 |
3.2 3D 操纵工具
| 工具 | 快捷键 | 功能 |
|---|
| 移动 | W | 三轴移动手柄 |
| 旋转 | E | 三轴旋转手柄 |
| 缩放 | R | 三轴缩放手柄 |
| 自由变换 | Y | 综合变换 |
4. 调试器(Debugger)
4.1 调试面板
| 标签页 | 功能 |
|---|
| 调试器 | 显示断点、调用栈、变量值 |
| 监视 | 添加自定义监视表达式 |
| 性能监视器 | FPS、内存、渲染统计 |
| 网络分析器 | 网络流量监控 |
| 视觉分析器 | 可视化性能瓶颈 |
# 调试工具函数
func _ready() -> void:
# 打印调试信息
print("节点路径: %s" % get_path())
print("场景树: %s" % str(get_tree().root))
# 断言(调试模式下生效)
assert(health > 0, "生命值必须大于 0")
# 条件断点:在脚本编辑器中点击行号左侧设置断点
# 右键断点可以设置条件,例如:health < 50
# 推送错误/警告到调试控制台
push_warning("这是一个警告")
push_error("这是一个错误")
# 性能监控
print("FPS: %d" % Performance.get_monitor(Performance.TIME_FPS))
print("对象数量: %d" % Performance.get_monitor(Performance.OBJECT_COUNT))
print("内存: %d MB" % (Performance.get_monitor(Performance.MEMORY_STATIC) / 1048576))
4.2 调试快捷键
| 快捷键 | 功能 |
|---|
| F5 | 运行项目 |
| F6 | 运行当前场景 |
| F7 | 单步跳过(调试中) |
| F8 | 步入(调试中) |
| F9 | 切换断点 |
| F12 | 步出(调试中) |
| Ctrl+Shift+F5 | 调试运行项目 |
| Ctrl+Shift+F6 | 调试运行场景 |
5. 动画编辑器
5.1 AnimationPlayer 使用
# AnimationPlayer 使用示例
extends CharacterBody2D
@onready var anim_player: AnimationPlayer = $AnimationPlayer
@onready var sprite: Sprite2D = $Sprite2D
var is_attacking: bool = false
func play_animation(anim_name: String) -> void:
if anim_player.has_animation(anim_name):
anim_player.play(anim_name)
func attack() -> void:
if is_attacking:
return
is_attacking = true
anim_player.play("attack")
await anim_player.animation_finished
is_attacking = false
func _physics_process(delta: float) -> void:
if is_attacking:
return
if velocity.length() > 0:
play_animation("run")
else:
play_animation("idle")
5.2 创建动画关键帧
在编辑器中操作:
- 选中 AnimationPlayer 节点
- 点击底部 “动画” 面板
- 点击 “新建” 创建动画
- 在时间线上点击关键帧按钮记录属性
动画轨道类型:
- 属性轨道:记录节点属性变化(位置、旋转、颜色等)
- 方法轨道:在指定时间调用函数
- Bezier 轨道:贝塞尔曲线控制的平滑动画
- 音频轨道:播放音频片段
- 子动画轨道:嵌套播放其他动画
💡 提示: 使用 AnimationMixer(Godot 4.3+)可以更高效地管理和混合多个动画。
6. TileMap 编辑器
6.1 TileMap 新系统
Godot 4 的 TileMap 系统经过全面重写:
# TileMapLayer 使用示例(Godot 4.3+推荐)
extends TileMapLayer
# 地图尺寸
const MAP_WIDTH: int = 50
const MAP_HEIGHT: int = 30
func _ready() -> void:
generate_random_map()
func generate_random_map() -> void:
for x in range(MAP_WIDTH):
for y in range(MAP_HEIGHT):
var tile_id: int
if y > MAP_HEIGHT * 0.7:
tile_id = 1 # 地面
elif y > MAP_HEIGHT * 0.5:
tile_id = 2 # 草地
else:
tile_id = 0 # 空气
set_cell(Vector2i(x, y), tile_id, Vector2i.ZERO)
func get_tile_at(world_pos: Vector2) -> Vector2i:
return local_to_map(to_local(world_pos))
func set_tile_at(world_pos: Vector2, tile_id: int) -> void:
var map_pos = local_to_map(to_local(world_pos))
set_cell(map_pos, tile_id, Vector2i.ZERO)
6.2 TileSet 资源配置
| 设置项 | 说明 |
|---|
| 瓦片大小 | 每个瓦片的像素尺寸 |
| 瓦片形状 | 正方形、六角形、等距 |
| 物理层 | 配置碰撞形状 |
| 导航层 | 配置导航区域 |
| 地形集 | 自动地形贴图规则 |
7. 信号面板
7.1 信号连接界面
在 Godot 编辑器中连接信号:
- 选中发出信号的节点
- 点击检查器旁的 “节点” 标签页
- 双击要连接的信号
- 选择接收信号的节点
- 选择或输入处理函数名
# 代码方式连接信号
extends Node2D
@onready var button: Button = $Button
@onready var timer: Timer = $Timer
@onready var area: Area2D = $Area2D
func _ready() -> void:
# 新语法:使用 Callable
button.pressed.connect(_on_button_pressed)
timer.timeout.connect(_on_timer_timeout)
area.body_entered.connect(_on_area_body_entered)
# 带参数的信号
area.body_entered.connect(_on_body_entered_with_arg.bind("敌人区域"))
func _on_button_pressed() -> void:
print("按钮被点击")
func _on_timer_timeout() -> void:
print("定时器超时")
func _on_area_body_entered(body: Node2D) -> void:
print("物体进入: %s" % body.name)
func _on_body_entered_with_arg(body: Node2D, area_name: String) -> void:
print("%s 进入了 %s" % [body.name, area_name])
8. 编辑器布局自定义
8.1 保存和加载布局
| 操作 | 菜单路径 |
|---|
| 保存布局 | 编辑器 → 编辑器布局 → 保存 |
| 加载布局 | 编辑器 → 编辑器布局 → 选择布局 |
| 删除布局 | 编辑器 → 编辑器布局 → 删除 |
| 重置布局 | 编辑器 → 编辑器布局 → 默认 |
8.2 推荐布局
2D 游戏开发布局:
┌─────┬────────────────────┬─────┐
│场景 │ 2D 视口 │检查器│
│ │ │ │
├─────┼────────────────────┤ │
│文件 │ 脚本编辑器 │ │
└─────┴────────────────────┴─────┘
3D 游戏开发布局:
┌─────┬────────────────────┬─────┐
│场景 │ 3D 视口 │检查器│
│ │ │ │
├─────┼────────────────────┤ │
│文件 │ 脚本编辑器 │ │
└─────┴────────────────────┴─────┘
9. 资源导入设置
9.1 图片导入
| 设置 | 推荐值 | 说明 |
|---|
| 压缩模式 | Lossless (像素图) / VRAM (大纹理) | 根据美术风格选择 |
| 尺寸限制 | 2的幂次 | 优化内存对齐 |
| 过滤 | Nearest (像素图) / Linear (3D) | 根据美术风格选择 |
| Mipmaps | 3D 开 / 2D 关 | 3D 远距离纹理优化 |
9.2 音频导入
| 设置 | 推荐值 | 说明 |
|---|
| 音乐 | OGG Vorbis | 有损压缩,文件小 |
| 音效 | WAV 或 OGG | 根据音效长度选择 |
| 循环 | 勾选 Loop | 背景音乐需要 |
| 混合率 | 44100 Hz | 标准采样率 |
10. 快捷键速查表
10.1 通用快捷键
| 快捷键 | 功能 |
|---|
| Ctrl+S | 保存场景 |
| Ctrl+Shift+S | 另存为 |
| Ctrl+Z | 撤销 |
| Ctrl+Y / Ctrl+Shift+Z | 重做 |
| Ctrl+C / V / X | 复制/粘贴/剪切 |
| Ctrl+D | 复制节点 |
| Delete | 删除选中 |
| Ctrl+A | 添加新节点 |
| Ctrl+P | 快速查找文件 |
| Ctrl+Shift+P | 命令面板 |
10.2 2D 视口快捷键
| 快捷键 | 功能 |
|---|
| W | 移动工具 |
| E | 旋转工具 |
| S | 缩放工具 |
| F | 聚焦选中 |
| Shift+F | 显示全部 |
| G | 切换网格 |
| Ctrl+Shift+T | 自由变换 |
10.3 脚本编辑器快捷键
| 快捷键 | 功能 |
|---|
| Ctrl+Click | 跳转到定义 |
| Ctrl+F | 查找 |
| Ctrl+H | 查找替换 |
| Ctrl+G | 跳转到行 |
| Ctrl+/ | 切换注释 |
| Ctrl+Shift+F | 全局查找 |
| Tab | 缩进 |
| Shift+Tab | 取消缩进 |
11. 游戏开发场景
场景:高效关卡设计工作流
# 使用 @tool 脚本在编辑器中实时预览
@tool
extends Node2D
# 在编辑器中显示自定义绘制
@export var room_size: Vector2 = Vector2(320, 240):
set(value):
room_size = value
queue_redraw()
@export var room_color: Color = Color(0.2, 0.3, 0.5, 0.5):
set(value):
room_color = value
queue_redraw()
@export var show_grid: bool = true:
set(value):
show_grid = value
queue_redraw()
func _draw() -> void:
# 只在编辑器中绘制
if not Engine.is_editor_hint():
return
# 绘制房间轮廓
draw_rect(Rect2(-room_size / 2, room_size), room_color)
draw_rect(Rect2(-room_size / 2, room_size), Color.WHITE, false, 2.0)
# 绘制网格
if show_grid:
var grid_step = 32.0
for x in range(-room_size.x / 2, room_size.x / 2, grid_step):
var from = Vector2(x, -room_size.y / 2)
var to = Vector2(x, room_size.y / 2)
draw_line(from, to, Color(1, 1, 1, 0.1))
for y in range(-room_size.y / 2, room_size.y / 2, grid_step):
var from = Vector2(-room_size.x / 2, y)
var to = Vector2(room_size.x / 2, y)
draw_line(from, to, Color(1, 1, 1, 0.1))
# 绘制门标记
draw_circle(Vector2(0, -room_size.y / 2), 8, Color.GREEN)
draw_circle(Vector2(0, room_size.y / 2), 8, Color.GREEN)
⚠️ 注意: @tool 脚本在编辑器中运行,请谨慎处理,避免在 _process 或 _physics_process 中执行破坏性操作。
12. 扩展阅读
上一章: 02 - 安装与项目设置
下一章: 04 - GDScript 2.0 基础语法