第五部分:Camera2D、地图边界、玩家出生点、场景组织

2026-05-19
393114 分钟
...

这一部分会让你的 RPG 场景从“角色能在地图上走”变成“像一个真正的游戏画面”。

现在我们要解决这些问题:

角色走远了镜头怎么跟着走
镜头会不会看到地图外面的黑边
玩家出生点应该怎么放
MainWorldUI 应该怎么组织
以后切换地图时结构怎么预留

1. Camera2D 是什么

Camera2D 就是 2D 游戏里的相机。

它决定玩家在屏幕上看到哪一块世界。

如果没有相机,Godot 也会显示默认视图,但你没法很好地控制:

镜头跟随玩家
镜头缩放
镜头平滑移动
镜头边界
镜头震动
镜头偏移

RPG 里最常见的做法是:

Player CharacterBody2D
├── AnimatedSprite2D
├── CollisionShape2D
└── Camera2D

Camera2D 作为 Player 的子节点。

这样 Player 移动时,Camera2D 会跟着 Player 一起移动。

这就是最简单的镜头跟随。

2. Camera2D 为什么放在 Player 下面

因为子节点会跟随父节点的位置变化。

所以:

Player 移动

Camera2D 跟着移动

画面跟着玩家移动

这很适合初学阶段。

你现在先别搞太复杂的独立 CameraController。

先用最稳的:

Camera2D 放在 Player 下面

结构:

Player CharacterBody2D
├── AnimatedSprite2D
├── CollisionShape2D
└── Camera2D

选中 Camera2D,在 Inspector 里确认它是当前相机。

Godot 的 Camera2D 有很多用于控制镜头的属性,比如位置平滑、缩放、偏移、边界限制等;其中 position_smoothing_enabled 可以让镜头平滑靠近目标位置,zoom 可以控制视图缩放。(Godot Engine documentation)

3. Camera2D 的 Current / Enabled

一个场景里可以有多个 Camera2D。

但是同一时间真正工作的,一般只有一个。

你可以理解成:

场景里可以摆很多摄像机
但当前屏幕只能主要看一个摄像机

初学阶段,你只需要:

选中 Camera2D
Inspector
启用当前相机相关选项

或者在代码里:

func _ready():
    $Camera2D.make_current()

如果你运行后画面没有跟随玩家,第一件事就检查 Camera2D 有没有成为当前相机。

4. Camera2D 的 Zoom

zoom 控制镜头缩放。

默认:

zoom = Vector2(1, 1)

如果你想看得更近:

zoom = Vector2(2, 2)

如果你想看得更远:

zoom = Vector2(0.75, 0.75)

这里有点反直觉:

数值越大看起来越近
数值越小看起来越远

像素 RPG 初期可以先用:

Vector2(2, 2)

这样图块和角色会更大,看起来更像复古 RPG。

但如果你的 tile 是 32x32,可能 Vector2(1, 1) 就已经够了。

5. 相机平滑 Position Smoothing

如果 Camera2D 直接跟随 Player,画面会非常“硬”。

角色一动,镜头立刻贴着动。

可以开启平滑:

Camera2D
Inspector
Position Smoothing
Enabled = true
Speed = 5 8

代码也可以写:

@onready var camera: Camera2D = $Camera2D

func _ready():
    camera.position_smoothing_enabled = true
    camera.position_smoothing_speed = 8.0

position_smoothing_enabled 开启后,相机会平滑移动到目标位置,position_smoothing_speed 控制平滑速度。(Godot Engine documentation)

简单理解:

Speed镜头更慢更柔
Speed镜头更快更紧

RPG 里不建议太慢。

否则玩家走路时会有拖影感,容易晕。

推荐先试:

5.0
8.0
10.0

6. 地图边界是什么

现在你会遇到一个问题:

玩家走到地图边缘
Camera2D 继续跟着玩家移动
屏幕外露出黑色空白

这就需要相机边界。

Camera2D 有四个边界属性:

limit_left
limit_top
limit_right
limit_bottom

它们表示相机能滚动到的最左、最上、最右、最下位置。官方文档里说明,limit_leftlimit_rightlimit_top 这些属性是以像素为单位的滚动边界;相机到达这些值后会停止继续滚动。(Godot Engine documentation)

比如你的地图大小是:

 960 像素
 640 像素

