创建多个关卡

  • 每个关卡的根节点都要绑定level.gd作为脚本文件
    • 修改level.gd
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      class_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()

创建场景转换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
      @tool 
      class_name LevelTransition extends Area2D

      enum SIDE {LEFT, RIGHT, TOP, BOTTOM}

      @export_file("*.tscn") var level
      @export var target_transition_area: String = "LevelTransition"

      @export_category("Collision Area Setting")
      @export var snap_to_grid: bool = false :
      set(_v):
      snap_to_grid = _v
      _snap_to_grid()

      @export_range(1, 12, 1, "or_greater") var size: int = 2 :
      set(_v):
      size = _v
      _update_area()
      @export var side: SIDE = SIDE.LEFT :
      set(_v):
      side = _v
      _update_area()

      @onready var collision_shape: CollisionShape2D = $CollisionShape2D

      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
      45
      extends 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
      14
      extends CanvasLayer

      @onready var animation_player: AnimationPlayer = $Control/AnimationPlayer

      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注解可以在编辑器中运行,直接可以看到效果,不需要在游戏运行后才看到效果

  • 有些代码不需要编辑器执行的话需要注意