280 lines
7.8 KiB
GDScript
280 lines
7.8 KiB
GDScript
extends Node
|
||
class_name WorldManager
|
||
## 世界管理器
|
||
## 管理游戏世界中的所有角色和对象
|
||
|
||
# 角色管理
|
||
var characters: Dictionary = {} # character_id -> CharacterController
|
||
var player_character: CharacterController = null
|
||
|
||
# 场景引用
|
||
var character_container: Node2D = null
|
||
|
||
# 预加载的角色场景
|
||
var player_character_scene: PackedScene = null
|
||
var remote_character_scene: PackedScene = null
|
||
|
||
# 信号
|
||
signal character_spawned(character_id: String, character: CharacterController)
|
||
signal character_removed(character_id: String)
|
||
signal character_state_updated(character_id: String)
|
||
|
||
func _ready():
|
||
"""初始化世界管理器"""
|
||
print("WorldManager initialized")
|
||
|
||
## 设置角色容器
|
||
func set_character_container(container: Node2D):
|
||
"""
|
||
设置角色容器节点
|
||
@param container: 用于放置角色的 Node2D 容器
|
||
"""
|
||
character_container = container
|
||
|
||
## 生成角色
|
||
func spawn_character(character_data: Dictionary, is_player: bool = false) -> CharacterController:
|
||
"""
|
||
在世界中生成角色
|
||
@param character_data: 角色数据
|
||
@param is_player: 是否为玩家角色
|
||
@return: 生成的角色控制器
|
||
"""
|
||
if not character_container:
|
||
push_error("Character container not set")
|
||
return null
|
||
|
||
var character_id = character_data.get(CharacterData.FIELD_ID, "")
|
||
if character_id.is_empty():
|
||
push_error("Character data missing ID")
|
||
return null
|
||
|
||
# 检查是否已存在
|
||
if characters.has(character_id):
|
||
push_warning("Character already exists: ", character_id)
|
||
return characters[character_id]
|
||
|
||
# 创建角色实例
|
||
var character: CharacterController
|
||
if is_player:
|
||
# 玩家角色(将在任务 11 中使用场景)
|
||
character = CharacterController.new()
|
||
character.name = "PlayerCharacter_" + character_id
|
||
else:
|
||
# 远程角色
|
||
character = CharacterController.new()
|
||
character.name = "RemoteCharacter_" + character_id
|
||
|
||
# 初始化角色
|
||
character.initialize(character_data)
|
||
|
||
# 添加到容器
|
||
character_container.add_child(character)
|
||
|
||
# 记录到字典
|
||
characters[character_id] = character
|
||
|
||
# 如果是玩家角色,保存引用
|
||
if is_player:
|
||
player_character = character
|
||
|
||
# 发射信号
|
||
character_spawned.emit(character_id, character)
|
||
|
||
print("Character spawned: ", character_id, " (player: ", is_player, ")")
|
||
return character
|
||
|
||
## 移除角色
|
||
func remove_character(character_id: String) -> void:
|
||
"""
|
||
从世界中移除角色
|
||
@param character_id: 角色 ID
|
||
"""
|
||
if not characters.has(character_id):
|
||
push_warning("Character not found: ", character_id)
|
||
return
|
||
|
||
var character = characters[character_id]
|
||
|
||
# 如果是玩家角色,清除引用
|
||
if character == player_character:
|
||
player_character = null
|
||
|
||
# 从字典中移除
|
||
characters.erase(character_id)
|
||
|
||
# 从场景树中移除
|
||
character.queue_free()
|
||
|
||
# 发射信号
|
||
character_removed.emit(character_id)
|
||
|
||
print("Character removed: ", character_id)
|
||
|
||
## 更新角色状态
|
||
func update_character_state(character_id: String, state: Dictionary) -> void:
|
||
"""
|
||
更新角色状态
|
||
@param character_id: 角色 ID
|
||
@param state: 状态数据(包含位置、在线状态等)
|
||
"""
|
||
if not characters.has(character_id):
|
||
# 检查是否是离线状态更新,如果是则忽略(角色可能已被清理)
|
||
var is_online = state.get("isOnline", true)
|
||
if not is_online:
|
||
print("Ignoring offline state update for removed character: ", character_id)
|
||
return
|
||
|
||
# 如果是在线状态但角色不存在,可能需要重新创建
|
||
print("Character not found for state update, attempting to recreate: ", character_id)
|
||
|
||
# 尝试从状态数据重新创建角色
|
||
if state.has("name") and state.has("position"):
|
||
var character_data = {
|
||
CharacterData.FIELD_ID: character_id,
|
||
CharacterData.FIELD_NAME: state.get("name", "Unknown"),
|
||
CharacterData.FIELD_POSITION: state.get("position", {"x": 0, "y": 0}),
|
||
CharacterData.FIELD_IS_ONLINE: is_online
|
||
}
|
||
spawn_character(character_data, false)
|
||
return
|
||
else:
|
||
print("Insufficient data to recreate character: ", character_id)
|
||
return
|
||
|
||
var character = characters[character_id]
|
||
|
||
# 更新位置
|
||
if state.has("position"):
|
||
var pos_data = state["position"]
|
||
var new_pos = Vector2(pos_data.get("x", 0), pos_data.get("y", 0))
|
||
character.set_position_smooth(new_pos)
|
||
|
||
# 更新在线状态
|
||
if state.has("isOnline"):
|
||
var is_online = state["isOnline"]
|
||
character.set_online_status(is_online)
|
||
|
||
# 如果角色下线,考虑延迟清理(避免频繁上下线导致的问题)
|
||
if not is_online:
|
||
print("Character went offline: ", character_id)
|
||
# 可以在这里添加延迟清理逻辑,比如5分钟后清理离线角色
|
||
# _schedule_character_cleanup(character_id)
|
||
|
||
# 发射信号
|
||
character_state_updated.emit(character_id)
|
||
|
||
## 获取附近角色
|
||
func get_nearby_characters(position: Vector2, radius: float) -> Array:
|
||
"""
|
||
获取指定位置附近的角色
|
||
@param position: 中心位置
|
||
@param radius: 搜索半径
|
||
@return: 附近角色的数组
|
||
"""
|
||
var nearby: Array = []
|
||
|
||
for character in characters.values():
|
||
if character is CharacterController:
|
||
var distance = position.distance_to(character.global_position)
|
||
if distance <= radius:
|
||
nearby.append(character)
|
||
|
||
return nearby
|
||
|
||
## 获取所有角色
|
||
func get_all_characters() -> Array:
|
||
"""
|
||
获取所有角色
|
||
@return: 所有角色的数组
|
||
"""
|
||
return characters.values()
|
||
|
||
## 获取角色
|
||
func get_character(character_id: String) -> CharacterController:
|
||
"""
|
||
根据 ID 获取角色
|
||
@param character_id: 角色 ID
|
||
@return: 角色控制器,如果不存在则返回 null
|
||
"""
|
||
return characters.get(character_id, null)
|
||
|
||
## 获取玩家角色
|
||
func get_player_character() -> CharacterController:
|
||
"""
|
||
获取玩家角色
|
||
@return: 玩家角色控制器
|
||
"""
|
||
return player_character
|
||
|
||
## 处理角色上线
|
||
func handle_character_online(character_id: String) -> void:
|
||
"""
|
||
处理角色上线事件
|
||
@param character_id: 角色 ID
|
||
"""
|
||
if characters.has(character_id):
|
||
# 角色已存在,更新在线状态
|
||
var character = characters[character_id]
|
||
character.set_online_status(true)
|
||
print("Character came online: ", character_id)
|
||
else:
|
||
# 角色不存在,需要从服务器获取数据后生成
|
||
print("Character online but not spawned yet: ", character_id)
|
||
|
||
## 处理角色下线
|
||
func handle_character_offline(character_id: String) -> void:
|
||
"""
|
||
处理角色下线事件
|
||
@param character_id: 角色 ID
|
||
"""
|
||
if characters.has(character_id):
|
||
# 更新为离线状态(但不移除角色)
|
||
var character = characters[character_id]
|
||
character.set_online_status(false)
|
||
print("Character went offline: ", character_id)
|
||
else:
|
||
push_warning("Character not found for offline event: ", character_id)
|
||
|
||
## 生成或更新角色
|
||
func spawn_or_update_character(character_data: Dictionary) -> CharacterController:
|
||
"""
|
||
生成新角色或更新已存在的角色
|
||
@param character_data: 角色数据
|
||
@return: 角色控制器
|
||
"""
|
||
var character_id = character_data.get(CharacterData.FIELD_ID, "")
|
||
if character_id.is_empty():
|
||
push_error("Character data missing ID")
|
||
return null
|
||
|
||
# 检查角色是否已存在
|
||
if characters.has(character_id):
|
||
# 更新已存在的角色
|
||
update_character_state(character_id, character_data)
|
||
return characters[character_id]
|
||
else:
|
||
# 生成新角色(远程角色)
|
||
return spawn_character(character_data, false)
|
||
|
||
## 更新角色位置
|
||
func update_character_position(character_id: String, new_position: Vector2) -> void:
|
||
"""
|
||
更新角色位置
|
||
@param character_id: 角色 ID
|
||
@param new_position: 新位置
|
||
"""
|
||
if not characters.has(character_id):
|
||
push_warning("Character not found for position update: ", character_id)
|
||
return
|
||
|
||
var character = characters[character_id]
|
||
character.set_position_smooth(new_position)
|
||
|
||
## 清除所有角色
|
||
func clear_all_characters() -> void:
|
||
"""清除世界中的所有角色"""
|
||
for character_id in characters.keys():
|
||
remove_character(character_id)
|
||
|
||
print("All characters cleared")
|