那可以设置:

camera.limit_left = 0
camera.limit_top = 0
camera.limit_right = 960
camera.limit_bottom = 640

这样相机就不会无限看到地图外面。

7. 手动设置相机边界

最简单方法是手动填。

选中 Camera2D

Inspector
Limit
Left = 0
Top = 0
Right = 地图宽度
Bottom = 地图高度

例如你的地图是:

30 格宽
20 格高
每格 32 像素

那地图像素大小是:

30 * 32 = 960
20 * 32 = 640

相机边界:

Left = 0
Top = 0
Right = 960
Bottom = 640

如果你的 tile 是 16x16:

30 * 16 = 480
20 * 16 = 320

所以你一定要知道你的 tile 尺寸。

8. 用代码根据 TileMapLayer 自动设置边界

后面地图多了,手动填会麻烦。

可以写一个简单方法,根据 Ground 的使用范围自动设置相机边界。

假设结构是:

Main
└── World
    ├── Ground TileMapLayer
    └── Player
        └── Camera2D

在 Player 脚本里导出一个 TileMapLayer

@export var ground_layer: TileMapLayer
@onready var camera: Camera2D = $Camera2D

func _ready():
    setup_camera_limits()

func setup_camera_limits():
    if ground_layer == null:
        return

    var used_rect: Rect2i = ground_layer.get_used_rect()
    var tile_size: Vector2i = ground_layer.tile_set.tile_size

    camera.limit_left = used_rect.position.x * tile_size.x
    camera.limit_top = used_rect.position.y * tile_size.y
    camera.limit_right = used_rect.end.x * tile_size.x
    camera.limit_bottom = used_rect.end.y * tile_size.y

然后在 Inspector 里,把 Ground 拖到 Player 的 ground_layer 上。

这段的核心思想是:

Ground 画了多大

相机边界就设置多大

注意:这个版本适合 Ground 从原点附近开始、不做复杂缩放的情况。以后你地图节点有偏移、缩放、多层嵌套时,需要进一步把坐标转换成 global 坐标。初学阶段先不折腾那个,先跑通。

9. 相机边界常见问题

如果你设置了边界,但没生效,检查这些:

Camera2D 是不是当前相机
Limit Enabled 是否开启
limit_right 是否大于 limit_left
limit_bottom 是否大于 limit_top
地图尺寸是不是算错了
Player 是否已经跑到边界外
Camera2D offset 是否让画面越界

Camera2D 文档里提到,关闭 limits 后,四个 limit_* 属性不会起作用;另外,offset 可以把视图推到限制范围之外。(Godot Engine documentation)

所以如果你后面做镜头震动,发现边界附近会露黑边,可能就是 offset 或 shake 效果把相机画面推出去了。

10. Marker2D 是什么

Marker2D 是一个非常适合当“位置标记”的节点。

它自己不会显示到游戏运行画面里,但在编辑器里会显示一个十字标记。官方文档也说,Marker2D 是一个通用的 2D 位置提示节点,类似普通 Node2D,但在 2D 编辑器里始终显示为十字。(Godot Engine documentation)

它很适合做:

玩家出生点
怪物刷新点
NPC 站位点
传送目标点
剧情触发位置
镜头参考点

比如:

World
├── Ground
├── Obstacles
├── SpawnPoints Node2D
│   ├── PlayerSpawn Marker2D
│   ├── SlimeSpawn01 Marker2D
│   └── SlimeSpawn02 Marker2D
└── Player

11. 玩家出生点怎么做

不要把玩家位置写死在代码里:

position = Vector2(100, 100)

短期能用,但后面地图多了会很烦。

更好的做法是放一个 Marker2D:

World
├── SpawnPoints Node2D
│   └── PlayerSpawn Marker2D
└── Player CharacterBody2D

然后让 Player 出现在这个点:

@onready var player: CharacterBody2D = $Player
@onready var player_spawn: Marker2D = $SpawnPoints/PlayerSpawn

func _ready():
    player.global_position = player_spawn.global_position

这段代码可以放在 World.gd 里。

12. 为什么出生点不要放在 Player 里面

有些人会把 Marker2D 放在 Player 下面。

不推荐。

因为出生点是地图的一部分,不是玩家的一部分。

Player 是要被放到出生点
不是出生点跟着 Player

正确思路是:

