13. 游戏场景搭建
游戏场景搭建
什么是场景(Scene)
想象一下你在拍一部电影。每一场戏都有自己的"布景"——有桌子、椅子、灯光、道具。在 Godot 里,场景就相当于电影里的一个"布景"。
一个场景包含:
- 节点(Node):就像布景里的每一样东西——一张桌子、一盏灯、一个演员,都是一个"节点"
- 场景树(Scene Tree):所有节点按层级关系组织在一起,就像一棵倒过来的树
场景 vs 节点
节点是最小的单位(比如一个方块、一盏灯)。场景是多个节点组合在一起形成的一个整体(比如一个"房间"场景里包含了墙壁、地板、灯等节点)。
一个场景可以保存为 .tscn 文件,然后在其他场景里反复使用——就像你可以把一套布景存起来,下次拍戏直接搬出来用。
Node3D 根节点的使用
在 3D 游戏中,每个场景的根节点通常是 Node3D。你可以把 Node3D 想象成一个"容器盒子",它的作用是:
- 组织子节点:所有 3D 对象都放在这个容器里
- 统一变换:移动这个容器,里面所有东西一起移动、旋转、缩放
- 方便管理:你可以把整个容器当作一个整体来操作
创建步骤:
- 点击编辑器左上角的 "+" 按钮
- 搜索
Node3D,选中后点击 创建 - 这个
Node3D就是你的场景根节点
// 用代码创建一个 Node3D 场景根节点
using Godot;
public partial class GameScene : Node3D
{
public override void _Ready()
{
// 场景加载完成时执行
GD.Print("场景已加载!");
// 设置场景根节点的位置
Position = new Vector3(0, 0, 0);
}
}# 用代码创建一个 Node3D 场景根节点
extends Node3D
func _ready():
# 场景加载完成时执行
print("场景已加载!")
# 设置场景根节点的位置
position = Vector3(0, 0, 0)场景树的概念
场景里的节点之间有父子关系——就像俄罗斯套娃,大娃娃里面套着小娃娃。
- 父节点移动、旋转、缩放时,所有子节点跟着一起变化
- 子节点也可以有自己的子节点,形成多层嵌套
为什么要用父子关系?
假设你做了一个"桌子"场景,桌面上放了一个"花瓶"。如果你把花瓶设为桌子的子节点,那么当你移动桌子时,花瓶会自动跟着走——不需要你手动移动两样东西。这就是父子关系的威力。
CSG 几何体快速搭建场景原型
CSG 的全称是 Constructive Solid Geometry(构造实体几何)。听起来很专业,但其实就是用基本形状(方块、球、圆柱等)像搭积木一样快速搭建场景。
CSG 节点的优势:
- 不需要 3D 建模软件:直接在 Godot 编辑器里拖拽就能搭建
- 快速原型:先用简单形状验证游戏设计,再替换成精美的 3D 模型
- 支持布尔运算:可以挖洞、合并形状,做出复杂结构
CSGBox3D —— 方块
方块是最常用的 CSG 形状,可以用来做墙壁、地板、天花板等。
// 创建一个 CSGBox3D 作为地板
using Godot;
public partial class FloorBlock : CSGBox3D
{
public override void _Ready()
{
// 设置方块大小:宽10米 x 厚0.2米 x 深10米
Size = new Vector3(10, 0.2f, 10);
// 设置位置(Y轴向下偏移,让地板在地面位置)
Position = new Vector3(0, -0.1f, 0);
// 设置材质颜色
var material = new StandardMaterial3D();
material.AlbedoColor = new Color(0.8f, 0.8f, 0.8f); // 灰色
Material = material;
}
}# 创建一个 CSGBox3D 作为地板
extends CSGBox3D
func _ready():
# 设置方块大小:宽10米 x 厚0.2米 x 深10米
size = Vector3(10, 0.2, 10)
# 设置位置(Y轴向下偏移,让地板在地面位置)
position = Vector3(0, -0.1, 0)
# 设置材质颜色
var material = StandardMaterial3D.new()
material.albedo_color = Color(0.8, 0.8, 0.8) # 灰色
material_override = materialCSGSphere3D —— 球体
球体可以用来做石球、柱子底座、天体等。
// 创建一个 CSGSphere3D 作为装饰球
using Godot;
public partial class DecorativeSphere : CSGSphere3D
{
public override void _Ready()
{
// 设置球体半径
Radius = 1.0;
// 设置细分度(越大越圆滑,但越耗性能)
RadialSegments = 16;
Rings = 8;
// 设置位置
Position = new Vector3(2, 1, 3);
// 红色材质
var material = new StandardMaterial3D();
material.AlbedoColor = new Color(1.0f, 0.2f, 0.2f);
Material = material;
}
}# 创建一个 CSGSphere3D 作为装饰球
extends CSGSphere3D
func _ready():
# 设置球体半径
radius = 1.0
# 设置细分度(越大越圆滑,但越耗性能)
radial_segments = 16
rings = 8
# 设置位置
position = Vector3(2, 1, 3)
# 红色材质
var material = StandardMaterial3D.new()
material.albedo_color = Color(1.0, 0.2, 0.2)
material_override = materialCSGCylinder3D —— 圆柱体
圆柱体可以用来做柱子、管道、树木等。
// 创建一个 CSGCylinder3D 作为柱子
using Godot;
public partial class Pillar : CSGCylinder3D
{
public override void _Ready()
{
// 设置半径和高度
Radius = 0.3f;
Height = 3.0f;
// 设置细分度
Sides = 12;
// 位置
Position = new Vector3(4, 1.5f, 4);
// 白色材质
var material = new StandardMaterial3D();
material.AlbedoColor = new Color(0.95f, 0.95f, 0.9f);
Material = material;
}
}# 创建一个 CSGCylinder3D 作为柱子
extends CSGCylinder3D
func _ready():
# 设置半径和高度
radius = 0.3
height = 3.0
# 设置细分度
sides = 12
# 位置
position = Vector3(4, 1.5, 4)
# 白色材质
var material = StandardMaterial3D.new()
material.albedo_color = Color(0.95, 0.95, 0.9)
material_override = materialCSGTorus3D —— 圆环体
圆环体可以用来做轮胎、拱门、环形装饰等。
// 创建一个 CSGTorus3D 作为环形装饰
using Godot;
public partial class DecorativeTorus : CSGTorus3D
{
public override void _Ready()
{
// 内半径和外半径
InnerRadius = 0.8f;
OuterRadius = 1.2f;
// 细分度
Sides = 16;
RingSides = 8;
// 位置
Position = new Vector3(0, 3, 0);
// 金色材质
var material = new StandardMaterial3D();
material.AlbedoColor = new Color(1.0f, 0.84f, 0.0f);
Material = material;
}
}# 创建一个 CSGTorus3D 作为环形装饰
extends CSGTorus3D
func _ready():
# 内半径和外半径
inner_radius = 0.8
outer_radius = 1.2
# 细分度
sides = 16
ring_sides = 8
# 位置
position = Vector3(0, 3, 0)
# 金色材质
var material = StandardMaterial3D.new()
material.albedo_color = Color(1.0, 0.84, 0.0)
material_override = material用 CSG 组合搭建一个简单房间
现在让我们把前面学到的知识综合起来,用 CSG 搭建一个完整的房间。这个房间包含:地板、四面墙壁、天花板,以及墙壁上的门洞和窗户。
// 用代码搭建一个完整的 CSG 房间
using Godot;
using System.Collections.Generic;
public partial class SimpleRoom : Node3D
{
// 房间参数
private const float RoomWidth = 8.0f; // 房间宽度(X轴)
private const float RoomHeight = 3.0f; // 房间高度(Y轴)
private const float RoomDepth = 6.0f; // 房间深度(Z轴)
private const float WallThickness = 0.2f; // 墙壁厚度
public override void _Ready()
{
CreateFloor();
CreateCeiling();
CreateWalls();
AddLighting();
AddCamera();
GD.Print("房间搭建完成!");
}
/// <summary>创建地板</summary>
private void CreateFloor()
{
var floor = new CSGBox3D();
floor.Name = "Floor";
floor.Size = new Vector3(RoomWidth, WallThickness, RoomDepth);
floor.Position = new Vector3(0, -WallThickness / 2, 0);
var mat = new StandardMaterial3D();
mat.AlbedoColor = new Color(0.6f, 0.5f, 0.4f); // 木地板色
floor.Material = mat;
AddChild(floor);
}
/// <summary>创建天花板</summary>
private void CreateCeiling()
{
var ceiling = new CSGBox3D();
ceiling.Name = "Ceiling";
ceiling.Size = new Vector3(RoomWidth, WallThickness, RoomDepth);
ceiling.Position = new Vector3(0, RoomHeight + WallThickness / 2, 0);
var mat = new StandardMaterial3D();
mat.AlbedoColor = new Color(0.9f, 0.9f, 0.9f); // 白色天花板
ceiling.Material = mat;
AddChild(ceiling);
}
/// <summary>创建四面墙壁(含门洞和窗户)</summary>
private void CreateWalls()
{
// === 前墙(带门洞) ===
var frontWall = CreateWall(
"FrontWall",
new Vector3(RoomWidth, RoomHeight, WallThickness),
new Vector3(0, RoomHeight / 2, RoomDepth / 2)
);
// 用布尔减法挖出门洞
var doorHole = new CSGBox3D();
doorHole.Size = new Vector3(1.2f, 2.2f, WallThickness + 0.1f);
doorHole.Position = new Vector3(0, 1.1f, 0);
doorHole.Operation = CSGShape3D.OperationEnum.Subtraction;
frontWall.AddChild(doorHole);
// === 后墙(带窗户) ===
var backWall = CreateWall(
"BackWall",
new Vector3(RoomWidth, RoomHeight, WallThickness),
new Vector3(0, RoomHeight / 2, -RoomDepth / 2)
);
// 挖出窗户
var windowHole = new CSGBox3D();
windowHole.Size = new Vector3(2.0f, 1.2f, WallThickness + 0.1f);
windowHole.Position = new Vector3(0, 1.8f, 0);
windowHole.Operation = CSGShape3D.OperationEnum.Subtraction;
backWall.AddChild(windowHole);
// === 左墙 ===
CreateWall(
"LeftWall",
new Vector3(WallThickness, RoomHeight, RoomDepth),
new Vector3(-RoomWidth / 2, RoomHeight / 2, 0)
);
// === 右墙 ===
CreateWall(
"RightWall",
new Vector3(WallThickness, RoomHeight, RoomDepth),
new Vector3(RoomWidth / 2, RoomHeight / 2, 0)
);
}
/// <summary>创建单面墙壁的辅助方法</summary>
private CSGBox3D CreateWall(string name, Vector3 size, Vector3 position)
{
var wall = new CSGBox3D();
wall.Name = name;
wall.Size = size;
wall.Position = position;
var mat = new StandardMaterial3D();
mat.AlbedoColor = new Color(0.85f, 0.82f, 0.78f); // 米色墙壁
wall.Material = mat;
AddChild(wall);
return wall;
}
/// <summary>添加灯光</summary>
private void AddLighting()
{
// 环境光
var worldEnv = new WorldEnvironment();
var env = new Environment();
env.AmbientLightSource = Environment.AmbientSource.Color;
env.AmbientLightColor = new Color(0.5f, 0.5f, 0.55f);
worldEnv.Environment = env;
AddChild(worldEnv);
// 天花板灯
var light = new OmniLight3D();
light.Position = new Vector3(0, RoomHeight - 0.3f, 0);
light.LightColor = new Color(1.0f, 0.95f, 0.8f);
light.LightEnergy = 1.5f;
light.OmniRange = 15.0f;
AddChild(light);
}
/// <summary>添加摄像机</summary>
private void AddCamera()
{
var camera = new Camera3D();
camera.Position = new Vector3(0, 1.7f, 2);
camera.LookAt(new Vector3(0, 1.5f, 0), Vector3.Up);
AddChild(camera);
}
}# 用代码搭建一个完整的 CSG 房间
extends Node3D
# 房间参数
const ROOM_WIDTH = 8.0 # 房间宽度(X轴)
const ROOM_HEIGHT = 3.0 # 房间高度(Y轴)
const ROOM_DEPTH = 6.0 # 房间深度(Z轴)
const WALL_THICKNESS = 0.2 # 墙壁厚度
func _ready():
create_floor()
create_ceiling()
create_walls()
add_lighting()
add_camera()
print("房间搭建完成!")
## 创建地板
func create_floor():
var floor_box = CSGBox3D.new()
floor_box.name = "Floor"
floor_box.size = Vector3(ROOM_WIDTH, WALL_THICKNESS, ROOM_DEPTH)
floor_box.position = Vector3(0, -WALL_THICKNESS / 2.0, 0)
var mat = StandardMaterial3D.new()
mat.albedo_color = Color(0.6, 0.5, 0.4) # 木地板色
floor_box.material_override = mat
add_child(floor_box)
## 创建天花板
func create_ceiling():
var ceiling = CSGBox3D.new()
ceiling.name = "Ceiling"
ceiling.size = Vector3(ROOM_WIDTH, WALL_THICKNESS, ROOM_DEPTH)
ceiling.position = Vector3(0, ROOM_HEIGHT + WALL_THICKNESS / 2.0, 0)
var mat = StandardMaterial3D.new()
mat.albedo_color = Color(0.9, 0.9, 0.9) # 白色天花板
ceiling.material_override = mat
add_child(ceiling)
## 创建四面墙壁(含门洞和窗户)
func create_walls():
# === 前墙(带门洞) ===
var front_wall = create_wall(
"FrontWall",
Vector3(ROOM_WIDTH, ROOM_HEIGHT, WALL_THICKNESS),
Vector3(0, ROOM_HEIGHT / 2.0, ROOM_DEPTH / 2.0)
)
# 用布尔减法挖出门洞
var door_hole = CSGBox3D.new()
door_hole.size = Vector3(1.2, 2.2, WALL_THICKNESS + 0.1)
door_hole.position = Vector3(0, 1.1, 0)
door_hole.operation = CSGShape3D.OPERATION_SUBTRACTION
front_wall.add_child(door_hole)
# === 后墙(带窗户) ===
var back_wall = create_wall(
"BackWall",
Vector3(ROOM_WIDTH, ROOM_HEIGHT, WALL_THICKNESS),
Vector3(0, ROOM_HEIGHT / 2.0, -ROOM_DEPTH / 2.0)
)
# 挖出窗户
var window_hole = CSGBox3D.new()
window_hole.size = Vector3(2.0, 1.2, WALL_THICKNESS + 0.1)
window_hole.position = Vector3(0, 1.8, 0)
window_hole.operation = CSGShape3D.OPERATION_SUBTRACTION
back_wall.add_child(window_hole)
# === 左墙 ===
create_wall(
"LeftWall",
Vector3(WALL_THICKNESS, ROOM_HEIGHT, ROOM_DEPTH),
Vector3(-ROOM_WIDTH / 2.0, ROOM_HEIGHT / 2.0, 0)
)
# === 右墙 ===
create_wall(
"RightWall",
Vector3(WALL_THICKNESS, ROOM_HEIGHT, ROOM_DEPTH),
Vector3(ROOM_WIDTH / 2.0, ROOM_HEIGHT / 2.0, 0)
)
## 创建单面墙壁的辅助方法
func create_wall(wall_name: String, wall_size: Vector3, wall_pos: Vector3) -> CSGBox3D:
var wall = CSGBox3D.new()
wall.name = wall_name
wall.size = wall_size
wall.position = wall_pos
var mat = StandardMaterial3D.new()
mat.albedo_color = Color(0.85, 0.82, 0.78) # 米色墙壁
wall.material_override = mat
add_child(wall)
return wall
## 添加灯光
func add_lighting():
# 环境光
var world_env = WorldEnvironment.new()
var env = Environment.new()
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
env.ambient_light_color = Color(0.5, 0.5, 0.55)
world_env.environment = env
add_child(world_env)
# 天花板灯
var light = OmniLight3D.new()
light.position = Vector3(0, ROOM_HEIGHT - 0.3, 0)
light.light_color = Color(1.0, 0.95, 0.8)
light.light_energy = 1.5
light.omni_range = 15.0
add_child(light)
## 添加摄像机
func add_camera():
var camera = Camera3D.new()
camera.position = Vector3(0, 1.7, 2)
camera.look_at(Vector3(0, 1.5, 0), Vector3.UP)
add_child(camera)场景实例化(Instance)
场景实例化就像"复印"——你设计好一张图纸(场景),然后可以印出无数份副本(实例),每份副本都一模一样但可以独立使用。
// 场景实例化示例
using Godot;
public partial class SceneManager : Node3D
{
// 引用房间场景的路径
[Export]
public PackedScene RoomScene { get; set; }
public override void _Ready()
{
// 方法1:通过代码加载场景文件
var packedScene = GD.Load<PackedScene>("res://scenes/simple_room.tscn");
// 实例化第一个房间
var room1 = packedScene.Instantiate<Node3D>();
room1.Position = new Vector3(0, 0, 0);
room1.Name = "Room1";
AddChild(room1);
// 实例化第二个房间(完全相同的副本)
var room2 = packedScene.Instantiate<Node3D>();
room2.Position = new Vector3(10, 0, 0); // 放在右边10米处
room2.Name = "Room2";
AddChild(room2);
// 方法2:通过 Export 属性在编辑器中拖拽指定场景
if (RoomScene != null)
{
var room3 = RoomScene.Instantiate<Node3D>();
room3.Position = new Vector3(-10, 0, 0);
room3.Name = "Room3";
AddChild(room3);
}
}
}# 场景实例化示例
extends Node3D
# 引用房间场景(在编辑器中拖拽指定)
@export var room_scene: PackedScene
func _ready():
# 方法1:通过代码加载场景文件
var packed_scene = load("res://scenes/simple_room.tscn")
# 实例化第一个房间
var room1 = packed_scene.instantiate()
room1.position = Vector3(0, 0, 0)
room1.name = "Room1"
add_child(room1)
# 实例化第二个房间(完全相同的副本)
var room2 = packed_scene.instantiate()
room2.position = Vector3(10, 0, 0) # 放在右边10米处
room2.name = "Room2"
add_child(room2)
# 方法2:通过 export 变量在编辑器中拖拽指定场景
if room_scene:
var room3 = room_scene.instantiate()
room3.position = Vector3(-10, 0, 0)
room3.name = "Room3"
add_child(room3)静态碰撞体添加
纯 CSG 节点只有外观,没有碰撞——角色会直接穿过去。要让玩家能在房间里走动,需要添加静态碰撞体。
// 为 CSG 房间添加静态碰撞体
using Godot;
public partial class RoomWithCollision : Node3D
{
public override void _Ready()
{
// 创建地板碰撞
AddStaticCollision(
"FloorCollision",
new Vector3(8, 0.2f, 6),
new Vector3(0, -0.1f, 0)
);
// 创建前墙碰撞
AddStaticCollision(
"FrontWallCollision",
new Vector3(8, 3, 0.2f),
new Vector3(0, 1.5f, 3)
);
// 创建后墙碰撞
AddStaticCollision(
"BackWallCollision",
new Vector3(8, 3, 0.2f),
new Vector3(0, 1.5f, -3)
);
GD.Print("碰撞体添加完成!");
}
/// <summary>
/// 创建一个静态碰撞体
/// </summary>
private void AddStaticCollision(string name, Vector3 boxSize, Vector3 position)
{
var body = new StaticBody3D();
body.Name = name;
body.Position = position;
var shape = new CollisionShape3D();
var boxShape = new BoxShape3D();
boxShape.Size = boxSize;
shape.Shape = boxShape;
body.AddChild(shape);
AddChild(body);
}
}# 为 CSG 房间添加静态碰撞体
extends Node3D
func _ready():
# 创建地板碰撞
add_static_collision(
"FloorCollision",
Vector3(8, 0.2, 6),
Vector3(0, -0.1, 0)
)
# 创建前墙碰撞
add_static_collision(
"FrontWallCollision",
Vector3(8, 3, 0.2),
Vector3(0, 1.5, 3)
)
# 创建后墙碰撞
add_static_collision(
"BackWallCollision",
Vector3(8, 3, 0.2),
Vector3(0, 1.5, -3)
)
print("碰撞体添加完成!")
## 创建一个静态碰撞体
func add_static_collision(collision_name: String, box_size: Vector3, pos: Vector3):
var body = StaticBody3D.new()
body.name = collision_name
body.position = pos
var shape = CollisionShape3D.new()
var box_shape = BoxShape3D.new()
box_shape.size = box_size
shape.shape = box_shape
body.add_child(shape)
add_child(body)世界环境设置
WorldEnvironment 节点用来设置整个游戏世界的"氛围"——天空颜色、雾效、环境光等。就像现实世界中天气和光照影响你看到的一切。
// 设置世界环境
using Godot;
public partial class GameWorldEnvironment : WorldEnvironment
{
public override void _Ready()
{
var env = new Environment();
// 1. 设置背景(天空)
env.BackgroundMode = Environment.BgMode.Color;
env.BackgroundColor = new Color(0.4f, 0.6f, 0.9f); // 淡蓝色天空
// 2. 设置环境光
env.AmbientLightSource = Environment.AmbientSource.Color;
env.AmbientLightColor = new Color(0.4f, 0.45f, 0.55f);
env.AmbientLightEnergy = 0.8;
// 3. 设置雾效
env.FogEnabled = true;
env.FogLightColor = new Color(0.6f, 0.65f, 0.7f);
env.FogDepthBegin = 20.0f;
env.FogDepthEnd = 80.0f;
// 4. 设置色调映射(让画面更自然)
env.ToneMapper = Environment.ToneMapper.Aces;
Environment = env;
GD.Print("世界环境设置完成!");
}
}# 设置世界环境
extends WorldEnvironment
func _ready():
var env = Environment.new()
# 1. 设置背景(天空)
env.background_mode = Environment.BG_COLOR
env.background_color = Color(0.4, 0.6, 0.9) # 淡蓝色天空
# 2. 设置环境光
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
env.ambient_light_color = Color(0.4, 0.45, 0.55)
env.ambient_light_energy = 0.8
# 3. 设置雾效
env.fog_enabled = true
env.fog_light_color = Color(0.6, 0.65, 0.7)
env.fog_depth_begin = 20.0
env.fog_depth_end = 80.0
# 4. 设置色调映射(让画面更自然)
env.tone_mapper = Environment.TONE_MAPPER_ACES
environment = env
print("世界环境设置完成!")场景树结构总览
常见问题
场景黑屏
问题:运行游戏后画面全黑。
原因和解决方案:
- 没有 Camera3D:添加一个 Camera3D 节点,确保它是当前激活的摄像机
- 没有光源:添加 DirectionalLight3D 或 OmniLight3D,或者设置 WorldEnvironment 的环境光
- 摄像机位置不对:检查摄像机是否在场景内部、朝向是否正确
// 快速排错:检查场景基本设置
public override void _Ready()
{
// 确保有摄像机
var cameras = GetTree().GetNodesInGroup("cameras");
if (cameras.Count == 0)
{
GD.PrintErr("警告:场景中没有摄像机!");
}
// 确保有光源
var lights = GetTree().GetNodesInGroup("lights");
if (lights.Count == 0)
{
GD.PrintErr("警告:场景中没有光源!");
}
}# 快速排错:检查场景基本设置
func _ready():
# 确保有摄像机
var cameras = get_tree().get_nodes_in_group("cameras")
if cameras.size() == 0:
push_error("警告:场景中没有摄像机!")
# 确保有光源
var lights = get_tree().get_nodes_in_group("lights")
if lights.size() == 0:
push_error("警告:场景中没有光源!")碰撞不对
问题:角色穿墙或卡在墙里。
原因和解决方案:
- CSG 节点没有碰撞:CSG 默认不产生碰撞,需要单独添加 StaticBody3D + CollisionShape3D
- 碰撞形状大小不对:检查 CollisionShape3D 的 Shape 尺寸是否与视觉匹配
- 碰撞位置偏移:确保 StaticBody3D 的位置和 CSG 节点一致
CSG 显示异常
问题:CSG 形状出现破面、闪烁。
原因和解决方案:
- 布尔运算精度问题:确保减去的形状比原始形状稍大一点(厚度方向多 0.1)
- 面片重叠:避免两个 CSG 形状完全重合,稍微偏移 0.01 即可
- CSG 只适合原型:最终游戏建议替换为真实的 3D 模型,CSG 性能较差
CSG 只是"草稿"
CSG 非常适合快速搭建场景原型来测试游戏玩法。但当你的游戏进入正式开发阶段后,建议用 Blender 等 3D 建模软件制作精细的模型来替换 CSG。CSG 就像是建筑的设计草图,真正的建筑需要更精细的材料。
本章小结
通过本章的学习,你掌握了以下内容:
| 知识点 | 说明 |
|---|---|
| 场景(Scene) | Godot 中组织游戏世界的基本单位,类似电影布景 |
| Node3D | 3D 场景的根节点,负责组织和管理所有子节点 |
| 场景树 | 节点之间的父子层级关系,父节点变化会影响子节点 |
| CSG 几何体 | 用基本形状(方块、球、圆柱、圆环)快速搭建场景原型 |
| CSG 布尔运算 | 通过合并、减去、相交操作创建复杂形状 |
| 场景实例化 | 把场景当作模板,创建多个相同的副本 |
| 静态碰撞体 | 为场景添加物理碰撞,防止角色穿墙 |
| WorldEnvironment | 设置全局环境效果(天空、雾、环境光) |
接下来,我们将学习如何搭建更复杂的地形和建筑物。
