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 _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() : 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().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 --------------------] /// /// 添加或更新单位的负面状态显示 /// /// 技能类型 /// 是否有层数机制 /// 技能等级/层数 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(); } /// /// 移除指定状态显示 /// public void RemoveStatus(SkillType skillType) { _statusArea?.RemoveStatus(skillType); } /// /// 清除所有状态显示 /// public void ClearAllStatus() { _statusArea?.ClearAllStatus(); } /// /// 同步单位的技能数据到状态显示区域 /// 只显示 SkillInfo.ShowOnUnitMono = true 的技能 /// public void SyncStatusWithUnitSkills() { if (_statusArea == null || _unitData == null) return; _statusArea.SyncWithUnitSkills(_unitData); } /// /// 检查是否正在显示指定状态 /// public bool HasStatusDisplay(SkillType skillType) { return _statusArea?.HasStatus(skillType) ?? false; } /// /// 设置状态区域是否可见 /// 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(); if (canvasGroup == null) canvasGroup = _unitMono.InfoGroup.gameObject.AddComponent(); 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(); 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(); _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; } } }