地图决定玩家出生在哪里
Player 只是被放过去

所以出生点应该放在 World 或具体地图场景里。

例如:

ForestMap
├── Ground
├── Obstacles
├── SpawnPoints
│   └── PlayerSpawn
└── Foreground

Player 进入 ForestMap 时,被放到 PlayerSpawn 的位置。

13. Main、World、UI 的推荐结构

你的主场景建议这样:

Main Node
├── World Node2D
└── UI CanvasLayer

这是一个很经典的结构。

Godot 官方的场景组织建议里也提到,游戏应该有一个明确入口点;在 Godot 里通常是 Main 节点,World 可以作为 Main 的子节点,GUI 也作为主界面部分存在。(Godot Engine documentation)

你可以这样理解:

Main游戏总入口负责组织大结构
World游戏世界地图玩家NPC怪物都在这里
UI屏幕界面血条背包对话框都在这里

前端类比:

App
├── GameWorld
└── HUD

Godot:

Main
├── World
└── UI

14. 为什么 UI 要放 CanvasLayer

UI 不应该跟着地图一起移动。

比如:

血条
背包按钮
任务提示
金币数量
对话框

这些应该固定在屏幕上。

如果 UI 放在 World 里面,Camera2D 移动时,UI 可能跟着地图跑。

CanvasLayer 正是为这种情况准备的:它会创建独立的 2D 渲染层,层级数字越大越靠上,并且它有自己的 transform,不依赖其他层的 transform,因此可以让 UI 固定在屏幕空间里。(Godot Engine documentation)

推荐:

Main
├── World Node2D
└── UI CanvasLayer
    ├── HPBar
    ├── BagButton
    └── DialoguePanel

这样玩家走到哪里,UI 都稳稳待在屏幕上。

15. 第一阶段 Main 场景结构

你现在可以按这个来:

Main Node
├── World Node2D
│   ├── Ground TileMapLayer
│   ├── Obstacles TileMapLayer
│   ├── SpawnPoints Node2D
│   │   └── PlayerSpawn Marker2D
│   ├── Player CharacterBody2D
│   │   ├── AnimatedSprite2D
│   │   ├── CollisionShape2D
│   │   └── Camera2D
│   └── Foreground TileMapLayer
└── UI CanvasLayer
    └── DebugLabel Label

这个结构足够你做第一张可玩的地图。

先实现:

玩家出生
玩家移动
相机跟随
相机边界
地图碰撞
UI 固定

不要再往里塞系统了。

天气、四季、卡牌、背包、任务,都后面慢慢加。

16. World.gd 应该负责什么

World.gd 适合负责“这个地图场景启动时要做什么”。

比如:

把玩家放到出生点
设置相机边界
生成当前地图的怪物
初始化地图环境
连接地图内信号

一个简单的 World.gd

extends Node2D

@onready var player: CharacterBody2D = $Player
@onready var player_spawn: Marker2D = $SpawnPoints/PlayerSpawn
@onready var ground: TileMapLayer = $Ground
@onready var camera: Camera2D = $Player/Camera2D

func _ready():
    setup_player_spawn()
    setup_camera_limits()

func setup_player_spawn():
    player.global_position = player_spawn.global_position

func setup_camera_limits():
    var used_rect: Rect2i = ground.get_used_rect()
    var tile_size: Vector2i = ground.tile_set.tile_size

    camera.limit_left = used_rect.position.x * tile_size.x
    camera.limit_top = used_rect.position.y * tile_size.y
    camera.limit_right = used_rect.end.x * tile_size.x
    camera.limit_bottom = used_rect.end.y * tile_size.y

这个脚本非常适合现在用。

17. Player.gd 应该负责什么

Player.gd 不要什么都管。

它主要管自己:

输入
移动
动画
血量
攻击
交互检测

不要让 Player 去管:

地图怎么加载
UI 怎么创建
天气怎么变化
场景怎么切换
怪物怎么生成

也就是说,不要写成:

func _ready():
    create_map()
    create_ui()
    spawn_all_enemies()
    setup_weather()

这会让 Player 变成“上帝对象”,后面必炸。

Player 现在保持简单:

extends CharacterBody2D

@export var speed: float = 120.0
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

var last_direction: Vector2 = Vector2.DOWN

