Files
Cielonos/Assets/Scripts/MainGame/UI/PlayerUI/EnemyInfo/EnemyInfoUnitBase.cs
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

143 lines
6.2 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 System;
using Cielonos.MainGame.Buffs.Character;
using Cielonos.MainGame.Characters;
using Sirenix.OdinInspector;
using SLSUtilities.General;
using SLSUtilities.UI;
using UnityEngine;
namespace Cielonos.MainGame.UI
{
public class EnemyInfoUnitBase : UIElementBase
{
[HideInInspector]
public CharacterBase enemy;
[TitleGroup("Bars")]
public RectTransform barContainer;
[TitleGroup("Bars")]
public AttributeBarBase healthBar;
[TitleGroup("Bars")]
public AttributeBarBase energyBar;
[TitleGroup("Buffs")]
public RectTransform buffIconContainer;
[TitleGroup("Distance & Scale Settings")]
public float minShowDistance = 5f; // 距离小于此值血条消失过近4
[TitleGroup("Distance & Scale Settings")]
public float maxShowDistance = 30f; // 距离大于此值,血条消失(过远)
[TitleGroup("Distance & Scale Settings")]
public float maxScale = 1f; // 距离最近 (minShowDistance) 时的最大缩放比例
[TitleGroup("Distance & Scale Settings")]
public float minScale = 0.4f; // 距离最远 (maxShowDistance) 时的最小缩放比例
private float distanceFade;
[Header("Occlusion Settings")]
public LayerMask obstacleLayer; // 遮挡物层级(墙壁、地面等)
public float occlusionTimer = 0f; // 被遮挡的计时器
public float occlusionDelay = 0.5f; // 被遮挡后延迟多久开始消失
private float occlusionFade;
[Header("Alpha & Edge Fade Settings")]
public float fadeSpeed = 8f; // 透明度渐变速度 (越大消失越快)
[Tooltip("从中心到边缘,开始衰减的百分比 (0~1)")]
public float fadeStartPct = 0.80f; // 80% 开始消失
[Tooltip("从中心到边缘,完全透明的百分比 (0~1)")]
public float fadeEndPct = 0.95f; // 95% 完全消失
private float screenFade;
public void Initialize(CharacterBase character)
{
enemy = character;
UpdateHealth(true);
UpdateEnergy(true);
}
private void Update()
{
UpdatePosition();
canvasGroup.alpha = Mathf.Min(distanceFade, occlusionFade, screenFade);
}
public void UpdatePosition()
{
if(enemy?.bodyPartsSc?.infoUIPoint == null) return;
Vector3 enemyPos = enemy.centerPosition;
Vector3 infoUIPos = enemy.bodyPartsSc.infoUIPoint.position;
Vector3 playerPos = MainGameManager.Player.centerPosition;
Camera playerCamera = MainGameManager.Player.viewSc.playerCamera;
float cameraDistance = Vector3.Distance(playerCamera.transform.position, infoUIPos);
float playerDistance = Vector3.Distance(playerPos, enemyPos);
float midDistance = (minShowDistance + maxShowDistance) / 2f;
// 计算距离衰减在midDistance处达到最大值minShowDistance和maxShowDistance处为0
distanceFade = Mathf.InverseLerp(cameraDistance < midDistance ? minShowDistance : maxShowDistance, midDistance, cameraDistance);
distanceFade = Mathf.Min(distanceFade * 4f, 1f); // 在距离范围内,快速达到完全显示
if(distanceFade <= 0f) return; // 距离过近或过远,直接隐藏
Vector3 screenPos = SpaceConverter.WorldPointToScreenPoint(infoUIPos, playerCamera);
Vector3 viewportPos = playerCamera.WorldToViewportPoint(infoUIPos);
bool isBehindCamera = screenPos.z < 0;
float normalizedDistX = Mathf.Abs(viewportPos.x - 0.5f) * 2f;
float normalizedDistY = Mathf.Abs(viewportPos.y - 0.5f) * 2f;
float maxNormalizedDist = Mathf.Max(normalizedDistX, normalizedDistY);
screenFade = Mathf.InverseLerp(fadeEndPct, fadeStartPct, maxNormalizedDist);
/*bool isOffScreen = screenPos.x < 0 || screenPos.x > Screen.width ||
screenPos.y < 0 || screenPos.y > Screen.height;*/
if (isBehindCamera || screenFade <= 0f)
{
screenFade = 0f;
return;
}
if (Physics.Linecast(playerCamera.transform.position, infoUIPos, out RaycastHit hitInfo))
{
if (hitInfo.collider.GetComponentInParent<CharacterBase>() != enemy)
{
occlusionTimer += Time.deltaTime;
}
else
{
occlusionTimer = 0f;
}
}
if (occlusionTimer > occlusionDelay)
{
float progress = (occlusionTimer - occlusionDelay) * fadeSpeed;
occlusionFade = Mathf.Lerp(1f, 0f, progress);
}
else
{
occlusionFade = 1f;
}
float t = Mathf.InverseLerp(minShowDistance, maxShowDistance, cameraDistance);
float currentScale = Mathf.Lerp(maxScale, minScale, t);
RectTransform areaRect = PlayerCanvas.Instance.enemyInfoUIArea.rectTransform;
Vector2 enemyScreenPos = SpaceConverter.WorldPointToUILocalPoint(areaRect, infoUIPos, playerCamera, null);
rectTransform.localScale = Vector3.one * currentScale;
rectTransform.anchoredPosition = enemyScreenPos;
}
public void UpdateHealth(bool isInstant = false)
{
float currentHealth = enemy.attributeSm["Health"];
float maximumHealth = enemy.attributeSm["MaximumHealth"];
//float ratio = currentHealth / maximumHealth;
healthBar.UpdateFillImage(currentHealth, maximumHealth);
if(!isInstant) healthBar.Blink(Color.white);
}
public void UpdateEnergy(bool isInstant = false)
{
float currentEnergy = enemy.attributeSm["Energy"];
float maximumEnergy = enemy.attributeSm["MaximumEnergy"];
energyBar.UpdateFillImage(currentEnergy, maximumEnergy);
if(!isInstant) energyBar.Blink(Color.white);
}
}
}