godot4制作2D游戏14———场景管理
创建多个关卡
- 每个关卡的根节点都要绑定level.gd作为脚本文件
- 修改level.gd
1
2
3
4
5
6
7
8
9
10class_name Level extends Node2D
func _ready() -> void:
self.y_sort_enabled = true
PlayerManager.set_as_parent(self)
pass
func _exit_tree() -> void:
PlayerManager.unparent(self)
queue_free()
- 修改level.gd
创建场景转换Scene
创建一个新Scene,命名为level_transition
- 根节点改为Area2D
- 添加CollisionShape2D节点
- 取消monitorable,mask layer选择1,表示不被监控但与1层的玩家可碰撞
- 创建level_transition.gd脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class_name LevelTransition extends Area2D
enum SIDE {LEFT, RIGHT, TOP, BOTTOM}
set(_v):
snap_to_grid = _v
_snap_to_grid()
set(_v):
size = _v
_update_area()
set(_v):
side = _v
_update_area()
func _ready() -> void:
_update_area()
if Engine.is_editor_hint():
return
monitoring = false
_place_player()
await LevelManager.LevelLoaded
monitoring = true
body_entered.connect(_player_entered)
pass
func _player_entered(_p: Node2D) -> void:
LevelManager.load_new_level(level, target_transition_area, get_offset())
pass
func _place_player() -> void:
if name != LevelManager.target_transition:
return
PlayerManager.set_player_position(global_position + LevelManager.position_offset)
func get_offset() -> Vector2:
var offset: Vector2 = Vector2.ZERO
var player_pos = PlayerManager.player.global_position
if side == SIDE.LEFT or side == SIDE.RIGHT:
offset.y = player_pos.y - global_position.y
offset.x = 16
if side == SIDE.LEFT:
offset.x *= -1
else:
offset.x = player_pos.x - global_position.x
offset.y = 16
if side == SIDE.TOP:
offset.y *= -1
return offset
func _update_area() -> void:
var position: Vector2 = Vector2.ZERO
var new_rect: Vector2 = Vector2(32, 32)
if side == SIDE.TOP:
new_rect.x *= size
position.y -= 16
elif side == SIDE.BOTTOM:
new_rect.x *= size
position.y += 16
elif side == SIDE.LEFT:
new_rect.y *= size
position.x -= 16
elif side == SIDE.RIGHT:
new_rect.y *= size
position.x += 16
if collision_shape == null:
collision_shape = get_node("CollisionShape2D")
collision_shape.shape.size = new_rect
collision_shape.position = position
pass
func _snap_to_grid() -> void:
position.x = roundi(position.x / 16) * 16
position.y = roundi(position.y / 16) * 16 - level_transition场景中的形状下有个Resource下有个local to scene,点击选中
- 通过level_transition将三个场景连接起来
- 修改global_level_manager脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45extends Node
signal LevelLoadStarted
signal LevelLoaded
signal TileMapBoundsChanged(bounds: Array[Vector2])
var current_tilemap_bounds: Array[Vector2]
var target_transition: String
var position_offset: Vector2
func _ready() -> void:
await get_tree().process_frame
LevelLoaded.emit()
pass
func ChangeTileMapBounds(bounds: Array[Vector2]) -> void:
current_tilemap_bounds = bounds
TileMapBoundsChanged.emit(bounds)
func load_new_level(
level_path: String,
_target_transition: String,
_position_offset: Vector2
) -> void:
get_tree().paused = true
target_transition = _target_transition
position_offset = _position_offset
await SceneTransition.fade_in()
LevelLoadStarted.emit()
await get_tree().process_frame
get_tree().change_scene_to_file(level_path)
await SceneTransition.fade_out()
get_tree().paused = false
await get_tree().process_frame
LevelLoaded.emit()
pass - 创建一个新的转场scene,并添加到autoload
1
2
3
4
5
6
7
8
9
10
11
12
13
14extends CanvasLayer
func fade_out() -> bool:
animation_player.play("fade_out")
await animation_player.animation_finished
return true
func fade_in() -> bool:
animation_player.play("fade_in")
await animation_player.animation_finished
return true
tool注解可以在编辑器中运行,直接可以看到效果,不需要在游戏运行后才看到效果
有些代码不需要编辑器执行的话需要注意
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Have a nice day!!