func _physics_process(delta):
    var direction = Input.get_vector(
        "move_left",
        "move_right",
        "move_up",
        "move_down"
    )

    velocity = direction * speed
    move_and_slide()
    update_animation(direction)

func update_animation(direction: Vector2):
    if direction == Vector2.ZERO:
        animated_sprite.play("idle_" + get_direction_name(last_direction))
        return

    last_direction = direction
    animated_sprite.play("walk_" + get_direction_name(direction))

func get_direction_name(direction: Vector2) -> String:
    if abs(direction.x) > abs(direction.y):
        return "right" if direction.x > 0 else "left"

    return "down" if direction.y > 0 else "up"

18. Main.gd 应该负责什么

Main.gd 适合做更高层的组织。

比如:

当前加载哪个 World
切换地图
暂停游戏
连接 UI World
管理游戏整体状态

第一阶段你甚至可以不写 Main.gd

World.gd 先工作就行。

但你要知道后面会变成:

Main
├── CurrentWorld
└── UI

以后切换地图时,你可以把旧 World 移除,再实例化新 World。

19. 为以后切换地图预留结构

现在先不要直接用很多个完整主场景来回切。

比如:

ForestMain.tscn
TownMain.tscn
HouseMain.tscn

不太推荐这样开局。

更推荐:

Main.tscn
├── WorldContainer Node2D
└── UI CanvasLayer

然后不同地图是独立场景:

ForestMap.tscn
TownMap.tscn
HouseInterior.tscn

运行时把地图实例放进 WorldContainer

Main
├── WorldContainer
│   └── ForestMap
└── UI

切换到室内:

Main
├── WorldContainer
│   └── HouseInterior
└── UI

这样 UI 不会被删掉,整体结构也更稳。

Godot 的最佳实践文档也提到,切换关卡时可以替换 World 节点的子节点;如果直接切换整个主场景,GUI 也可能会随场景一起被删除,所以 GUI 需要作为单例、World 的临时部分,或手动作为 root 的直接子节点来处理。(Godot Engine documentation)

20. 简单场景切换方式

Godot 里最简单的切换场景是:

get_tree().change_scene_to_file("res://scenes/main_menu.tscn")

SceneTree 负责管理节点层级和场景本身,可以加载、切换和重载场景;官方也提到,基础场景切换可以使用 SceneTree.change_scene_to_file()。(Godot Engine documentation)

但是对 RPG 来说,后面你大概率会想保留:

UI
玩家数据
背包
任务状态
时间系统
天气系统

所以不一定每次都切整个主场景。

更好的思路是:

Main 不换
UI 不换
只换 WorldContainer 里的地图

这对你后面做室内/室外切换很重要。

21. 地图切换的简化版代码

先看结构:

Main Node
├── WorldContainer Node2D
└── UI CanvasLayer

Main.gd

extends Node

@onready var world_container: Node2D = $WorldContainer

var current_world: Node = null

func change_world(scene_path: String):
    if current_world != null:
        current_world.queue_free()

    var world_scene: PackedScene = load(scene_path)
    current_world = world_scene.instantiate()
    world_container.add_child(current_world)

调用:

change_world("res://scenes/maps/forest_map.tscn")

切室内:

change_world("res://scenes/maps/house_interior.tscn")

这只是基础版。

以后还要处理:

从哪个门进入
出生在哪个 Marker2D
是否播放转场动画
是否保存旧地图状态

但别急,现在知道结构就行。

22. 传送点怎么设计

比如你从室外进入房子。

可以做一个 Area2D

DoorToHouse Area2D
├── CollisionShape2D
└── Sprite2D 可选

玩家进入区域并按 E:

触发切换地图

门节点可以导出目标地图路径:

extends Area2D

@export var target_scene: String
@export var target_spawn_name: String = "PlayerSpawn"

以后进入门时:

切到 target_scene
把玩家放到 target_spawn_name 对应的 Marker2D

但这是后面“交互系统”和“地图切换系统”的内容。

现在你只要知道:

门不是 tile
门应该是有逻辑的 Area2D / Scene

因为门需要触发事件。

23. 第一张地图要不要拆成独立场景

建议拆。

不要把所有东西都堆在 Main.tscn

推荐:

Main.tscn
ForestMap.tscn
Player.tscn
UI.tscn

结构大概是:

