第一部分 02:Scene 和 Node 的关系

2026-05-19
424215 分钟
...

这一章是 Godot 的地基。

你以后看到的这些东西:

TileMapLayer
Player
Camera2D
Sprite2D
CollisionShape2D
Area2D
CanvasLayer
Button
Label
AnimationPlayer

本质上都绕不开两个概念:

Scene = 一棵节点树可以保存复用实例化
Node = 组成这棵树的一个个功能节点

Godot 官方文档的说法很直接:Node 是 Godot 的构建块,节点可以成为其他节点的子节点,从而形成树状结构;一棵节点树就叫 Scene,Scene 可以保存到磁盘,也可以实例化到其他 Scene 中。 (Godot Engine documentation)

1. 先用一句话理解

Node 是零件,Scene 是由一堆零件组装好的模块。

比如一个玩家:

Player CharacterBody2D
├── Sprite2D
├── CollisionShape2D
├── AnimationPlayer
└── Camera2D

这里每一个都是 Node。

整个 Player 这一棵树,可以保存成:

res://scenes/player.tscn

这个 player.tscn 就是一个 Scene。

2. 前端类比

你可以把 Godot 的 Scene 和 Node 类比成前端里的组件和 DOM 树。

前端里

function Player() {
  return (
    <div className="player">
      <img className="sprite" />
      <div className="collision-box" />
      <Camera />
    </div>
  )
}

Godot 里

Player CharacterBody2D
├── Sprite2D
├── CollisionShape2D
└── Camera2D

但是 Godot 比前端组件更“实体”。

前端组件主要负责:

结构
样式
状态
事件
渲染

Godot Scene 还会负责:

位置
旋转
缩放
碰撞
物理
动画
声音
摄像机
输入
生命周期

所以你可以这样理解:

Godot Scene可视化组件 + 物理对象 + 行为逻辑 + 资源引用

3. Node 是什么

Node 是 Godot 的最小功能单位。

每一种 Node 都有自己的职责。

比如:

Node                 最基础节点
Node2D               2D 节点基础类
Sprite2D             显示图片
CharacterBody2D      角色移动和碰撞
CollisionShape2D     碰撞形状
Camera2D             2D 摄像机
Area2D               区域检测
AudioStreamPlayer    播放音频
AnimationPlayer      播放动画
Control              UI 节点基础类
Button               按钮
Label                文本

一个 Node 本身可以很简单,也可以很强大。

例如:

Sprite2D

它的核心职责就是显示一张图片。

而:

CharacterBody2D

它的职责是做角色移动、碰撞处理、物理检测。

4. Scene 是什么

Scene 不是单纯的“地图”。

这是很多新手最容易误会的地方。

在 Godot 里,Scene 可以是:

一张地图
一个玩家
一个敌人
一个宝箱
一个 NPC
一个技能特效
一个 UI 面板
一个按钮
一个天气系统
一个背包系统
一个房间
一个房子
一个对话框

也就是说:

只要它是一组节点的组合,并且你想保存、复用、实例化,它就适合做成 Scene。

比如你做 RPG,可以有这些 Scene:

res://scenes/main.tscn
res://scenes/world/world_map.tscn
res://scenes/player/player.tscn
res://scenes/npc/villager.tscn
res://scenes/ui/hud.tscn
res://scenes/ui/dialog_box.tscn
res://scenes/items/chest.tscn
res://scenes/effects/rain_effect.tscn

这就很像前端项目里拆组件:

App.vue
Map.vue
Player.vue
Npc.vue
Hud.vue
DialogBox.vue
Chest.vue
RainEffect.vue

5. Scene 必须有一个根节点

每个 Scene 都有且只有一个根节点。

比如玩家场景:

Player CharacterBody2D
├── Sprite2D
├── CollisionShape2D
└── AnimationPlayer

这里的根节点是:

Player CharacterBody2D

比如主场景:

