(client) feat:健康给予,路径优化,结算界面,商店界面 (#60)

Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com>
Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/60
This commit is contained in:
2025-10-10 14:08:23 +08:00
parent 9a797479ff
commit 16b49f3d3a
1900 changed files with 114053 additions and 34157 deletions

View File

@@ -1,14 +1,16 @@
using System;
using Base;
using Map;
using UnityEngine;
using Utils;
namespace CameraControl
{
/// <summary>
/// 控制游戏摄像机的移动、缩放和维度切换。
/// 继承自 MonoSingleton 以确保场景中只有一个实例,并实现 ITick 接口以在游戏循环中更新。
/// 控制游戏摄像机的移动、缩放和维度切换。
/// 继承自 MonoSingleton 以确保场景中只有一个实例,并实现 ITick 接口以在游戏循环中更新。
/// </summary>
public class CameraControl : Utils.MonoSingleton<CameraControl>, ITick
public class CameraControl : MonoSingleton<CameraControl>, ITick
{
// 摄像机移动相关变量
[SerializeField] private float _zoomSpeed = 5f; // 摄像机缩放速度
@@ -16,13 +18,16 @@ namespace CameraControl
[SerializeField] private float _maxZoom = 20f; // 摄像机最大缩放级别
[SerializeField] private float _focusLerpSpeed = 5f; // 摄像机跟随目标时的平滑插值速度
private Vector3 _dragOrigin; // 拖拽操作的起始世界坐标
private bool _isDragging; // 标记摄像机是否正在被拖拽
private Camera _cachedCamera; // 缓存的场景摄像机引用
private Vector3 _dragOrigin; // 拖拽操作的起始世界坐标
private bool _isDragging; // 标记摄像机是否正在被拖拽
private Dimension currentDimension;
private int dimensionId; // 当前摄像机控制器关注的维度索引
/// <summary>
/// 获取当前生效的场景摄像机。懒加载并缓存。
/// 获取当前生效的场景摄像机。懒加载并缓存。
/// </summary>
public Camera CurrentCamera
{
@@ -37,10 +42,7 @@ namespace CameraControl
_cachedCamera = FindFirstObjectByType<Camera>();
}
if (!_cachedCamera)
{
Debug.LogError("[CameraControl] 场景中未找到可用的摄像机!摄像机控制功能将受限。");
}
if (!_cachedCamera) Debug.LogError("[CameraControl] 场景中未找到可用的摄像机!摄像机控制功能将受限。");
}
return _cachedCamera;
@@ -48,14 +50,49 @@ namespace CameraControl
}
public Vector3 Position => CurrentCamera.transform.position;
private int dimensionId; // 当前摄像机控制器关注的维度索引
private string[] dimensionList=>Program.Instance.Dimensions; // 维度名称列表
private Dimension currentDimension;
private string[] dimensionList => Program.Instance.Dimensions; // 维度名称列表
/// <summary>
/// MonoSingleton 的 OnStart 方法,在单例首次创建并激活时调用,早于普通的 Start 方法
/// 用于初始化摄像机缓存
/// 当脚本实例被销毁时调用
/// 用于取消订阅 Program.Instance 的事件,防止内存泄漏
/// </summary>
private void OnDestroy()
{
Program.Instance.OnFocusedDimensionChanged -= Init;
Clock.RemoveTick(this);
}
/// <summary>
/// 在游戏循环中每帧调用,用于处理摄像机跟随聚焦实体和维度切换。
/// </summary>
public void Tick()
{
if (!CurrentCamera) return; // 确保相机存在
// 当没有拖拽且存在聚焦实体时,摄像机跟随聚焦实体
if (!_isDragging && Program.Instance.FocusedEntity)
{
var targetPosition = new Vector3(
Program.Instance.FocusedEntity.Position.x,
Program.Instance.FocusedEntity.Position.y,
CurrentCamera.transform.position.z);
// 使用 deltaTime 进行平滑的摄像机跟随
CurrentCamera.transform.position = Vector3.Lerp(
CurrentCamera.transform.position,
targetPosition,
Time.deltaTime * _focusLerpSpeed);
}
HandleMiddleMouseDrag(); // 处理鼠标中键拖拽
// HandleMouseZoom(); // 处理鼠标滚轮缩放
// 按下 Tab 键时切换到下一个维度
if (Input.GetKeyDown(KeyCode.Tab)) NextDimension();
}
/// <summary>
/// MonoSingleton 的 OnStart 方法,在单例首次创建并激活时调用,早于普通的 Start 方法。
/// 用于初始化摄像机缓存。
/// </summary>
protected override void OnStart()
{
@@ -63,31 +100,17 @@ namespace CameraControl
Clock.AddTick(this);
}
/// <summary>
/// 当脚本实例被销毁时调用。
/// 用于取消订阅 Program.Instance 的事件,防止内存泄漏。
/// </summary>
private void OnDestroy()
{
Program.Instance.OnFocusedDimensionChanged -= Init;
Clock.RemoveTick(this);
}
/// <summary>
/// 根据指定的维度对象初始化摄像机控制器。
/// 主要用于在聚焦维度改变时更新摄像机状态和内部的维度ID。
/// 根据指定的维度对象初始化摄像机控制器。
/// 主要用于在聚焦维度改变时更新摄像机状态和内部的维度ID。
/// </summary>
/// <param name="obj">当前聚焦的维度对象。</param>
private void Init(Dimension obj)
{
Clock.AddTick(this);
// 处理 obj 为 null 的情况 - 此时 dimensionList 已更新
if (!obj)
{
return;
}
if (!obj) return;
if (!CurrentCamera) // 如果摄像机仍未找到,记录错误并返回
{
Debug.LogWarning("[CameraControl] 未找到摄像机!摄像机控制功能将无法完全初始化。");
@@ -95,7 +118,7 @@ namespace CameraControl
}
// 根据当前聚焦维度同步 CameraControl 内部的 dimensionId
var focusedIndex = System.Array.IndexOf(dimensionList, obj.DimensionId);
var focusedIndex = Array.IndexOf(dimensionList, obj.DimensionId);
if (focusedIndex != -1)
{
dimensionId = focusedIndex;
@@ -105,27 +128,23 @@ namespace CameraControl
Debug.LogWarning($"[CameraControl] 聚焦维度 '{obj.DimensionId}' 未在维度列表中找到。回退到ID 0。");
dimensionId = 0; // 找不到时,回退到第一个维度,避免数组越界
}
CurrentCamera.transform.position = new Vector3(obj.cameraPosition.x, obj.cameraPosition.y, -10f);
if(currentDimension)
{
currentDimension.OnDimensionLoaded-=DimensionLoaded;
}
if (currentDimension) currentDimension.OnDimensionLoaded -= DimensionLoaded;
currentDimension = obj;
currentDimension.OnDimensionLoaded+=DimensionLoaded;
currentDimension.OnDimensionLoaded += DimensionLoaded;
}
private void DimensionLoaded(Dimension obj)
{
if (obj == Program.Instance.FocusedDimension)
{
CurrentCamera.transform.position = new Vector3(obj.cameraPosition.x, obj.cameraPosition.y, -10f);
}
}
/// <summary>
/// 切换到下一个维度。
/// 会保存当前摄像机位置到当前维度,然后加载下一个维度的摄像机位置。
/// 切换到下一个维度。
/// 会保存当前摄像机位置到当前维度,然后加载下一个维度的摄像机位置。
/// </summary>
public void NextDimension()
{
@@ -146,14 +165,10 @@ namespace CameraControl
{
var currentDimension = Program.Instance.GetDimension(dimensionList[dimensionId]);
if (currentDimension != null)
{
currentDimension.cameraPosition = CurrentCamera.transform.position;
}
else
{
Debug.LogWarning(
$"[CameraControl] 无法找到ID为 {dimensionId} ({dimensionList[dimensionId]}) 的维度对象,无法保存摄像机位置。");
}
}
else
{
@@ -169,8 +184,8 @@ namespace CameraControl
}
/// <summary>
/// 设置 Program.Instance 中聚焦的维度。
/// 摄像机位置的实际更新将通过 Program.Instance.OnFocusedDimensionChanged 事件在 Init(Dimension obj) 方法中处理。
/// 设置 Program.Instance 中聚焦的维度。
/// 摄像机位置的实际更新将通过 Program.Instance.OnFocusedDimensionChanged 事件在 Init(Dimension obj) 方法中处理。
/// </summary>
/// <param name="id">要设置的维度ID。</param>
private void SetFocusedDimensionById(int id)
@@ -186,59 +201,25 @@ namespace CameraControl
Debug.LogWarning($"[CameraControl] 维度ID {id} 超出范围或维度列表为空,无法设置聚焦维度。");
return;
}
Program.Instance.SetFocusedDimension(dimensionList[id]);
}
/// <summary>
/// 在游戏循环中每帧调用,用于处理摄像机跟随聚焦实体和维度切换。
/// </summary>
public void Tick()
{
if (!CurrentCamera) return; // 确保相机存在
// 当没有拖拽且存在聚焦实体时,摄像机跟随聚焦实体
if (!_isDragging && Program.Instance.FocusedEntity)
{
var targetPosition = new Vector3(
Program.Instance.FocusedEntity.Position.x,
Program.Instance.FocusedEntity.Position.y,
CurrentCamera.transform.position.z);
// 使用 deltaTime 进行平滑的摄像机跟随
CurrentCamera.transform.position = Vector3.Lerp(
CurrentCamera.transform.position,
targetPosition,
Time.deltaTime * _focusLerpSpeed);
}
HandleMiddleMouseDrag(); // 处理鼠标中键拖拽
// HandleMouseZoom(); // 处理鼠标滚轮缩放
// 按下 Tab 键时切换到下一个维度
if (Input.GetKeyDown(KeyCode.Tab))
{
NextDimension();
}
}
/// <summary>
/// 设置摄像机的世界坐标位置。
/// 设置摄像机的世界坐标位置。
/// </summary>
/// <param name="position">要设置的摄像机位置。</param>
public void SetPosition(Vector3 position)
{
if (CurrentCamera)
{
CurrentCamera.transform.position = position;
}
else
{
Debug.LogWarning("[CameraControl] 摄像机引用为空,无法设置位置。");
}
}
/// <summary>
/// 处理鼠标中键拖拽摄像机的逻辑。
/// 处理鼠标中键拖拽摄像机的逻辑。
/// </summary>
private void HandleMiddleMouseDrag()
{
@@ -250,10 +231,7 @@ namespace CameraControl
_dragOrigin = CurrentCamera.ScreenToWorldPoint(Input.mousePosition);
_isDragging = true;
// 如果有聚焦实体,则在开始拖拽时取消聚焦,暂停跟随
if (Program.Instance.FocusedEntity)
{
Program.Instance.SetFocusedEntity(null);
}
if (Program.Instance.FocusedEntity) Program.Instance.SetFocusedEntity(null);
}
// 拖拽中:根据鼠标移动更新摄像机位置
@@ -264,14 +242,11 @@ namespace CameraControl
}
// 结束拖拽:检测鼠标中键抬起
if (Input.GetMouseButtonUp(2))
{
_isDragging = false;
}
if (Input.GetMouseButtonUp(2)) _isDragging = false;
}
/// <summary>
/// 处理鼠标滚轮缩放摄像机的逻辑。
/// 处理鼠标滚轮缩放摄像机的逻辑。
/// </summary>
private void HandleMouseZoom()
{