Main.tscn
├── WorldContainer
│   └── ForestMap 实例
└── UI 实例

ForestMap.tscn

ForestMap Node2D
├── Ground TileMapLayer
├── Obstacles TileMapLayer
├── SpawnPoints
│   └── PlayerSpawn Marker2D
├── Player 实例
└── Foreground TileMapLayer

Player.tscn

Player CharacterBody2D
├── AnimatedSprite2D
├── CollisionShape2D
└── Camera2D

这样你之后复用 Player、替换地图都会方便。

24. 但玩家到底放在地图里,还是放在 Main 里?

这问题很关键。

初学阶段,建议:

Player 先放在地图里

也就是:

ForestMap
├── Ground
├── Obstacles
├── Player
└── Foreground

这样最直观,最好调试。

后面项目复杂了,可以改成:

Main
├── Player
├── WorldContainer
│   └── CurrentMap
└── UI

或者切地图时保留 Player,只换地图。

但现在不要一上来搞“完美架构”。

你现在最重要的是:

地图能跑
玩家能走
相机能跟
碰撞能挡

先活下来,再讲优雅。

25. DebugLabel 很有用

建议你在 UI 里放一个 DebugLabel

结构:

UI CanvasLayer
└── DebugLabel Label

显示玩家坐标:

extends CanvasLayer

@export var player: CharacterBody2D
@onready var debug_label: Label = $DebugLabel

func _process(delta):
    if player == null:
        return

    debug_label.text = "Player: %s" % player.global_position

这对调试出生点、相机边界、地图坐标很有帮助。

你会很直观地看到:

玩家当前在哪里
坐标是不是负数
地图边界大概是多少

小项目可以先简单粗暴点,别嫌丑。调试 UI 是游戏开发里的扳手,不是艺术品。

26. Camera2D 和 DebugLabel 的常见坑

如果 DebugLabel 跟着地图移动了,说明它没放在 CanvasLayer 里。

正确:

Main
├── World
│   └── Player
│       └── Camera2D
└── UI CanvasLayer
    └── DebugLabel

错误:

World
├── Player
│   └── Camera2D
└── DebugLabel

因为错误结构里,Label 在 World 里,会受相机影响。

27. 地图边界和玩家边界不是一回事

相机边界只限制镜头。

它不会阻止玩家走出地图。

比如:

camera.limit_right = 960

只是相机不会继续往右显示。

但玩家如果没有墙或边界碰撞,仍然可以走出地图。

所以你还需要地图边缘有碰撞:

边界墙
树墙
河流
悬崖
InvisibleWall

最简单做法:

 Obstacles TileMapLayer 在地图边缘围一圈不可通行 tile

后面可以做一个 InvisibleWall

StaticBody2D
└── CollisionShape2D

但第一阶段,用 tile 围边就够了。

28. 第一张地图的推荐尺寸

建议第一张测试地图不要太大。

用:

30 x 20

或者:

40 x 25

如果 tile 是 32x32:

30 x 20 = 960 x 640 像素
40 x 25 = 1280 x 800 像素

够你测试:

移动
碰撞
相机跟随
边界
遮挡
出生点

地图太大只会让你调试变慢。

29. 当前阶段推荐的完整结构

我建议你现在最终搭成这样:

Main Node
├── World Node2D
│   ├── Ground TileMapLayer
│   ├── Obstacles TileMapLayer
│   ├── SpawnPoints Node2D
│   │   └── PlayerSpawn Marker2D
│   ├── Player CharacterBody2D
│   │   ├── AnimatedSprite2D
│   │   ├── CollisionShape2D
│   │   └── Camera2D
│   └── Foreground TileMapLayer
└── UI CanvasLayer
    └── DebugLabel Label

脚本分配:

World.gd出生点相机边界
Player.gd移动动画
UI.gd调试显示以后血条

这就是第一阶段的“干净骨架”。

30. 本部分最重要的记忆点

Camera2D 控制玩家看到哪里
Camera2D Player 下面最简单
Position Smoothing 可以让镜头更柔
Limit 可以限制相机不要看到地图外
Marker2D 很适合做玩家出生点
出生点属于地图不属于玩家
Main 是游戏入口
World 是游戏世界
UI 应该放 CanvasLayer
相机边界不会阻止玩家出地图
地图边缘还需要碰撞

31. 你现在的小练习

按这个目标做:

