798 lines
31 KiB
C#
798 lines
31 KiB
C#
using System.Collections.Generic;
|
||
using Logic;
|
||
using Logic.Multilingual;
|
||
using Logic.Skill;
|
||
using RuntimeData;
|
||
using TH1_Anim.UnitAtomAnim;
|
||
using TH1_Logic.Core;
|
||
using TH1Renderer;
|
||
using TH1Resource;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace TH1_Renderer
|
||
{
|
||
public class UnitRenderer
|
||
{
|
||
private uint _unitId;
|
||
private UnitData _unitData;
|
||
private static List<GridData> _aroundBuf;
|
||
private PlayerData _playerData;
|
||
private GridData _gridData;
|
||
private GameObject _ROUnit;
|
||
private UnitMono _unitMono;
|
||
|
||
public bool IsValid => _ROUnit != null && _unitMono != null && _unitMono.SpriteRenderer != null && _unitData != null;
|
||
|
||
public string GetDiagnosticString(MapData mapData)
|
||
{
|
||
UnitData currentUnit = null;
|
||
uint gridId = 0;
|
||
uint cityId = 0;
|
||
uint playerId = 0;
|
||
var hasData = false;
|
||
if (mapData != null)
|
||
{
|
||
hasData = mapData.UnitMap != null && mapData.UnitMap.GetUnitDataByUnitId(_unitId, out currentUnit);
|
||
mapData.GetGridIdByUnitId(_unitId, out gridId);
|
||
mapData.GetCityIdByUnitId(_unitId, out cityId);
|
||
mapData.GetPlayerIdByUnitId(_unitId, out playerId);
|
||
}
|
||
|
||
var pos = _ROUnit != null ? _ROUnit.transform.position : Vector3.zero;
|
||
var cachedUnit = _unitData != null
|
||
? $"{_unitData.UnitType}/{_unitData.GiantType}/{_unitData.UnitLevel}, hp={_unitData.Health}, alive={_unitData.IsAlive()}"
|
||
: "null";
|
||
var currentData = currentUnit != null
|
||
? $"{currentUnit.UnitType}/{currentUnit.GiantType}/{currentUnit.UnitLevel}, hp={currentUnit.Health}, alive={currentUnit.IsAlive()}"
|
||
: "null";
|
||
|
||
return $"uid={_unitId}, rendererValid={IsValid}, go={_ROUnit != null}, active={(_ROUnit != null && _ROUnit.activeSelf)}, pos=({pos.x:F2},{pos.y:F2},{pos.z:F2}), dataExists={hasData}, grid={gridId}, city={cityId}, player={playerId}, cached={cachedUnit}, current={currentData}";
|
||
}
|
||
|
||
private bool TryRefreshUnitRefs(bool requirePlayer = false, bool requireGrid = false)
|
||
{
|
||
var mapData = Main.MapData;
|
||
if (mapData == null || mapData.UnitMap == null)
|
||
{
|
||
_unitData = null;
|
||
_playerData = null;
|
||
_gridData = null;
|
||
return false;
|
||
}
|
||
|
||
if (!mapData.UnitMap.GetUnitDataByUnitId(_unitId, out _unitData) || _unitData == null)
|
||
{
|
||
_unitData = null;
|
||
_playerData = null;
|
||
_gridData = null;
|
||
return false;
|
||
}
|
||
|
||
if (requirePlayer && (!mapData.GetPlayerDataByUnitId(_unitId, out _playerData) || _playerData == null))
|
||
{
|
||
_playerData = null;
|
||
return false;
|
||
}
|
||
|
||
if (requireGrid && (!mapData.GetGridDataByUnitId(_unitId, out _gridData) || _gridData == null))
|
||
{
|
||
_gridData = null;
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
//------- 表现层RenderData ---------//
|
||
public bool IsAttackHighlight = false;
|
||
public bool IsSelectHighlight = false;
|
||
public bool IsAllyHighlight = false;
|
||
|
||
//------- Status Area ---------//
|
||
private UnitStatusArea _statusArea;
|
||
private float _infoGroupAlpha = 1.0f;
|
||
private float _citySelectionSpriteAlpha = 1.0f;
|
||
|
||
//--------------- AnimManager ----------------
|
||
public UnitAnimManager AnimManager;
|
||
|
||
|
||
private Vector3 originalPosition; // 记录初始位置
|
||
|
||
SpriteEffectController effectController;
|
||
|
||
//------bounce相关参数--------
|
||
bool _needBounce = false, _isBounceDown = true;
|
||
Vector3 bounceUpPos, bounceDownPos;
|
||
private float _bounceWaitTime = 0f;
|
||
float bounceTime = 0f;
|
||
|
||
|
||
bool _needMove = false;
|
||
Vector3 moveStartPos, moveEndPos;
|
||
float moveTime = 0f;
|
||
float moveFullTime = 0.3f;
|
||
bool renderVeteran = false;
|
||
private bool _isGlow = false;
|
||
private bool _isHideState = false;
|
||
|
||
// Shenlan 技能视觉效果:按 Time.time 循环变色
|
||
private static readonly Color[] _shenlanColors = new[]
|
||
{
|
||
new Color(1.0f, 0.4f, 0.4f), // 红
|
||
new Color(1.0f, 0.7f, 0.3f), // 橙
|
||
new Color(1.0f, 1.0f, 0.4f), // 黄
|
||
new Color(0.4f, 1.0f, 0.4f), // 绿
|
||
new Color(0.3f, 0.8f, 1.0f), // 青
|
||
new Color(0.4f, 0.4f, 1.0f), // 蓝
|
||
new Color(0.9f, 0.4f, 1.0f), // 紫
|
||
};
|
||
// 上一帧是否处于 Shenlan 染色状态(用于失效时一次性恢复白色)
|
||
private bool _shenlanTinted = false;
|
||
|
||
private bool _needAttack = false;
|
||
private AttackAnimType _attackAnimType = AttackAnimType.None;
|
||
private float _attackTime = 0f;
|
||
private bool _isAttackGo = false;
|
||
private bool _isAttackBack = false;
|
||
private bool _isAttackArrow = false;
|
||
private bool _isAttackBomb = false;
|
||
private bool _isAttackRemilia = false;
|
||
private bool _isAttackPatchouli = false;
|
||
private bool _isAttackMokou = false;
|
||
private bool _isAttackReisen = false;
|
||
private bool _isAttackKaguya = false;
|
||
|
||
|
||
private Vector3 _attackTargetPos, _attackBackPos;
|
||
private bool _needBack;
|
||
private float _attackGoFullTime = 0.15f;
|
||
private float _attackBackFullTime = 0.15f;
|
||
|
||
public UnitRenderer(GameObject prefab,Transform father, uint uid)
|
||
{
|
||
_unitId = uid;
|
||
|
||
AnimManager = new UnitAnimManager();
|
||
|
||
var table = Table.Instance;
|
||
if (!TryRefreshUnitRefs(requirePlayer: true, requireGrid: true) || prefab == null || father == null || table == null)
|
||
{
|
||
_unitData = null;
|
||
_playerData = null;
|
||
_gridData = null;
|
||
return;
|
||
}
|
||
|
||
Vector3 tpos = table.GridToWorld(_gridData,"isUnit");
|
||
_ROUnit = GameObject.Instantiate(prefab, tpos, Quaternion.identity, father);
|
||
_unitMono = _ROUnit != null ? _ROUnit.GetComponent<UnitMono>() : null;
|
||
if (_unitMono == null || _unitMono.SpriteRenderer == null)
|
||
{
|
||
if (_ROUnit != null)
|
||
GameObject.Destroy(_ROUnit);
|
||
_ROUnit = null;
|
||
_unitMono = null;
|
||
_unitData = null;
|
||
_playerData = null;
|
||
_gridData = null;
|
||
return;
|
||
}
|
||
|
||
// 初始化 StatusArea
|
||
if (_unitMono?.StatusAreaContainer != null && _unitMono?.StatusIconPrefab != null)
|
||
{
|
||
_statusArea = new UnitStatusArea(_unitMono.StatusAreaContainer, _unitMono.StatusIconPrefab, _unitMono.InfoGroup);
|
||
}
|
||
|
||
//InstantUpdateUnit(false);
|
||
|
||
}
|
||
|
||
public void Die()
|
||
{
|
||
//_ROUnit.gameObject.SetActive(false);
|
||
//Debug.Log("Delete !!!" + _unitData.Id + " name = " + _ROUnit.name + "; ID = " + _ROUnit.GetInstanceID());
|
||
//Debug.Log(_ROUnit.transform.Find("UnitSprite").GetComponent<SpriteRenderer>().sprite);
|
||
//_unitMono = null;
|
||
//Debug.Break();
|
||
|
||
// 清理状态区域
|
||
_statusArea?.ClearAllStatus();
|
||
|
||
if (_ROUnit != null)
|
||
GameObject.Destroy(_ROUnit.gameObject);
|
||
|
||
var mapRenderer = MapRenderer.Instance;
|
||
if (mapRenderer?.ROUnitMap != null)
|
||
mapRenderer.ROUnitMap.Remove(_unitId);
|
||
_unitData = null;
|
||
_playerData = null;
|
||
_gridData = null;
|
||
_unitMono = null;
|
||
_statusArea = null;
|
||
}
|
||
|
||
#region [-------------------- Status Area Management --------------------]
|
||
|
||
/// <summary>
|
||
/// 添加或更新单位的负面状态显示
|
||
/// </summary>
|
||
/// <param name="skillType">技能类型</param>
|
||
/// <param name="hasLevel">是否有层数机制</param>
|
||
/// <param name="level">技能等级/层数</param>
|
||
public void AddOrUpdateStatus(SkillType skillType, bool hasLevel = false, int level = 1)
|
||
{
|
||
if (_statusArea == null || _unitData == null) return;
|
||
_statusArea.AddOrUpdateStatus(skillType, _unitData.UnitFullType, hasLevel, level);
|
||
_statusArea.RefreshLayout();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除指定状态显示
|
||
/// </summary>
|
||
public void RemoveStatus(SkillType skillType)
|
||
{
|
||
_statusArea?.RemoveStatus(skillType);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除所有状态显示
|
||
/// </summary>
|
||
public void ClearAllStatus()
|
||
{
|
||
_statusArea?.ClearAllStatus();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同步单位的技能数据到状态显示区域
|
||
/// 只显示 SkillInfo.ShowOnUnitMono = true 的技能
|
||
/// </summary>
|
||
public void SyncStatusWithUnitSkills()
|
||
{
|
||
if (_statusArea == null || _unitData == null) return;
|
||
|
||
_statusArea.SyncWithUnitSkills(_unitData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否正在显示指定状态
|
||
/// </summary>
|
||
public bool HasStatusDisplay(SkillType skillType)
|
||
{
|
||
return _statusArea?.HasStatus(skillType) ?? false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置状态区域是否可见
|
||
/// </summary>
|
||
public void SetStatusAreaVisible(bool visible)
|
||
{
|
||
_statusArea?.SetAreaVisible(visible);
|
||
}
|
||
|
||
#endregion
|
||
|
||
public void InstantDisappear()
|
||
{
|
||
if (_ROUnit == null) return;
|
||
_ROUnit.SetActive(false);
|
||
}
|
||
|
||
public void InstantShow()
|
||
{
|
||
if (_ROUnit == null) return;
|
||
_ROUnit.SetActive(true);
|
||
}
|
||
|
||
public void SetInfoGroupAlpha(float alpha)
|
||
{
|
||
_infoGroupAlpha = Mathf.Clamp01(alpha);
|
||
if (_unitMono?.InfoGroup != null)
|
||
{
|
||
var canvasGroup = _unitMono.InfoGroup.GetComponent<CanvasGroup>();
|
||
if (canvasGroup == null)
|
||
canvasGroup = _unitMono.InfoGroup.gameObject.AddComponent<CanvasGroup>();
|
||
canvasGroup.alpha = _infoGroupAlpha;
|
||
}
|
||
|
||
SetGraphicAlpha(_unitMono?.ChessBG, _infoGroupAlpha);
|
||
SetGraphicAlpha(_unitMono?.ChessImg, _infoGroupAlpha);
|
||
}
|
||
|
||
public void SetCitySelectionSpriteAlpha(float alpha)
|
||
{
|
||
_citySelectionSpriteAlpha = Mathf.Clamp01(alpha);
|
||
ApplySpriteAlpha();
|
||
}
|
||
|
||
private static void SetGraphicAlpha(Graphic graphic, float alpha)
|
||
{
|
||
if (graphic == null) return;
|
||
var color = graphic.color;
|
||
color.a = alpha;
|
||
graphic.color = color;
|
||
}
|
||
|
||
private void ApplySpriteAlpha()
|
||
{
|
||
if (_unitMono?.SpriteRenderer == null) return;
|
||
var baseAlpha = 1.0f;
|
||
var mapData = Main.MapData;
|
||
if (mapData != null
|
||
&& mapData.PlayerMap != null
|
||
&& _unitData != null
|
||
&& _playerData != null
|
||
&& _unitData.IsHideState(mapData)
|
||
&& mapData.SameUnion(_playerData.Id, mapData.PlayerMap.SelfPlayerId))
|
||
{
|
||
baseAlpha = 0.5f;
|
||
}
|
||
|
||
var color = _unitMono.SpriteRenderer.color;
|
||
color.a = Mathf.Min(baseAlpha, _citySelectionSpriteAlpha);
|
||
_unitMono.SpriteRenderer.color = color;
|
||
}
|
||
|
||
public void Update()
|
||
{
|
||
if (_unitMono != null)
|
||
AnimManager?.Update(_unitMono);
|
||
UpdateShenlanTint();
|
||
}
|
||
|
||
// Shenlan 技能:单位贴图按 Time.time 每秒切换一种颜色。
|
||
// 只改 RGB,保留 alpha(HideState 用 alpha 控制半透明)。
|
||
private void UpdateShenlanTint()
|
||
{
|
||
if (_unitMono == null || _unitMono.SpriteRenderer == null) return;
|
||
if (_unitData == null || !_unitData.IsAlive())
|
||
{
|
||
if (_shenlanTinted)
|
||
{
|
||
var c = _unitMono.SpriteRenderer.color;
|
||
_unitMono.SpriteRenderer.color = new Color(1f, 1f, 1f, c.a);
|
||
_shenlanTinted = false;
|
||
}
|
||
return;
|
||
}
|
||
|
||
bool hasShenlan = _unitData.GetSkill(SkillType.Shenlan, out _);
|
||
if (hasShenlan)
|
||
{
|
||
int idx = Mathf.FloorToInt(Time.time) % _shenlanColors.Length;
|
||
if (idx < 0) idx += _shenlanColors.Length;
|
||
var target = _shenlanColors[idx];
|
||
var curr = _unitMono.SpriteRenderer.color;
|
||
_unitMono.SpriteRenderer.color = new Color(target.r, target.g, target.b, curr.a);
|
||
_shenlanTinted = true;
|
||
}
|
||
else if (_shenlanTinted)
|
||
{
|
||
var c = _unitMono.SpriteRenderer.color;
|
||
_unitMono.SpriteRenderer.color = new Color(1f, 1f, 1f, c.a);
|
||
_shenlanTinted = false;
|
||
}
|
||
}
|
||
|
||
public void RenderUpdateUnitDefense()
|
||
{
|
||
var mapData = Main.MapData;
|
||
if (_unitMono == null || mapData == null || !TryRefreshUnitRefs() || !_unitData.IsAlive()) return;
|
||
_unitMono.UpdateUnitDefense(_unitData.GetDefenseMultiplicationParamOnlyForDefenseShow(mapData));
|
||
}
|
||
|
||
public void RenderUpdateUnitImage()
|
||
{
|
||
if (_unitMono == null || Main.MapData == null || !TryRefreshUnitRefs()) return;
|
||
|
||
RenderUpdateUnitInfo();
|
||
|
||
//更新图像
|
||
RenderUpdateUnitSprite();
|
||
//更新防御显示信息
|
||
RenderUpdateUnitDefense();
|
||
//更新高亮
|
||
RenderUpdateUnitGlow();
|
||
//更新隐身透明度
|
||
RenderUpdateHideState();
|
||
//更新周围隐身提示
|
||
RenderUpdateHideAround();
|
||
//DebugRender
|
||
RenderUpdateDebug();
|
||
}
|
||
|
||
//这个会同时处理非player mapData的情况
|
||
//瞬间更新unit的视觉(不包括pos,不包括die,但是包括showoff) showoff开关,如果=true,先判断是否显隐,更新显隐,再决定更新image 如果=false,仅更新image,不处理显隐
|
||
//如果unit死了,不能直接die!!要等动画那边主动凋起才可以die
|
||
public bool InstantUpdateUnit(bool showoff)
|
||
{
|
||
if (_unitMono == null || !TryRefreshUnitRefs()) return false;
|
||
//如果要做显隐更新,先判断显隐,显的情况下,再更新image
|
||
//如果不做显隐更新,直接更新image
|
||
if ((showoff && RenderUpdateUnitShowOff())
|
||
|| !showoff)
|
||
RenderUpdateUnitImage();
|
||
return _unitData != null && _unitData.InMainSight();
|
||
|
||
}
|
||
|
||
//瞬间更新unit的 die的情况
|
||
public bool InstantUpdateTryDie()
|
||
{
|
||
if (!TryRefreshUnitRefs() || !_unitData.IsAlive())
|
||
{
|
||
Die();
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
//瞬间更新unit的pos到最新 最正确的位置
|
||
public void InstantUpdateUnitPos()
|
||
{
|
||
RenderUpdateUnitPosition();
|
||
}
|
||
|
||
public void RenderUpdateUnitInfo()
|
||
{
|
||
if (_unitMono == null || !TryRefreshUnitRefs() || Table.Instance?.UnitTypeDataAssets == null) return;
|
||
if (!_unitMono?.HealthText || !_unitMono?.UnitInfoBG) return;
|
||
_unitMono.HealthText.text = _unitData.Health.ToString();
|
||
//处理血量的颜色。如果血量<一半且<5,那么赋予红色,否则白色
|
||
if(_unitData.Health < 5 && _unitData.Health < _unitData.GetMaxHealth() / 2)
|
||
_unitMono.HealthText.color = _unitMono.UnitLowHealth;
|
||
else
|
||
_unitMono.HealthText.color = Color.white;
|
||
|
||
if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(_unitData.UnitFullType, out var unitInfo))
|
||
return;
|
||
var chessType = unitInfo.ChessType;
|
||
if (chessType == ChessType.None)
|
||
{
|
||
if(Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(_unitData.CarryUnitFullType, out var carryUnitInfo))
|
||
chessType = carryUnitInfo.ChessType;
|
||
}
|
||
if (chessType != ChessType.None && _unitMono.ChessImg != null)
|
||
{
|
||
if (Table.Instance.UnitTypeDataAssets.GetChessTypeInfo(chessType ,out var chessInfo))
|
||
_unitMono.ChessImg.sprite = chessInfo.ChessSprite;
|
||
}
|
||
|
||
|
||
//根据敌我情况更新infoBG的颜色
|
||
//_unitInfoBGImg.sprite = (Main.MapData.SameUnion(_playerData.Id , Main.MapData.PlayerMap.SelfPlayerId)) ? ResourceCache.Instance.SpriteCache.UnitInfoSelf :
|
||
if (Main.MapData == null) return;
|
||
if (Main.MapData.PlayerMap == null) return;
|
||
if (!Main.MapData.GetPlayerDataByUnitId(_unitData.Id, out var playerData)) return;
|
||
var col = _unitMono.UnitBGBlue;
|
||
if (playerData.Id != Main.MapData.PlayerMap.SelfPlayerId)
|
||
col =(Main.MapData.SameUnion(playerData.Id, Main.MapData.PlayerMap.SelfPlayerId))
|
||
? _unitMono.UnitBGGreen
|
||
: _unitMono.UnitBGRed;
|
||
if (_unitMono.ChessBG != null)
|
||
_unitMono.ChessBG.color = col;
|
||
_unitMono.UnitInfoBG.color = col;
|
||
if (!Mathf.Approximately(_infoGroupAlpha, 1.0f))
|
||
SetInfoGroupAlpha(_infoGroupAlpha);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//如果是盟友,额外显示盟友标记;背盟状态也显示但用背盟颜色
|
||
var selfPlayerId = Main.MapData.PlayerMap.SelfPlayerId;
|
||
bool isSelf = playerData.Id == selfPlayerId;
|
||
bool sameUnion = Main.MapData.SameUnion(playerData.Id, selfPlayerId);
|
||
bool sameOrJustBreak = Main.MapData.SameUnionOrJustBreakUnion(playerData.Id, selfPlayerId);
|
||
bool justBreakUnion = sameOrJustBreak && !sameUnion;
|
||
bool showUnionIcon = !isSelf && (sameUnion || justBreakUnion);
|
||
if (_unitMono.UnionBG != null)
|
||
{
|
||
_unitMono.UnionBG.SetActive(showUnionIcon);
|
||
if (showUnionIcon)
|
||
{
|
||
var unionImg = _unitMono.UnionBGImage != null
|
||
? _unitMono.UnionBGImage
|
||
: _unitMono.UnionBG.GetComponent<UnityEngine.UI.Image>();
|
||
if (unionImg != null)
|
||
unionImg.color = justBreakUnion ? _unitMono.UnionBGBetrayColor : _unitMono.UnionBGNormalColor;
|
||
}
|
||
}
|
||
|
||
//更改兵种显示文字
|
||
if(_unitMono.UnitInfoName != null
|
||
&& MultilingualManager.Instance != null
|
||
&& Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(_unitData.UnitType,_unitData.GiantType,_unitData.UnitLevel,out var info))
|
||
MultilingualManager.Instance.SetUIText(_unitMono.UnitInfoName,info.Name);
|
||
|
||
SyncStatusWithUnitSkills();
|
||
}
|
||
|
||
public void RenderUpdateDebug()
|
||
{
|
||
if (_unitMono == null || !TryRefreshUnitRefs(requirePlayer: true) || _unitMono.RODebugText == null || _unitMono.DebugText == null || Main.MapData?.PlayerMap?.SelfPlayerData == null) return;
|
||
if (DebugCenter.Instance.DebugMode)
|
||
{
|
||
if(!_unitMono.RODebugText.activeSelf)
|
||
_unitMono.RODebugText.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
_unitMono.RODebugText.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
_unitMono.DebugText.text = "";
|
||
_unitMono.DebugText.text += $"ID{_unitId} GetActionPoint(ActionPointType.Attack){_unitData.GetActionPoint(ActionPointType.Attack)} GetActionPoint(ActionPointType.Move){_unitData.GetActionPoint(ActionPointType.Move)} GetActionPoint(ActionPointType.Capture){_unitData.GetActionPoint(ActionPointType.Move)}\n";
|
||
|
||
//如果不是我方单位,显示军团及unit的战略
|
||
_unitMono.DebugText.text += $"Lid={_unitData.LegionId}\n";
|
||
if(!Main.MapData.CheckUnitIdBelongPlayerId(_unitData.Id,Main.MapData.PlayerMap.SelfPlayerData.Id))
|
||
{
|
||
var mainEditor = MainEditor.Instance;
|
||
if (mainEditor?.Data != null)
|
||
{
|
||
mainEditor.GetUnitStrategy(_unitId, _unitData.LegionId, _playerData.Id, out var st,
|
||
out var tar, out var type);
|
||
_unitMono.DebugText.text += $"ST:{st} TAR:{tar} TYPE:{type}";
|
||
}
|
||
}
|
||
}
|
||
public bool RenderUpdateUnitShowOff()
|
||
{
|
||
var mapData = Main.MapData;
|
||
if (_unitMono == null || mapData == null || mapData.PlayerMap == null || mapData.PlayerMap.SelfPlayerData == null || !TryRefreshUnitRefs())
|
||
return false;
|
||
bool ret = _unitData.InMainSight();
|
||
//如果在视野内但是敌方隐身单位,对当前玩家不可见
|
||
if (ret && _unitData.IsHideAndCantSee(mapData, mapData.PlayerMap.SelfPlayerData))
|
||
ret = false;
|
||
//由隐转显时,先把 transform 同步到当前 grid,避免显示在过期位置
|
||
//(敌方隐身单位全程 SetActive(false),RenderUpdateUnitPosition 没机会跑)
|
||
if (ret && !_unitMono.gameObject.activeSelf)
|
||
RenderUpdateUnitPosition();
|
||
_unitMono.gameObject.SetActive(ret); //如果不在玩家视野,就暂时隐藏这个单位的显示
|
||
return ret;
|
||
}
|
||
public void RenderUpdateUnitGlow()
|
||
{
|
||
var mapData = Main.MapData;
|
||
var table = Table.Instance;
|
||
if (_unitMono == null || _unitMono.SpriteRenderer == null || mapData == null || table == null || table.UnitTypeDataAssets == null || ResourceCache.Instance?.MatCache == null || !TryRefreshUnitRefs())
|
||
return;
|
||
var player = _unitData.Player(mapData);
|
||
if (player == null) return;
|
||
Sprite sprite;
|
||
if (!table.UnitTypeDataAssets.GetUnitSprite(mapData, _unitData, out sprite))
|
||
return;
|
||
_unitMono.SpriteRenderer.sprite = sprite;
|
||
_unitMono.SpriteRenderer.material = ResourceCache.Instance.MatCache.TH1URPShaders_Default;
|
||
_isGlow = false;
|
||
|
||
//首先处理玩家(判断是否置灰或者高亮)
|
||
if (player.IsSelfPlayer())
|
||
{
|
||
var mapRenderer = MapRenderer.Instance;
|
||
//如果MP>0 或者周围有可以攻击的目标,或者可以移动的目标,或者说可以占领城市
|
||
if (_unitData.GetActionPoint(ActionPointType.Move) > 0
|
||
|| (mapRenderer != null && mapRenderer.CheckUnitHasMoveAttackTarget(_unitId))
|
||
|| (mapRenderer != null && mapRenderer.CheckUnitHasSpecialUnitActionTarget(_unitId)))
|
||
{
|
||
_unitMono.SpriteRenderer.material = ResourceCache.Instance.MatCache.TH1URPShaders_Sprite_Glow;
|
||
_isGlow = true;
|
||
|
||
}
|
||
else
|
||
_unitMono.SpriteRenderer.material = ResourceCache.Instance.MatCache.TH1URPShaders_Sprite_WhiteOverlay;
|
||
}
|
||
//然后处理AI(主要就判断是否置灰)
|
||
else
|
||
{
|
||
//如果是正在行动的AI
|
||
if (mapData.CurPlayer == player)
|
||
{
|
||
if(_unitData.GetActionPoint(ActionPointType.Move) == 0 && _unitData.GetActionPoint(ActionPointType.Capture) == 0 && _unitData.GetActionPoint(ActionPointType.Attack) == 0 && _unitData.GetActionPoint(ActionPointType.Move) == 0)
|
||
_unitMono.SpriteRenderer.material = ResourceCache.Instance.MatCache.TH1URPShaders_Sprite_WhiteOverlay;
|
||
}
|
||
else
|
||
//如果是还没行动的AI
|
||
if(mapData.GetPlayerHasActedInBigTurn(player))
|
||
{
|
||
//啥都不做
|
||
}
|
||
//否则是已经行动过的AI
|
||
else
|
||
{
|
||
_unitMono.SpriteRenderer.material = ResourceCache.Instance.MatCache.TH1URPShaders_Sprite_WhiteOverlay;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
public void RenderUpdateHideState()
|
||
{
|
||
var mapData = Main.MapData;
|
||
if (_unitMono == null || _unitMono.SpriteRenderer == null || mapData == null || mapData.PlayerMap == null || !TryRefreshUnitRefs(requirePlayer: true))
|
||
return;
|
||
|
||
bool hideState = _unitData.IsHideState(mapData);
|
||
bool isSelfOrAlly = mapData.SameUnion(_playerData.Id, mapData.PlayerMap.SelfPlayerId);
|
||
|
||
// 状态未变时的处理:确保显示状态正确
|
||
if (hideState == _isHideState)
|
||
{
|
||
if (hideState)
|
||
{
|
||
if (isSelfOrAlly)
|
||
{
|
||
ApplySpriteAlpha();
|
||
}
|
||
else
|
||
{
|
||
// 敌方隐身单位:确保保持隐藏(防止被ShowOff重新显示)
|
||
InstantDisappear();
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
_isHideState = hideState;
|
||
|
||
if (hideState)
|
||
{
|
||
// 进入HideState
|
||
if (isSelfOrAlly)
|
||
{
|
||
// 己方/盟友:显示但半透明(0.5f)
|
||
InstantShow();
|
||
ApplySpriteAlpha();
|
||
}
|
||
else
|
||
{
|
||
// 敌方:完全隐藏(SetActive(false))
|
||
InstantDisappear();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 退出HideState:恢复显示(视野系统会决定最终显隐)
|
||
InstantShow();
|
||
ApplySpriteAlpha();
|
||
}
|
||
}
|
||
|
||
public void RenderUpdateHideAround()
|
||
{
|
||
var mapData = Main.MapData;
|
||
if (_unitMono == null || _unitMono.HideAround == null || mapData?.GridMap == null || !TryRefreshUnitRefs(requirePlayer: true)) return;
|
||
bool show = false;
|
||
//只对当前玩家自己的单位显示
|
||
var curGrid = _unitData.Grid(mapData);
|
||
if (_playerData != null && _playerData.IsSelfPlayer() && curGrid != null)
|
||
{
|
||
_aroundBuf ??= new List<GridData>();
|
||
_aroundBuf.Clear();
|
||
mapData.GridMap.GetAroundGridData(1, 1, curGrid, _aroundBuf);
|
||
foreach (var around in _aroundBuf)
|
||
{
|
||
if (around == curGrid) continue;
|
||
if (!around.RealUnit(mapData, out var nearUnit)) continue;
|
||
if (!nearUnit.IsHideState(mapData)) continue;
|
||
//排除自己的单位和同盟单位
|
||
if (mapData.SameUnionByUnitId(_unitData.Id, nearUnit.Id)) continue;
|
||
show = true;
|
||
break;
|
||
}
|
||
}
|
||
_unitMono.HideAround.gameObject.SetActive(show);
|
||
}
|
||
|
||
#region [-------------------- Damage Preview --------------------]
|
||
|
||
public void ShowDamagePreview(int damage, Color color)
|
||
{
|
||
if (_unitMono?.DamagePreviewPanel == null || _unitMono?.DamagePreviewText == null) return;
|
||
_unitMono.DamagePreviewPanel.SetActive(true);
|
||
_unitMono.DamagePreviewText.text = "-" + damage;
|
||
_unitMono.DamagePreviewText.color = color;
|
||
}
|
||
|
||
public void HideDamagePreview()
|
||
{
|
||
if (_unitMono?.DamagePreviewPanel == null) return;
|
||
_unitMono.DamagePreviewPanel.SetActive(false);
|
||
}
|
||
|
||
#endregion
|
||
|
||
public void RenderUpdataHighlight()
|
||
{
|
||
if (_unitMono == null) return;
|
||
if (_unitMono.AttackHighlight != null)
|
||
_unitMono.AttackHighlight.SetActive(IsAttackHighlight);
|
||
if (_unitMono.SelectHighlight != null)
|
||
_unitMono.SelectHighlight.SetActive(IsSelectHighlight);
|
||
if (_unitMono.AllyHighlight != null)
|
||
_unitMono.AllyHighlight.SetActive(IsAllyHighlight);
|
||
}
|
||
|
||
public void SetSelectHighlight(bool v)
|
||
{
|
||
if (IsSelectHighlight == v)
|
||
return;
|
||
IsSelectHighlight = v;
|
||
var mapRenderer = MapRenderer.Instance;
|
||
if (mapRenderer?.HighlightUnitIdSet == null) return;
|
||
mapRenderer.HighlightUnitIdSet.Add(_unitId);
|
||
mapRenderer.HighlightUnitIdSetRenderMark = true;
|
||
}
|
||
|
||
public void SetAttackHighlight(bool v)
|
||
{
|
||
if (IsAttackHighlight == v)
|
||
return;
|
||
IsAttackHighlight = v;
|
||
var mapRenderer = MapRenderer.Instance;
|
||
if (mapRenderer?.HighlightUnitIdSet == null) return;
|
||
mapRenderer.HighlightUnitIdSet.Add(_unitId);
|
||
mapRenderer.HighlightUnitIdSetRenderMark = true;
|
||
}
|
||
|
||
public void SetAllyHighlight(bool v)
|
||
{
|
||
if (IsAllyHighlight == v)
|
||
return;
|
||
IsAllyHighlight = v;
|
||
var mapRenderer = MapRenderer.Instance;
|
||
if (mapRenderer?.HighlightUnitIdSet == null) return;
|
||
mapRenderer.HighlightUnitIdSet.Add(_unitId);
|
||
mapRenderer.HighlightUnitIdSetRenderMark = true;
|
||
}
|
||
|
||
public void RenderUpdateUnitSprite()
|
||
{
|
||
var mapData = Main.MapData;
|
||
var table = Table.Instance;
|
||
if (_unitMono == null || _unitMono.SpriteRenderer == null || mapData == null || table == null || table.UnitTypeDataAssets == null || !TryRefreshUnitRefs())
|
||
return;
|
||
|
||
if (!table.UnitTypeDataAssets.GetUnitSprite(mapData, _unitData, out var sprite) || sprite == null)
|
||
return;
|
||
_unitMono.SpriteRenderer.sprite = sprite;
|
||
//RenderUpdateUnitSpecialSprite();
|
||
|
||
}
|
||
|
||
|
||
public void RenderUpdateUnitPosition()
|
||
{
|
||
var mapData = Main.MapData;
|
||
var table = Table.Instance;
|
||
if (_unitMono == null || mapData == null || table == null || !TryRefreshUnitRefs(requireGrid: true))
|
||
return;
|
||
|
||
var t = _unitData.Grid(mapData)?.Pos;
|
||
if (t == null) return;
|
||
_unitMono.transform.position = table.GridPosToWorld(new Vector2Int(t.X,t.Y),"isUnit");
|
||
}
|
||
|
||
public Vector3 GetPosition()
|
||
{
|
||
return _ROUnit != null ? _ROUnit.transform.position : Vector3.zero;
|
||
}
|
||
|
||
public bool isGlow()
|
||
{
|
||
return _isGlow;
|
||
}
|
||
|
||
}
|
||
}
|