mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 02:37:12 +08:00
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
252 lines
9.3 KiB
C#
252 lines
9.3 KiB
C#
using System.Collections.Generic;
|
||
using Base;
|
||
using Managers;
|
||
using Prefab;
|
||
using UnityEngine;
|
||
using UnityEngine.Events;
|
||
using Utils;
|
||
|
||
namespace Entity
|
||
{
|
||
public class Outline : MonoBehaviour
|
||
{
|
||
// 边界的最小尺寸
|
||
public static readonly Vector2 MinimumBoundsSize = new(0.5f, 0.5f);
|
||
|
||
// 实体身体的游戏对象
|
||
public GameObject body;
|
||
|
||
// 描边渲染器
|
||
public SpriteRenderer outlineRenderer;
|
||
|
||
// 描边碰撞体
|
||
public CapsuleCollider2D outlineCollider;
|
||
|
||
// 进度条预制件
|
||
public ProgressBarPrefab progressBarPrefab;
|
||
|
||
// 关联的实体
|
||
public Entity entity;
|
||
|
||
// 缓存身体纹理大小
|
||
private Vector2 _cachedBodyTextureSize;
|
||
|
||
// 缓存碰撞体大小
|
||
private Vector2 _cachedColliderSize;
|
||
|
||
// 缓存碰撞体偏移
|
||
private Vector2 _cachedOffset;
|
||
|
||
// 缓存是否已初始化标志 (明确它管理的是数据缓存状态)
|
||
private bool _isDataCacheInitialized; // 修改部分1:变量更名
|
||
|
||
// 是否可以显示描边
|
||
public bool CanShow => Setting.Instance.CurrentSettings.developerMode && entity.canSelect &&
|
||
!UIInputControl.Instance.HasWindowOpen;
|
||
|
||
/// <summary>
|
||
/// 当鼠标进入描边区域时调用。
|
||
/// </summary>
|
||
protected virtual void OnMouseEnter()
|
||
{
|
||
if (!CanShow)
|
||
return;
|
||
Show();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当鼠标离开描边区域时调用。
|
||
/// </summary>
|
||
protected virtual void OnMouseExit()
|
||
{
|
||
Hide();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当鼠标停留在描边区域时每帧调用。
|
||
/// </summary>
|
||
protected virtual void OnMouseOver()
|
||
{
|
||
if (!Program.Instance.CanOpenRightMenu || !CanShow)
|
||
return;
|
||
// 检测是否按下的是鼠标右键
|
||
if (Input.GetMouseButtonDown(1)) RightMenuManager.GenerateRightMenu(GetMenu(), Input.mousePosition);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确保描边尺寸相关数据缓存已初始化。如果未初始化,则会计算并缓存。
|
||
/// 此方法保证内部的尺寸计算只执行一次。
|
||
/// </summary>
|
||
private void EnsureDataCacheInitialized() // 修改部分2:新增私有方法
|
||
{
|
||
if (_isDataCacheInitialized) return; // 如果数据缓存已初始化,则直接返回
|
||
// 计算并缓存所有必要尺寸
|
||
_cachedBodyTextureSize = CalculateBodyTextureSize();
|
||
_cachedColliderSize = CalculateColliderSize();
|
||
_cachedOffset = CalculateOffset();
|
||
_isDataCacheInitialized = true; // 标记数据缓存已初始化
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化描边,将计算出的尺寸应用于描边渲染器、碰撞体和进度条。
|
||
/// 此方法确保数据缓存已初始化,并可以被重复调用以重新应用设置。
|
||
/// </summary>
|
||
public virtual void Init() // 修改部分4:修改 Init 方法
|
||
{
|
||
// 首先确保尺寸数据是可用的。这个调用会立即返回如果数据缓存已初始化。
|
||
EnsureDataCacheInitialized();
|
||
// 使用缓存值设置OutlineRenderer
|
||
outlineRenderer.size = _cachedBodyTextureSize;
|
||
// 使用缓存值设置OutlineCollider
|
||
var colliderSize = _cachedColliderSize; // 使用缓存值
|
||
outlineCollider.direction = colliderSize.x > colliderSize.y
|
||
? CapsuleDirection2D.Horizontal
|
||
: CapsuleDirection2D.Vertical;
|
||
outlineCollider.size = colliderSize;
|
||
outlineCollider.offset = _cachedOffset; // 使用缓存值
|
||
// 使用缓存值调整ProgressBarPrefab
|
||
if (progressBarPrefab)
|
||
{
|
||
// 确保每次 Init 调用都能正确设置位置而不重复累加。
|
||
progressBarPrefab.transform.localPosition =
|
||
new Vector3(0f, colliderSize.y * 2 / 3, 0f); // 逻辑修改:将 += 改为 =
|
||
progressBarPrefab.transform.localScale = new Vector3(colliderSize.x, 1f / 10f, 1);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示描边。
|
||
/// </summary>
|
||
public void Show()
|
||
{
|
||
if (CanShow)
|
||
outlineRenderer.enabled = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏描边。
|
||
/// </summary>
|
||
public void Hide()
|
||
{
|
||
outlineRenderer.enabled = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前实体的碰撞体大小。在首次调用时自动计算并缓存。
|
||
/// </summary>
|
||
/// <returns>碰撞体大小的Vector2。</returns>
|
||
public Vector2 GetColliderSize() // 修改部分3:修改 GetColliderSize 方法
|
||
{
|
||
EnsureDataCacheInitialized(); // 确保数据缓存已初始化
|
||
return _cachedColliderSize;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取身体的纹理总大小。在首次调用时自动计算并缓存。
|
||
/// </summary>
|
||
/// <returns>身体纹理大小的Vector2。</returns>
|
||
public Vector2 GetBodyTextureSize() // 修改部分3:修改 GetBodyTextureSize 方法
|
||
{
|
||
EnsureDataCacheInitialized(); // 确保数据缓存已初始化
|
||
return _cachedBodyTextureSize;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前实体的碰撞体偏移。在首次调用时自动计算并缓存。
|
||
/// </summary>
|
||
/// <returns>碰撞体偏移的Vector2。</returns>
|
||
public Vector2 GetOffset() // 修改部分3:修改 GetOffset 方法
|
||
{
|
||
EnsureDataCacheInitialized(); // 确保数据缓存已初始化
|
||
return _cachedOffset;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算并返回碰撞体大小。此方法是内部实现细节。
|
||
/// </summary>
|
||
/// <returns>碰撞体大小的Vector2。</returns>
|
||
private Vector2 CalculateColliderSize()
|
||
{
|
||
return !string.IsNullOrEmpty(entity.entityDef?.colliderSize)
|
||
? StringUtils.StringToVector2(entity.entityDef.colliderSize)
|
||
: CalculateBodyTextureSize();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算并返回身体纹理的总大小。此方法是内部实现细节。
|
||
/// </summary>
|
||
/// <returns>身体纹理总大小的Vector2。</returns>
|
||
private Vector2 CalculateBodyTextureSize()
|
||
{
|
||
// 获取所有子对象的 Renderer 组件
|
||
var renderers = body.GetComponentsInChildren<Renderer>(true);
|
||
// 如果没有找到任何 Renderer,返回一个默认值
|
||
if (renderers.Length == 0) return MinimumBoundsSize;
|
||
|
||
// 初始化 totalBounds 为第一个 Renderer 的 bounds
|
||
var totalBounds = renderers[0].bounds;
|
||
// 遍历剩余的 Renderer,将它们的 bounds 合并到 totalBounds 中
|
||
for (var i = 1; i < renderers.Length; i++) totalBounds.Encapsulate(renderers[i].bounds);
|
||
|
||
// 获取合并后的包围盒的XY大小
|
||
var size = new Vector2(totalBounds.size.x, totalBounds.size.y);
|
||
// 确保每个维度的大小都不小于最小限制
|
||
size.x = Mathf.Max(size.x, MinimumBoundsSize.x);
|
||
size.y = Mathf.Max(size.y, MinimumBoundsSize.y);
|
||
return size;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算并返回碰撞体偏移。此方法是内部实现细节。
|
||
/// </summary>
|
||
/// <returns>碰撞体偏移的Vector2。</returns>
|
||
private Vector2 CalculateOffset()
|
||
{
|
||
return string.IsNullOrEmpty(entity.entityDef?.colliderPosition)
|
||
? Vector2.zero
|
||
: StringUtils.StringToVector2(entity.entityDef.colliderPosition);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取右键菜单项列表。
|
||
/// </summary>
|
||
/// <returns>包含菜单项名称和对应回调函数的列表。</returns>
|
||
protected virtual List<(string name, UnityAction callback)> GetMenu()
|
||
{
|
||
var result = new List<(string name, UnityAction callback)>();
|
||
if (entity.PlayerControlled)
|
||
result.Add(("结束操控", EndControl));
|
||
else
|
||
result.Add(("手动操控", StartControl));
|
||
result.Add(("杀死", () => entity.Kill()));
|
||
result.Add(("变成笨蛋", BecomeDefault));
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将当前实体变为默认实体。
|
||
/// </summary>
|
||
protected void BecomeDefault()
|
||
{
|
||
entity?.Kill();
|
||
if (entity)
|
||
EntityManager.Instance.GenerateDefaultEntity(Program.Instance.FocusedDimensionId, entity.Position);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开始玩家对实体的操控。
|
||
/// </summary>
|
||
protected void StartControl()
|
||
{
|
||
entity.PlayerControlled = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 结束玩家对实体的操控。
|
||
/// </summary>
|
||
protected void EndControl()
|
||
{
|
||
entity.PlayerControlled = false;
|
||
}
|
||
}
|
||
} |