1. Player 添加 Camera2D
2. Camera2D 成为当前相机
3. 开启 Position Smoothing
4. 设置 Camera2D Limit
5. World 里添加 SpawnPoints/PlayerSpawn
6. 运行时把 Player 放到 PlayerSpawn
7. UI 里放 DebugLabel 显示玩家坐标
8. Obstacles 在地图边缘围一圈碰撞

做完这一部分,你的项目就已经有“基础 RPG 场景”的样子了。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
godot2026-07-27
Godot 4 常用 UI 节点详解
Godot 4 常用 UI 节点详解 在 Godot 4 中,UI 系统基于 Control(控件) 节点构建。所有 UI 节点都继承自 Control,形成一棵完整的 UI 树。与游戏引擎中常见的"Canvas + DOM"模式不同,Godot 的 UI 系统是声明式的——你在场景中搭好节点树,引擎自动完成布局计算。 一、布局系统:Container 家族 Container 是 Godot UI 的 骨架 。它决定了子节点的大小和位...
学习
godot2026-07-09
Godot 4 自动地形系统(AutoTileSet / Terrains)完全指南
前言 在 2D 游戏开发中,地形瓦片(tile)的拼接是一个绕不开的问题。想象一下:你有一片草地、一条河流、一段平台——如果每一块边缘、角落、过渡区域都要手动选择对应的瓦片图,工作量将是巨大的。 自动地形系统 就是为了解决这个问题而生的。 一、什么是自动地形(Autotiling)? 自动地形的核心思想很简单: 你只管画,引擎帮你选对瓦片 。 当你在 TileMap 上绘制地形时,引擎会自动检测每个瓦片的上下左右邻居,然后根据预设的规则...
学习
godot2026-06-25
Godot 中 zindex 和 ysort 的区别总结
在 Godot 2D 游戏开发中,角色、树木、怪物、地面、技能特效、UI 都需要正确的显示顺序。比如角色走到树前面时,角色应该挡住树;角色走到树后面时,树又应该挡住角色。 这种显示顺序主要和两个概念有关: 和 。 其中 用来手动控制图层顺序, 用来根据物体的 Y 坐标自动排序。 一句话理解 是手动分层。 是根据 Y 坐标自动排序。 简单来说: | 属性 | 作用 | 适合场景 | | | | | | | 数值越大,显示越靠前 | 地面、...
学习
godot2026-06-11
Tileset 资源图的标准和规范
一、什么是 Tileset 资源图 Tileset,中文通常叫“图块资源图”或“瓦片图”,是 2D 游戏中非常常见的一种地图资源组织方式。 简单来说,Tileset 就是把很多小图块按照固定尺寸排列在一张图片里。游戏引擎会按照固定的格子大小去切割这张图片,然后把每个小格子当成一个独立的地图块使用。 比如一个 32×32 像素的 Tileset 中,每一个 tile 都是 32×32 像素。地图编辑器或游戏引擎会按照 32×32 的网格,...
学习
godot2026-05-29
用户角色精灵图制作角色的完整流程
在 2D RPG 游戏里,角色通常不是用一张单独图片完成的,而是用一张“角色精灵图”来做。 所谓角色精灵图,通常是一张包含多个动作帧的大图。比如角色向下走有 4 帧,向左走有 4 帧,向右走有 4 帧,向上走有 4 帧。Godot 会根据这些帧不断切换图片,看起来角色就动起来了。 这篇文章主要介绍:拿到一张角色精灵图之后,如何在 Godot 中把它做成一个可以正常移动、播放动画、和地图产生遮挡关系的角色。 一、先理解角色精灵图是什么 角...
学习
godot2026-05-26
Godot 节点系统详细介绍
Godot 里最核心的东西不是“类”,也不是“组件”,而是 节点 Node 。 你可以把 Godot 的节点理解成: 在前端里,一个页面是由很多 DOM 元素组成的; 在 Godot 里,一个游戏场景是由很多 Node 节点组成的。 比如一个玩家角色,可能不是一个单独对象,而是这样的结构: 这里的 是根节点,下面挂着显示图片、播放动画、碰撞检测、摄像机、音效等子节点。 Godot 官方文档也把节点和场景放在一起讲:多个节点组成树状结构后...
学习

评论

请登录后发表评论

去登录
加载评论中...