|
|
|
|
extends Node3D
|
|
|
|
|
class_name LevelManager
|
|
|
|
|
|
|
|
|
|
var target: int
|
|
|
|
|
var level: Level
|
|
|
|
|
var cur_level_instance: LevelInstance
|
|
|
|
|
var level_instance_dict: Dictionary = {}
|
|
|
|
|
var level_loading_time: float
|
|
|
|
|
var level_active_spots: Array[Node]
|
|
|
|
|
var level_character_born_spots: Array[LevelInstance.ChacacterBornSpot]
|
|
|
|
|
var level_enemy_cfgs: Array[CharacterCfg]
|
|
|
|
|
var level_doors: Array[LevelDoor]
|
|
|
|
|
var is_level_active: bool
|
|
|
|
|
var enemy_count: int # 由关卡生成的怪物数量
|
|
|
|
|
var current_enmey: Array[int] # 当前存活怪物id
|
|
|
|
|
var replace_cache: LevelInstance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
|
|
|
Global.level_mgr = self
|
|
|
|
|
SignalManager.character_create.connect(on_character_create)
|
|
|
|
|
SignalManager.character_pos_changed.connect(on_character_pos_changed)
|
|
|
|
|
SignalManager.character_die.connect(on_character_die)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func init():
|
|
|
|
|
var level_scene: PackedScene = load("res://scene/level/level.tscn")
|
|
|
|
|
level = level_scene.instantiate() as Level
|
|
|
|
|
add_child(level)
|
|
|
|
|
var level_instance_list: Array[LevelInstance] = level.get_level_instance_list()
|
|
|
|
|
for level_instance in level_instance_list:
|
|
|
|
|
var level_id_list: Array[Vector3i] = get_level_id_list(level_instance.get_global_position(), level_instance.size)
|
|
|
|
|
for level_id in level_id_list:
|
|
|
|
|
if level_id in level_instance_dict:
|
|
|
|
|
print("关卡id重复", level_id)
|
|
|
|
|
level_instance_dict[level_id] = level_instance
|
|
|
|
|
level.init()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _process(delta) -> void:
|
|
|
|
|
if not level:
|
|
|
|
|
return
|
|
|
|
|
if level_loading_time > 0:
|
|
|
|
|
level_loading_time -= delta
|
|
|
|
|
if level_loading_time <= 0:
|
|
|
|
|
enter_level()
|
|
|
|
|
SignalManager.level_loading_end.emit()
|
|
|
|
|
Global.is_level_loading = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_born_pos() -> Vector3:
|
|
|
|
|
return level.get_born_pos()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func on_character_create(id: int, type: int, pos: Vector3):
|
|
|
|
|
if type == Enum.ECharacterType.Player:
|
|
|
|
|
target = id
|
|
|
|
|
on_character_pos_changed(id, pos)
|
|
|
|
|
elif type == Enum.ECharacterType.Monster:
|
|
|
|
|
current_enmey.append(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func on_character_pos_changed(id: int, pos: Vector3):
|
|
|
|
|
if id == target:
|
|
|
|
|
set_player_position(pos)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func on_character_die(id: int) -> void:
|
|
|
|
|
if id in current_enmey:
|
|
|
|
|
current_enmey.remove_at(current_enmey.find(id))
|
|
|
|
|
#强制战斗关卡通关
|
|
|
|
|
if not cur_level_instance.is_force_battle:
|
|
|
|
|
return
|
|
|
|
|
if enemy_born(1):
|
|
|
|
|
return
|
|
|
|
|
if current_enmey.size() > 0:
|
|
|
|
|
return
|
|
|
|
|
for level_door: LevelDoor in level_doors:
|
|
|
|
|
level_door.set_open(true)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func set_player_position(pos: Vector3) -> void:
|
|
|
|
|
level.set_player_position(pos)
|
|
|
|
|
var new_level_instance: LevelInstance = get_level_by_pos(pos)
|
|
|
|
|
if not new_level_instance:
|
|
|
|
|
return # todo 不存在的关卡 主角直接死亡
|
|
|
|
|
var is_first_level: bool = cur_level_instance == null
|
|
|
|
|
|
|
|
|
|
if !is_first_level:
|
|
|
|
|
if new_level_instance == cur_level_instance:
|
|
|
|
|
check_level_active(pos)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
cur_level_instance = new_level_instance
|
|
|
|
|
if is_first_level:
|
|
|
|
|
enter_level()
|
|
|
|
|
else:
|
|
|
|
|
SignalManager.level_loading_start.emit()
|
|
|
|
|
Global.is_level_loading = true
|
|
|
|
|
level_loading_time = Setting.level_loading_time
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func enter_level() -> void:
|
|
|
|
|
cur_level_instance.set_focus()
|
|
|
|
|
is_level_active = false
|
|
|
|
|
level_active_spots = []
|
|
|
|
|
level_doors = []
|
|
|
|
|
#创建关卡内活动部件
|
|
|
|
|
for level_active_spot: Node in level_active_spots:
|
|
|
|
|
level_active_spot.queue_free()
|
|
|
|
|
for level_active_spot: LevelInstance.LevelActiveSpot in cur_level_instance.get_level_active_spots():
|
|
|
|
|
var new_level_active: Node = level_active_spot.scene.instantiate()
|
|
|
|
|
add_child(new_level_active)
|
|
|
|
|
new_level_active.global_position = level_active_spot.pos
|
|
|
|
|
level_active_spots.append(new_level_active)
|
|
|
|
|
if new_level_active is LevelDoor:
|
|
|
|
|
level_doors.append(new_level_active)
|
|
|
|
|
#更新刷怪数据
|
|
|
|
|
level_character_born_spots = cur_level_instance.get_character_born_spots()
|
|
|
|
|
level_enemy_cfgs = cur_level_instance.get_enemy_cfgs()
|
|
|
|
|
enemy_count = 0
|
|
|
|
|
#更新cell
|
|
|
|
|
if replace_cache:
|
|
|
|
|
replace_cache.set_replace(false)
|
|
|
|
|
cur_level_instance.set_replace(true)
|
|
|
|
|
replace_cache = cur_level_instance
|
|
|
|
|
|
|
|
|
|
SignalManager.level_size_change.emit(cur_level_instance.get_level_size())
|
|
|
|
|
SignalManager.level_pos_change.emit(cur_level_instance.get_level_pos())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func check_level_active(pos: Vector3) -> void:
|
|
|
|
|
if is_level_active:
|
|
|
|
|
return
|
|
|
|
|
var is_active: bool = cur_level_instance.is_in_active_area(pos)
|
|
|
|
|
if not is_active:
|
|
|
|
|
return
|
|
|
|
|
is_level_active = true
|
|
|
|
|
for level_door: LevelDoor in level_doors:
|
|
|
|
|
level_door.set_open(true)
|
|
|
|
|
#创建关卡内角色
|
|
|
|
|
for character_spot: LevelInstance.ChacacterSpot in cur_level_instance.get_character_spots():
|
|
|
|
|
Global.character_mgr.create_character(character_spot.cfg, Enum.ETeam.Monster, character_spot.pos)
|
|
|
|
|
#强制战斗关门刷怪
|
|
|
|
|
if cur_level_instance.is_force_battle:
|
|
|
|
|
if enemy_born(level_character_born_spots.size()):
|
|
|
|
|
for level_door: LevelDoor in level_doors:
|
|
|
|
|
level_door.set_open(false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_level_id_list(pos: Vector3, size: Vector3i) -> Array[Vector3i]:
|
|
|
|
|
var size_basic: Vector3 = Setting.size_basic
|
|
|
|
|
var ret: Array[Vector3i] = []
|
|
|
|
|
for x in range(size.x):
|
|
|
|
|
for y in range(size.y):
|
|
|
|
|
for z in range(size.z):
|
|
|
|
|
var pos_sub: Vector3 = pos + Vector3(x * size_basic.x, y * size_basic.y, z * size_basic.z)
|
|
|
|
|
ret.append(Util.get_level_id(pos_sub))
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func enemy_born(count: int) -> bool:
|
|
|
|
|
if level_character_born_spots.size() == 0:
|
|
|
|
|
return false
|
|
|
|
|
var count_max: int = level_enemy_cfgs.size()
|
|
|
|
|
count = min(count, count_max - enemy_count)
|
|
|
|
|
if count == 0:
|
|
|
|
|
return false
|
|
|
|
|
var count_start: int = enemy_count
|
|
|
|
|
for i in count:
|
|
|
|
|
var cfg_index: int = count_start + i
|
|
|
|
|
var cfg: CharacterCfg = level_enemy_cfgs[cfg_index]
|
|
|
|
|
var pos_index: int = enemy_count % level_character_born_spots.size()
|
|
|
|
|
var character_spot: LevelInstance.ChacacterBornSpot = level_character_born_spots[pos_index]
|
|
|
|
|
Global.character_mgr.create_character(cfg, Enum.ETeam.Monster, character_spot.pos)
|
|
|
|
|
enemy_count += 1
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_level_by_pos(pos: Vector3) -> LevelInstance:
|
|
|
|
|
var level_id: Vector3i = Util.get_level_id(pos)
|
|
|
|
|
if level_id in level_instance_dict:
|
|
|
|
|
return level_instance_dict.get(level_id)
|
|
|
|
|
return null
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_cur_level_name() -> String:
|
|
|
|
|
if not cur_level_instance:
|
|
|
|
|
return ""
|
|
|
|
|
return cur_level_instance.get_name()
|