Main Node2D
├── World TileMapLayer
├── Player
├── Camera2D
└── UI CanvasLayer

这里的根节点是:

Main Node2D

这个根节点很重要,因为别人实例化这个 Scene 的时候,拿到的就是这个根节点。

比如你加载 player.tscn

var player_scene = preload("res://scenes/player.tscn")
var player = player_scene.instantiate()
add_child(player)

这里的 player 实际上就是 Player CharacterBody2D 这个根节点的实例。

6. Node 的父子关系

Godot 的节点是一棵树。

Main
├── World
├── Player
│   ├── Sprite2D
│   ├── CollisionShape2D
│   └── AnimationPlayer
└── UI
    ├── HealthBar
    └── InventoryButton

这里:

Main WorldPlayerUI 的父节点
Player Sprite2DCollisionShape2DAnimationPlayer 的父节点
Sprite2DCollisionShape2DAnimationPlayer 是兄弟节点

Godot 官方文档提到,一个节点可以包含任意数量的子节点,但同一个父节点下的直接子节点名称应该唯一。(Godot Engine documentation)

也就是说,这样可以:

Player
├── Sprite2D
└── CollisionShape2D

但不建议这样:

Player
├── Sprite2D
└── Sprite2D

因为同级重名会让查找路径变得混乱。

7. 节点路径 NodePath

Godot 通过路径找节点。

比如结构是:

Player
├── Sprite2D
└── Camera2D

Player 脚本里可以这样拿子节点:

var sprite = get_node("Sprite2D")
var camera = get_node("Camera2D")

Godot 有简写:

var sprite = $Sprite2D
var camera = $Camera2D

如果节点更深:

Player
└── UI
    └── HealthBar

可以这样:

var health_bar = $UI/HealthBar

官方文档也说明,可以用 Node.get_node() 获取节点引用,并且如果你想确保子节点已经存在,通常在父节点的 _ready() 中获取比较安全。(Godot Engine documentation)

8. $ 是什么

这个很常见。

$Sprite2D

基本等价于:

get_node("Sprite2D")

所以:

$Sprite2D.visible = false

等价于:

get_node("Sprite2D").visible = false

再比如:

$AnimationPlayer.play("walk")

意思是:

找到当前节点下面叫 AnimationPlayer 的子节点然后调用它的 play 方法

9. @onready 是什么

你经常会看到:

@onready var sprite: Sprite2D = $Sprite2D
@onready var animation_player: AnimationPlayer = $AnimationPlayer

意思是:

等节点进入场景并准备好之后,再获取这些子节点。

为什么要这样?

因为脚本刚加载的时候,子节点可能还没完全准备好。

所以这种写法很常见:

extends CharacterBody2D

@onready var sprite: Sprite2D = $Sprite2D
@onready var animation_player: AnimationPlayer = $AnimationPlayer

func _ready():
    animation_player.play("idle")

你可以把它类比成前端里的:

const ref = useRef(null)

useEffect(() => {
  // DOM 已经挂载后再操作
}, [])

不是完全一样,但理解上很接近。

10. Scene 文件和运行时实例不是一回事

这是非常关键的一点。

假设你有一个文件:

res://scenes/player.tscn

它只是一个场景资源文件。

它还不是游戏里真正跑起来的玩家。

当你把它放进主场景,或者通过代码实例化:

var player_scene = preload("res://scenes/player.tscn")
var player = player_scene.instantiate()
add_child(player)

这时才产生了一个真正存在于游戏里的玩家节点。

前端类比

组件定义:

function Player() {
  return <div>Player</div>
}

还不是真实 DOM。

使用它:

<Player />

React 渲染之后,才有真实 DOM。

Godot 也是:

player.tscn        场景模板
Player 实例        运行时对象

11. 一个 Scene 可以实例化很多次

比如你做一个史莱姆敌人:

res://scenes/enemies/slime.tscn

它的结构是:

Slime CharacterBody2D
├── Sprite2D
├── CollisionShape2D
└── AnimationPlayer

你可以在地图上放很多个:

World
├── Slime
├── Slime2
├── Slime3
├── Slime4
└── Slime5

它们都来自同一个 slime.tscn,但运行时是不同实例。

类似前端里:

{slimes.map(slime => <Slime key={slime.id} />)}

同一个组件,渲染出多个实例。

Godot 官方文档也有专门的 “Creating instances” 教程,用来说明如何把一个场景作为实例添加到另一个场景中。(Godot Engine documentation)

12. Scene 嵌套 Scene

Godot 的强大之处就在这里。

你可以用 Scene 组成更大的 Scene。

比如:

Player.tscn

内容:

Player CharacterBody2D
├── Sprite2D
├── CollisionShape2D
└── AnimationPlayer

然后主场景:

Main.tscn

内容:

Main Node2D
├── World TileMapLayer
├── Player这是 player.tscn 的实例
├── Camera2D
└── UI

再比如 UI 也可以是一个 Scene:

HUD.tscn

内容:

HUD CanvasLayer
├── HealthBar
├── ManaBar
└── InventoryButton

主场景里:

Main Node2D
├── World
├── Player
└── HUDhud.tscn 的实例

这样项目结构就会很清楚。

13. 编辑器里的 Scene 和运行时的 SceneTree

Godot 里有两个很容易混的概念:

Scene
SceneTree

Scene

Scene 是你保存的场景文件。

比如:

player.tscn
main.tscn
hud.tscn

它们在磁盘上。

SceneTree

SceneTree 是游戏运行时真正活着的节点树。

官方文档说明,SceneTree 负责管理节点层级和场景本身,节点可以被添加、获取和移除,当前场景也可以被暂停、切换或重新加载。(Godot Engine documentation)

可以这样理解:

Scene 文件 = 设计图纸
SceneTree = 游戏运行时真正搭起来的建筑

14. 节点什么时候才算“活了”

一个节点只有进入 SceneTree 后,才真正参与游戏运行。

官方文档的 SceneTree 教程里说,一个场景被加载或通过脚本创建后,它的根节点会被加入 root Viewport 或其子节点中;新加入场景的每个节点会收到 enter_tree 通知,对应 GDScript 的 _enter_tree() 回调。(Godot Engine documentation)

所以流程大概是:

1. 加载 scene 文件
2. instantiate 生成节点实例
3. add_child 加入 SceneTree
4. 节点进入树
5. 调用 _enter_tree
6. 调用 _ready
7. 开始 _process / _physics_process

代码:

var enemy_scene = preload("res://scenes/enemies/slime.tscn")
var enemy = enemy_scene.instantiate()

add_child(enemy)

只有执行了:

add_child(enemy)

这个敌人才真正进入当前场景树。

15. 生命周期顺序

你以后会经常用这些方法:

func _enter_tree():
    pass

func _ready():
    pass

func _process(delta):
    pass

func _physics_process(delta):
    pass

func _exit_tree():
    pass

_enter_tree

节点进入 SceneTree 时触发。

func _enter_tree():
    print("我进入场景树了")

适合做一些比较早的初始化。

_ready

节点和它的子节点都准备好后触发。

func _ready():
    print("我准备好了")

最常用。

你一般可以在这里获取子节点、初始化状态、连接信号。

@onready var sprite = $Sprite2D

func _ready():
    sprite.visible = true

官方 Node 文档中也提到,节点加入 SceneTree 时父节点的 _enter_tree() 会先于子节点触发;而 _ready() 是在节点及其子节点都进入树之后触发。(Godot Engine documentation)

_process

每帧调用。

func _process(delta):
    rotation += delta

适合:

视觉效果
普通计时
非物理更新
UI 动态变化
简单动画逻辑

_physics_process

固定物理帧调用。

func _physics_process(delta):
    move_and_slide()

