Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Entity/Outline.cs

262 lines
9.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Managers;
using Prefab;
using System.Collections.Generic;
using Base;
using UnityEngine;
using UnityEngine.Events;
namespace Entity
{
public class Outline : MonoBehaviour
{
// 实体身体的游戏对象
public GameObject body;
// 描边渲染器
public SpriteRenderer outlineRenderer;
// 描边碰撞体
public CapsuleCollider2D outlineCollider;
// 进度条预制件
public ProgressBarPrefab progressBarPrefab;
// 关联的实体
public Entity entity;
// 边界的最小尺寸
public static readonly Vector2 MinimumBoundsSize = new(0.5f, 0.5f);
// 缓存身体纹理大小
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>
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)
? Utils.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
: Utils.StringUtils.StringToVector2(entity.entityDef.colliderPosition);
}
/// <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>
/// <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 != null)
EntityManager.Instance.GenerateDefaultEntity(Program.Instance.FocusedDimensionId, entity.Position);
}
/// <summary>
/// 开始玩家对实体的操控。
/// </summary>
protected void StartControl()
{
entity.PlayerControlled = true;
}
/// <summary>
/// 结束玩家对实体的操控。
/// </summary>
protected void EndControl()
{
entity.PlayerControlled = false;
}
}
}