适合:

角色移动
碰撞判断
物理相关逻辑

_exit_tree

节点离开 SceneTree 时调用。

func _exit_tree():
    print("我离开场景树了")

适合清理逻辑。

16. 常用节点操作方法

add_child

添加子节点。

add_child(enemy)

意思是:

 enemy 加到当前节点下面

前端类比:

parent.appendChild(enemyElement)

remove_child

从父节点移除子节点。

remove_child(enemy)

注意:这只是从节点树中移除,不一定销毁内存。

可以理解为:

先从场景里拿掉但对象可能还在

queue_free

安全删除节点。

enemy.queue_free()

这个非常常用。

比如:

func die():
    queue_free()

常见场景:

敌人死亡
子弹命中后消失
特效播放完删除
临时 UI 关闭
掉落物被拾取

get_parent

获取父节点。

var parent = get_parent()

比如:

get_parent().add_child(effect)

意思是把 effect 加到当前节点的父节点下面。

get_tree

获取 SceneTree。

var tree = get_tree()

常用于:

切换场景
暂停游戏
获取当前场景
调用分组节点
退出游戏

比如:

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

17. PackedScene 是什么

你以后会经常看到:

var enemy_scene: PackedScene = preload("res://scenes/enemies/slime.tscn")

PackedScene 可以理解为:

打包好的场景资源

它还不是节点。

你需要调用:

instantiate()

才会生成节点实例。

完整写法:

extends Node2D

@export var slime_scene: PackedScene

func spawn_slime():
    var slime = slime_scene.instantiate()
    add_child(slime)
    slime.position = Vector2(200, 100)

如果不用 Inspector 暴露,也可以这样:

const SLIME_SCENE = preload("res://scenes/enemies/slime.tscn")

func spawn_slime():
    var slime = SLIME_SCENE.instantiate()
    add_child(slime)

官方的 “Nodes and scene instances” 文档也把“获取节点、创建节点、添加子节点、从代码实例化场景”放在一起讲,因为这几个操作本质上都是在操作运行时节点树。(Godot Engine documentation)

18. preload 和 load 的区别

常见写法:

const PLAYER_SCENE = preload("res://scenes/player.tscn")

还有:

var player_scene = load("res://scenes/player.tscn")

简单理解:

preload脚本加载时提前加载资源
load运行到这一行时再加载资源

入门阶段你可以先记:

固定会用到的资源 preload
运行时根据条件才加载的资源 load

比如玩家、子弹、常用敌人:

const BULLET_SCENE = preload("res://scenes/bullet.tscn")

比如根据地图名加载不同地图:

var map_scene = load("res://scenes/maps/%s.tscn" % map_name)

19. 创建节点的两种方式

方式一:编辑器里创建

适合固定结构。

比如 Player:

Player CharacterBody2D
├── Sprite2D
├── CollisionShape2D
└── AnimationPlayer

这种结构一般在编辑器里搭好。

方式二:代码里创建

适合动态生成。

比如运行时生成一个 Label:

func create_label():
    var label = Label.new()
    label.text = "Hello Godot"
    add_child(label)

生成一个 Sprite2D:

func create_sprite():
    var sprite = Sprite2D.new()
    sprite.texture = preload("res://assets/player.png")
    add_child(sprite)

不过入门时建议:

复杂对象做成 Scene然后 instantiate
简单临时节点可以用 .new()

比如敌人、子弹、道具,推荐做成 Scene:

var bullet = bullet_scene.instantiate()
add_child(bullet)

不要每次都代码手搓:

var bullet = CharacterBody2D.new()
var sprite = Sprite2D.new()
var collision = CollisionShape2D.new()
...

那样维护起来会很累。

20. 一个 RPG 项目的场景拆分示例

你现在想做类似星露谷、RPG、玄幻小镇这种游戏,可以这样拆:

scenes/
├── main.tscn
├── world/
│   ├── outdoor_map.tscn
│   ├── house_interior.tscn
│   └── dungeon_01.tscn
├── player/
│   └── player.tscn
├── npc/
│   ├── villager.tscn
│   └── merchant.tscn
├── items/
│   ├── chest.tscn
│   ├── dropped_item.tscn
│   └── collectable.tscn
├── ui/
│   ├── hud.tscn
│   ├── dialog_box.tscn
│   └── inventory_panel.tscn
└── systems/
    ├── weather_manager.tscn
    ├── time_manager.tscn
    └── audio_manager.tscn

主场景可以是:

Main Node
├── World Node2D
├── Player
├── Systems Node
│   ├── WeatherManager
│   ├── TimeManager
│   └── AudioManager
└── UI CanvasLayer
    ├── HUD
    └── DialogBox

这样拆的好处是:

地图可以单独改
玩家可以单独改
UI 可以单独改
天气系统可以单独改
时间系统可以单独改
NPC 可以复用
宝箱可以复用

这就很像前端项目里拆模块。

21. 什么时候做成一个 Scene

这个判断很重要。

适合做成 Scene 的东西

满足以下任意条件,就适合做成 Scene:

会重复使用
结构比较复杂
有自己的脚本逻辑
需要单独编辑和测试
可能被动态生成
可能被其他场景嵌套

比如:

Player
Slime
NPC
Chest
Door
DialogBox
InventoryPanel
RainEffect
FireballSkill
SavePoint

都适合做 Scene。

不一定需要单独做 Scene 的东西

一个普通 Sprite2D
一个简单 Label
一个临时 Debug 节点
一个纯装饰小物件

当然,如果后面它变复杂了,也可以再拆成 Scene。

22. 什么时候只是一个 Node

如果它只是某个对象的一部分,通常只是子节点。

比如玩家里的:

Sprite2D
CollisionShape2D
AnimationPlayer

它们是 Player 的组成部分,不一定单独保存成 Scene。

宝箱里的:

Chest StaticBody2D
├── Sprite2D
├── CollisionShape2D
├── Area2D
└── AnimationPlayer

这里 Sprite2DCollisionShape2DArea2D 是宝箱的零件。

整个 Chest 适合保存为 Scene。

23. 节点命名建议

Godot 项目里,节点命名很重要。

不建议这样:

Node2D
├── Sprite2D
├── Sprite2D2
├── Area2D
└── CollisionShape2D

建议这样:

Player CharacterBody2D
├── BodySprite Sprite2D
├── Hitbox Area2D
├── CollisionShape2D
└── AnimationPlayer

或者:

Chest StaticBody2D
├── ClosedSprite Sprite2D
├── OpenArea Area2D
├── CollisionShape2D
└── AnimationPlayer

因为你代码里经常会写:

@onready var body_sprite = $BodySprite
@onready var hitbox = $Hitbox

如果名字全是默认的 Sprite2DArea2D,后面会越来越难看。

24. 不要让节点关系太乱

新手很容易把所有东西都塞进一个大场景:

Main
├── TileMapLayer
├── Player
├── Enemy1
├── Enemy2
├── Enemy3
├── NPC1
├── NPC2
├── Chest1
├── Chest2
├── Rain
├── Snow
├── DialogBox
├── Inventory
├── HealthBar
├── TimeLabel
├── Audio1
├── Audio2
└── ...

短期能跑,长期会乱。

更推荐:

Main
├── World
│   ├── TileMapLayer
│   ├── Objects
│   ├── NPCs
│   └── Enemies
├── Player
├── Systems
│   ├── WeatherManager
│   ├── TimeManager
│   └── AudioManager
└── UI
    ├── HUD
    ├── DialogBox
    └── InventoryPanel

这样你一看就知道:

World 管地图和世界对象
Player 管玩家
Systems 管全局系统
UI 管界面

25. 一个完整小例子:生成敌人

假设你有一个敌人场景:

res://scenes/enemies/slime.tscn

结构:

Slime CharacterBody2D
├── Sprite2D
├── CollisionShape2D
└── AnimationPlayer

然后你在主场景里有一个生成器:

Main Node2D
├── EnemySpawner Node2D
└── Enemies Node2D

EnemySpawner.gd

extends Node2D

@export var slime_scene: PackedScene
@export var enemies_root: Node2D

func spawn_slime(spawn_position: Vector2):
    var slime = slime_scene.instantiate()
    enemies_root.add_child(slime)
    slime.global_position = spawn_position

这里发生了什么?

1. slime_scene 是一个 PackedScene 资源
2. instantiate() 创建了一个 Slime 节点实例
3. enemies_root.add_child(slime) 把它加入场景树
4. slime.global_position 设置它在世界中的位置

这就是 Godot 里“动态生成对象”的标准思路。

26. position 和 global_position

这个也要早点理解。

如果节点结构是:

World Node2D
└── Player CharacterBody2D

Player.position 表示它相对于父节点 World 的位置。

Player.global_position 表示它在整个世界坐标中的位置。

如果父节点没有移动,两者可能一样。

但如果父节点移动了:

World.position = Vector2(100, 100)
Player.position = Vector2(50, 50)

那么:

Player.position = Vector2(50, 50)
Player.global_position = Vector2(150, 150)

简单记:

position相对父节点
global_position世界坐标

前端类比:

position相对父容器的 left/top
global_position页面整体坐标中的 left/top

27. owner 是什么,先简单知道

这个可以先不用深究,但你以后可能会遇到。

owner 跟“节点是否会被保存到场景文件”有关。

如果你在编辑器里创建节点,它通常会有正确的 owner。

如果你在代码里动态创建节点,它默认只是运行时对象,不一定会保存进 .tscn 文件。

入门阶段记一句就行:

运行时 add_child 出来的节点通常只是运行时存在不会自动写回场景文件

这个对编辑器插件或运行时生成并保存场景时比较重要,普通游戏逻辑暂时不用纠结。

28. 新手常见误区

误区 1:Scene 就是地图

不是。

Scene 可以是任何节点树。

玩家是 Scene
敌人是 Scene
UI Scene
特效是 Scene
地图也是 Scene

误区 2:节点在文件里存在,就等于运行时存在

不是。

player.tscn 是文件
实例化并 add_child才是运行时对象

误区 3:instantiate 后就能显示

不一定。

你只是生成了对象:

var player = player_scene.instantiate()

但还没有加入场景树。

还需要:

add_child(player)

误区 4:queue_free 和 remove_child 是一回事

不是。

remove_child(node)

是从父节点移除。

node.queue_free()

是安全删除节点。

大多数“不要这个对象了”的情况,用:

queue_free()

误区 5:节点路径随便写

不行。

如果结构是:

Player
└── Visual
    └── Sprite2D

你不能写:

$Sprite2D

应该写:

$Visual/Sprite2D

或者:

get_node("Visual/Sprite2D")

29. 这一章你应该记住的核心

1. Node Godot 的功能单位
2. Scene 是一棵 Node
3. Scene 可以保存成 .tscn 文件
4. Scene 可以实例化到其他 Scene
5. 运行时真正活着的是 SceneTree 里的节点实例
6. instantiate() 只是创建实例
7. add_child() 才是加入场景树
8. $NodeName get_node("NodeName") 的简写
9. @onready 常用于安全获取子节点
10. 复杂可复用对象应该做成独立 Scene

最后用一句话收尾

Godot 的开发方式不是“一个大脚本控制全世界”,而是“把游戏拆成一棵棵 Scene,每个 Scene 由多个 Node 组成,再让这些 Scene 互相组合、复用、实例化”。

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

分享文章

相关文章

更多文章 →
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 官方文档也把节点和场景放在一起讲:多个节点组成树状结构后...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录