999 lines
41 KiB
C#
999 lines
41 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using RuntimeData;
|
||
using Animancer;
|
||
using Logic;
|
||
using Logic.Action;
|
||
using Logic.AI;
|
||
using Logic.CrashSight;
|
||
using TH1_Logic.Config;
|
||
using TH1_Logic.Core;
|
||
using TH1Resource;
|
||
using Unity.IO.LowLevel.Unsafe;
|
||
using Object = UnityEngine.Object;
|
||
using Random = UnityEngine.Random;
|
||
using TMPro;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine.UI;
|
||
|
||
namespace TH1Renderer
|
||
{
|
||
|
||
public class GridRenderer
|
||
{
|
||
private static readonly CommonActionId GainFishActionId = new CommonActionId
|
||
{
|
||
ActionType = CommonActionType.Gain,
|
||
ResourceType = ResourceType.Fish,
|
||
};
|
||
|
||
private MapData _mapData;
|
||
private GameObject _ROGrid;
|
||
private uint _gridId;
|
||
private bool _cityWallMark = false;
|
||
|
||
private Color terriColor = new Color(0.9f, 0.9f, 1f);
|
||
|
||
//-------- 表现层数据Rdata --------//
|
||
public bool IsSelectHighlight = false;
|
||
public bool IsMoveHighlight = false;
|
||
public bool IsAttackHighlight = false;
|
||
public MoveHighlightType MoveHighlightTypes { get; private set; } = MoveHighlightType.None;
|
||
|
||
|
||
//--------- 瞬间更新的动画 --------
|
||
public int NowCityBuildlingLevel;
|
||
public CivEnum NowCityCiv;
|
||
public CivEnum UpdateCityCiv;
|
||
public int UpdateCityBuildingLevel;
|
||
public bool UpdateGrid;
|
||
|
||
public float RandomWait;
|
||
|
||
//-------- Update缓存数据 --------//
|
||
private GridData _gridData;
|
||
private bool _freeland;
|
||
private CityData _cityData;
|
||
private PlayerData _playerData;
|
||
|
||
private GameObject _land,
|
||
_gridSp,
|
||
_mountain,
|
||
_forest,
|
||
_road,
|
||
_resource,
|
||
_cityBuilding,
|
||
_cityWall,
|
||
_fog,
|
||
_borderUpLeft,
|
||
_borderUpRight,
|
||
_borderDownLeft,
|
||
_borderDownRight,
|
||
_cityBorderUpLeft,
|
||
_cityBorderUpRight,
|
||
_cityBorderDownLeft,
|
||
_cityBorderDownRight,
|
||
_selectHighlight,
|
||
_moveHighlight,
|
||
_moveHighlightTypeGroup,
|
||
_attackHighlight,
|
||
_effect,
|
||
_RODebugText;
|
||
private TextMeshPro _debugText;
|
||
private readonly GameObject[] _moveHighlightTypeSlots = new GameObject[4];
|
||
private readonly SpriteRenderer[] _moveHighlightTypeRenderers = new SpriteRenderer[4];
|
||
private SpriteRenderer _moveHighlightRenderer;
|
||
private Sprite _defaultMoveHighlightSprite;
|
||
private Color _defaultMoveHighlightColor = Color.white;
|
||
private static readonly MoveHighlightType[] MoveHighlightDisplayOrder =
|
||
{
|
||
MoveHighlightType.Slow,
|
||
MoveHighlightType.Road,
|
||
MoveHighlightType.Boat,
|
||
MoveHighlightType.Ashore,
|
||
MoveHighlightType.Sanae,
|
||
MoveHighlightType.Teleport,
|
||
MoveHighlightType.Momiji,
|
||
MoveHighlightType.Yuugi,
|
||
};
|
||
|
||
public int x, y;
|
||
string forcesName, civName;
|
||
bool needBounce = false, isBounceDown = true,levelupBounce = false;
|
||
Vector3 bounceUpPos, bounceDownPos;
|
||
|
||
private float _bounceWaitTime = 0f;
|
||
float bounceTime = 0f;
|
||
float bounceDownFullTime = 0.13f;
|
||
float bounceUpFullTime = 0.07f;
|
||
|
||
float levelupBounceDownFullTime = 0.33f;
|
||
float levelupBounceUpFullTime = 0.07f;
|
||
|
||
|
||
//-------- VFX管理器 --------
|
||
public GridVFXManager GridVFXManager;
|
||
private Sprite _dieHint;
|
||
private Sprite _counterDieHint;
|
||
|
||
|
||
bool renderVeteran = false;
|
||
|
||
public GridRenderer(GameObject prefab,Transform father, uint gridId, MapData mapData, Main main)
|
||
{
|
||
_mapData = mapData;
|
||
_gridId = gridId;
|
||
mapData.GridMap.GetGridDataByGid(_gridId,out _gridData);
|
||
_freeland = !_mapData.GetCityDataByTerritoryGid(_gridId,out _cityData);
|
||
if(!_freeland)
|
||
_mapData.GetPlayerDataByCityId(_cityData.Id,out _playerData);
|
||
if (!(_cityData == null) && !(_playerData == null))
|
||
{
|
||
_mapData.GridMap.GetGridDataByGid(gridId, out var g1);
|
||
}
|
||
Vector3 tpos = Table.Instance.GridToWorld(_gridData);
|
||
_ROGrid = GameObject.Instantiate(prefab,tpos, Quaternion.identity, father);
|
||
Init(_gridData);
|
||
|
||
}
|
||
|
||
public GameObject GetROGrid() { return _ROGrid; }
|
||
|
||
public GridData Grid() { return _gridData; }
|
||
|
||
public void InstantUpdateGrid(bool v = true) { UpdateGrid = v; }
|
||
public void InstantUpdateCityBuilding(int v,CivEnum civ) { UpdateCityBuildingLevel = v; UpdateCityCiv = civ; }
|
||
|
||
public bool IsBelongSelfPlayer()
|
||
{
|
||
return _gridData.Player(Main.MapData).IsSelfPlayer();
|
||
}
|
||
|
||
private void ClearHistoryRenderMark()
|
||
{
|
||
GridVFXManager.Clear();
|
||
}
|
||
//判断各自是否要bounce 并处理bounce动画
|
||
private void UpdateBounceAnim()
|
||
{
|
||
var downFullTime = levelupBounce? levelupBounceDownFullTime : bounceUpFullTime;
|
||
var upFullTime = levelupBounce ? levelupBounceUpFullTime : bounceUpFullTime;
|
||
if (needBounce)
|
||
{
|
||
if (_bounceWaitTime > 0)
|
||
_bounceWaitTime -= Time.deltaTime;
|
||
else
|
||
{
|
||
if (isBounceDown)
|
||
{
|
||
bounceTime += Time.deltaTime / downFullTime;
|
||
if (levelupBounce)
|
||
{
|
||
float easedT = 1f - Mathf.Pow(1f - bounceTime, 3);
|
||
_ROGrid.transform.position = Vector3.Lerp(bounceUpPos, bounceDownPos, bounceTime);
|
||
}
|
||
else
|
||
_ROGrid.transform.position = Vector3.Lerp(bounceUpPos, bounceDownPos, bounceTime);
|
||
|
||
if (bounceTime >= 1f)
|
||
{
|
||
isBounceDown = false;
|
||
bounceTime = 0f;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bounceTime += Time.deltaTime / upFullTime;
|
||
_ROGrid.transform.position = Vector3.Lerp(bounceDownPos, bounceUpPos, bounceTime);
|
||
if (bounceTime >= 1f)
|
||
needBounce = false;
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//处理VFXManagerDict下每个Effect的Update
|
||
|
||
public void Update()
|
||
{
|
||
//step #1 每帧更新每个grid相关的player city的缓存数据
|
||
_mapData.GridMap.GetGridDataByGid(_gridId, out _gridData);
|
||
_freeland = !_mapData.GetCityDataByTerritoryGid(_gridId, out _cityData);
|
||
if (!_freeland) _mapData.GetPlayerDataByCityId(_cityData.Id, out _playerData);
|
||
|
||
//step #2 处理需要瞬间更新gridData视觉的情况
|
||
if (UpdateGrid)
|
||
{
|
||
UpdateGrid = false;
|
||
RenderUpdateGridWithoutCityBuilding();
|
||
}
|
||
|
||
if (UpdateCityBuildingLevel != NowCityBuildlingLevel)
|
||
{
|
||
NowCityBuildlingLevel = UpdateCityBuildingLevel;
|
||
RenderUpdateCityBuilding(_cityData.Id);
|
||
}
|
||
|
||
if (NowCityCiv != UpdateCityCiv)
|
||
{
|
||
NowCityCiv = UpdateCityCiv;
|
||
RenderUpdateCityBuilding(_cityData.Id);
|
||
}
|
||
|
||
|
||
//step #3 查看城市边界的更新情况,这个没有视野也会显示的,目前都是瞬间更新
|
||
UpdateCityBorder();
|
||
|
||
//step #4 判断各自是否要bounce
|
||
UpdateBounceAnim();
|
||
|
||
//step #5 驱动VFXManager的所有VFX对象的update
|
||
GridVFXManager.Update();
|
||
}
|
||
|
||
public void FirstShowGrid()
|
||
{
|
||
//Step #1 播放雾气消失动画
|
||
PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
|
||
//Step #2 呈现格子画面
|
||
RenderUpdateGridWithoutCityBuilding();
|
||
//Step #3 如果有city,更新city情况
|
||
var city = _gridData.CityOnGrid(Main.MapData);
|
||
if (city != null)
|
||
{
|
||
RenderUpdateCityBuilding(_cityData.Id);
|
||
_cityData.CityInfoRenderer(Main.MapData)?.InstantUpdateCityInfo();
|
||
}
|
||
|
||
//Step #4 如果有unit,更新unit的表现,更新unit的位置
|
||
if (_gridData.MainSelfPlayerVisibleUnit(out var unit))
|
||
{
|
||
//unit.RenderMark = true;
|
||
unit.Renderer(Main.MapData)?.InstantUpdateUnit(true);
|
||
unit.Renderer(Main.MapData)?.InstantUpdateUnitPos();
|
||
//更新该单位周围其他单位的高亮状态
|
||
MapRenderer.Instance.UpdateAroundHighlight(Main.MapData,_gridData);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
public void PlayVFXInSight(GridVFXParams param, GridVFXPlayType playType = GridVFXPlayType.PlayOnce)
|
||
{
|
||
//当前玩家有该格子的视野,才播放该动画
|
||
if (Main.MapData?.PlayerMap?.SelfPlayerData?.Sight?.SightGidSet == null || _gridData == null || GridVFXManager == null)
|
||
return;
|
||
if(Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(_gridData.Id))
|
||
GridVFXManager.PlayVFX(param,playType);
|
||
}
|
||
|
||
public void PlayVFXForce(GridVFXParams param, GridVFXPlayType playType = GridVFXPlayType.PlayOnce)
|
||
{
|
||
GridVFXManager.PlayVFX(param,playType);
|
||
}
|
||
|
||
private void RenderUpdateDebug()
|
||
{
|
||
if (DebugCenter.Instance.DebugMode)
|
||
{
|
||
if(!_RODebugText.activeSelf)
|
||
_RODebugText.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
_RODebugText.SetActive(false);
|
||
return;
|
||
}
|
||
_debugText.text = "";
|
||
_debugText.text += $"ID={_gridId}";
|
||
_debugText.text += $" pos={_gridData.Pos.X} {_gridData.Pos.Y}\n";
|
||
if(_gridData.buildingLevel > 0)
|
||
_debugText.text += $"lv = {_gridData.buildingLevel}\n";
|
||
if(_gridData.Feature == TerrainFeature.Road)
|
||
_debugText.text += $"road\n";
|
||
|
||
}
|
||
|
||
private void Init(GridData t)
|
||
{
|
||
|
||
x = (int)t.Pos.X;
|
||
y = (int)t.Pos.Y;
|
||
//Vector3 pos = transform.position;
|
||
//pos.z = GridData.pos.x + GridData.pos.y;
|
||
//transform.position = pos;
|
||
_land = _ROGrid.transform.Find("Land").gameObject;
|
||
_gridSp = _ROGrid.transform.Find("GridSp")?.gameObject;
|
||
_road = _ROGrid.transform.Find("Road").gameObject;
|
||
_mountain = _ROGrid.transform.Find("Mountain").gameObject;
|
||
_forest = _ROGrid.transform.Find("Forest").gameObject;
|
||
_resource = _ROGrid.transform.Find("Resource").gameObject;
|
||
_cityBuilding = _ROGrid.transform.Find("cityBuilding").gameObject;
|
||
_cityWall = _ROGrid.transform.Find("cityWall").gameObject;
|
||
_fog = _ROGrid.transform.Find("Fog").gameObject;
|
||
_borderUpLeft = _ROGrid.transform.Find("BorderUpLeft").gameObject;
|
||
_borderUpRight = _ROGrid.transform.Find("BorderUpRight").gameObject;
|
||
_borderDownLeft = _ROGrid.transform.Find("BorderDownLeft").gameObject;
|
||
_borderDownRight = _ROGrid.transform.Find("BorderDownRight").gameObject;
|
||
_cityBorderUpLeft = _ROGrid.transform.Find("CityBorderUpLeft").gameObject;
|
||
_cityBorderUpRight = _ROGrid.transform.Find("CityBorderUpRight").gameObject;
|
||
_cityBorderDownLeft = _ROGrid.transform.Find("CityBorderDownLeft").gameObject;
|
||
_cityBorderDownRight = _ROGrid.transform.Find("CityBorderDownRight").gameObject;
|
||
_selectHighlight = _ROGrid.transform.Find("SelectHighlight").gameObject;
|
||
_moveHighlight = _ROGrid.transform.Find("MoveHighlight").gameObject;
|
||
_moveHighlightRenderer = _moveHighlight.GetComponent<SpriteRenderer>();
|
||
if (_moveHighlightRenderer != null)
|
||
{
|
||
_defaultMoveHighlightSprite = _moveHighlightRenderer.sprite;
|
||
_defaultMoveHighlightColor = _moveHighlightRenderer.color;
|
||
}
|
||
InitMoveHighlightTypeGroup();
|
||
_attackHighlight = _ROGrid.transform.Find("AttackHighlight").gameObject;
|
||
_effect = _ROGrid.transform.Find("Effect").gameObject;
|
||
|
||
_RODebugText = _ROGrid.transform.Find("DebugText").gameObject;
|
||
_debugText = _RODebugText?.GetComponent<TextMeshPro>();
|
||
|
||
|
||
foreach(Transform child in _effect.transform)
|
||
child.gameObject.SetActive(false);
|
||
|
||
//创建特效管理器Dict
|
||
GridVFXManager = new GridVFXManager(_effect);
|
||
|
||
RenderUpdateGridWithoutCityBuilding();
|
||
//UpdateBorder();fog自带updateborder
|
||
|
||
}
|
||
|
||
private void RenderUpdateGridWithoutCityBuilding()
|
||
{
|
||
UpdateLand();
|
||
UpdateGridSp();
|
||
UpdateRoad();
|
||
UpdateMountain();
|
||
UpdateForest();
|
||
UpdateResource();
|
||
UpdateCityWall();
|
||
UpdateCityBorder();
|
||
UpdateFog();
|
||
UpdateGridVFX();
|
||
RenderUpdateDebug();
|
||
//UpdateBorder();fog自带updateborder
|
||
}
|
||
public void RenderUpdateCityBuilding(uint cityId)
|
||
{
|
||
if (_mapData?.CityMap == null || _cityBuilding == null || Table.Instance == null) return;
|
||
_mapData.CityMap.GetCityById(cityId,out CityData cityData);
|
||
_mapData.GetPlayerDataByCityId(cityId, out PlayerData playerData);
|
||
if (cityData == null || playerData == null) return;
|
||
int citylevel = cityData.Level;
|
||
if (citylevel < 0
|
||
|| citylevel >= Table.Instance.cityLevel2HouseEdge.Length
|
||
|| citylevel >= Table.Instance.cityLevel2HouseNumber.Length
|
||
|| citylevel >= Table.Instance.cityLevel2HouseHeight.Length
|
||
|| citylevel >= Table.Instance.cityLevel2HouseType.Length)
|
||
return;
|
||
int houseEdge = Table.Instance.cityLevel2HouseEdge[citylevel];
|
||
int houseSize = houseEdge * houseEdge;
|
||
int houseCount = Table.Instance.cityLevel2HouseNumber[citylevel];
|
||
int houseHeight = Table.Instance.cityLevel2HouseHeight[citylevel];
|
||
int houseTypeCount = Table.Instance.cityLevel2HouseType[citylevel];
|
||
if (houseEdge <= 0 || houseSize <= 0 || houseCount <= 0 || houseHeight <= 0 || houseTypeCount <= 0) return;
|
||
if (houseCount < houseSize) houseCount = houseSize;
|
||
int[] housePosHeight = new int[houseSize];
|
||
int[,] textureType = new int[houseHeight, houseCount];
|
||
|
||
for (int k = 0; k < houseSize; k++)
|
||
{
|
||
for (int l = 0; l < houseHeight; l++)
|
||
textureType[l, k] = 0; //初始化
|
||
housePosHeight[k] = 1;
|
||
textureType[0, k] = Random.Range(0, houseTypeCount);
|
||
}
|
||
for (int k = houseSize; k < houseCount; k++)
|
||
{
|
||
int randPos = Random.Range(0, houseSize);
|
||
if (housePosHeight[randPos] >= houseHeight)
|
||
{
|
||
for (randPos = houseSize - 1; randPos >= 0; randPos--)
|
||
if (housePosHeight[randPos] < houseHeight)
|
||
break;
|
||
if (randPos < 0) break;
|
||
}
|
||
textureType[housePosHeight[randPos]++, randPos] = Random.Range(0, houseTypeCount);
|
||
}
|
||
|
||
//清空原来的城市图像
|
||
foreach (UnityEngine.Transform child in _cityBuilding.transform)
|
||
Object.Destroy(child.gameObject);
|
||
|
||
//开始设置城市图像
|
||
for (int x = 0; x < houseEdge; x++)
|
||
for (int y = 0; y < houseEdge; y++)
|
||
for (int z = 0; z < housePosHeight[x * houseEdge + y]; z++)
|
||
{
|
||
int textureIndex = textureType[z, x * houseEdge + y];
|
||
GameObject house = new GameObject($"house{x}_{y}_{z}");
|
||
SpriteRenderer sr = house.AddComponent<SpriteRenderer>();
|
||
//string forcesName = Table.Instance.QueryForcesName(playerData.PlayerForceId);
|
||
//string civName = Table.Instance.QueryCivsName(playerData.PlayerCivId);
|
||
//sr.sprite = TH1Resource.ResourceLoader.Load<Sprite>(
|
||
// $"ArtResources/TH1Buildings/TH1Buildings{forcesName}/{civName}/{forcesName}_{civName}_House_{textureType[z,x*houseEdge +y] + 1}");
|
||
if (Table.Instance.CivDataAssets != null && Table.Instance.CivDataAssets.GetCivInfo(playerData.PlayerCivId, out var civInfo) && civInfo.HouseSpriteList != null && textureIndex >= 0 && civInfo.HouseSpriteList.Count > textureIndex)
|
||
sr.sprite = civInfo.HouseSpriteList[textureIndex];
|
||
house.transform.parent = _cityBuilding.transform;
|
||
Vector3 tpos = _ROGrid.transform.position;
|
||
//每层的层高
|
||
float levelHeight = 1.5f;
|
||
tpos = new Vector3(tpos.x + 1.22f * (x - y),
|
||
tpos.y + 0.7f * (x + y) + z * levelHeight - 7.5f + 0.7f * (4 - houseEdge),
|
||
tpos.z + 0.9f - (30 + z - x - y) * 0.001f);
|
||
house.transform.position = tpos;
|
||
house.transform.localScale = 3.9f * Vector3.one;
|
||
}
|
||
}
|
||
|
||
// 让 cityBuilding 下 house{x}_{y}_{z} 中 z >= h 的 sprite 半透(alpha=0.2),其余恢复 1.0
|
||
public void SetCityBuildingFadeAboveHeight(int h)
|
||
{
|
||
if (_cityBuilding == null) return;
|
||
foreach (Transform child in _cityBuilding.transform)
|
||
{
|
||
if (!TryParseHouseZ(child.name, out int z)) continue;
|
||
var sr = child.GetComponent<SpriteRenderer>();
|
||
if (sr == null) continue;
|
||
var c = sr.color;
|
||
c.a = z >= h ? 0.2f : 1.0f;
|
||
sr.color = c;
|
||
}
|
||
}
|
||
|
||
// 取消半透,cityBuilding 下所有 house 的 alpha 恢复 1.0
|
||
public void ClearCityBuildingFade()
|
||
{
|
||
if (_cityBuilding == null) return;
|
||
foreach (Transform child in _cityBuilding.transform)
|
||
{
|
||
var sr = child.GetComponent<SpriteRenderer>();
|
||
if (sr == null) continue;
|
||
var c = sr.color;
|
||
c.a = 1.0f;
|
||
sr.color = c;
|
||
}
|
||
}
|
||
|
||
// 从 "house{x}_{y}_{z}" 形式的名字解析出 z(最后一段)
|
||
private static bool TryParseHouseZ(string name, out int z)
|
||
{
|
||
z = 0;
|
||
if (string.IsNullOrEmpty(name)) return false;
|
||
int idx = name.LastIndexOf('_');
|
||
if (idx < 0 || idx == name.Length - 1) return false;
|
||
return int.TryParse(name.Substring(idx + 1), out z);
|
||
}
|
||
|
||
public void RenderUpdataHighlight()
|
||
{
|
||
UpdateMoveHighlightSprite();
|
||
_moveHighlight.SetActive(IsMoveHighlight);
|
||
_attackHighlight.SetActive(IsAttackHighlight);
|
||
_selectHighlight.SetActive(IsSelectHighlight);
|
||
UpdateMoveHighlightTypeSlots();
|
||
}
|
||
|
||
private void UpdateMoveHighlightSprite()
|
||
{
|
||
if (_moveHighlightRenderer == null)
|
||
return;
|
||
|
||
if (IsMoveHighlight
|
||
&& IsEnhancedMoveHighlightEnabled()
|
||
&& (MoveHighlightTypes & MoveHighlightType.Enemy) != 0
|
||
&& TryGetMoveHighlightVisual(MoveHighlightType.Enemy, out var enemyVisual)
|
||
&& enemyVisual.Sprite != null)
|
||
{
|
||
_moveHighlightRenderer.sprite = enemyVisual.Sprite;
|
||
_moveHighlightRenderer.color = enemyVisual.Color;
|
||
return;
|
||
}
|
||
|
||
_moveHighlightRenderer.sprite = _defaultMoveHighlightSprite;
|
||
_moveHighlightRenderer.color = _defaultMoveHighlightColor;
|
||
}
|
||
|
||
private void InitMoveHighlightTypeGroup()
|
||
{
|
||
var group = _ROGrid.transform.Find("MoveHighlightTypeGroup")
|
||
?? _ROGrid.transform.Find("MoveHiglightTypeGroup")
|
||
?? _ROGrid.transform.Find("MoveHighlight/MoveHighlightTypeGroup")
|
||
?? _ROGrid.transform.Find("MoveHighlight/MoveHiglightTypeGroup");
|
||
if (group == null)
|
||
return;
|
||
|
||
_moveHighlightTypeGroup = group.gameObject;
|
||
for (int i = 0; i < _moveHighlightTypeSlots.Length; i++)
|
||
{
|
||
int index = i + 1;
|
||
var slot = group.Find($"Position{index}")
|
||
?? group.Find($"Pos{index}")
|
||
?? group.Find(index.ToString());
|
||
if (slot == null && i < group.childCount)
|
||
slot = group.GetChild(i);
|
||
if (slot == null)
|
||
continue;
|
||
|
||
_moveHighlightTypeSlots[i] = slot.gameObject;
|
||
_moveHighlightTypeRenderers[i] = slot.GetComponent<SpriteRenderer>();
|
||
_moveHighlightTypeSlots[i].SetActive(false);
|
||
}
|
||
_moveHighlightTypeGroup.SetActive(false);
|
||
}
|
||
|
||
private void UpdateMoveHighlightTypeSlots()
|
||
{
|
||
if (_moveHighlightTypeGroup == null)
|
||
return;
|
||
|
||
if (!IsMoveHighlight || !IsEnhancedMoveHighlightEnabled() || MoveHighlightTypes == MoveHighlightType.None)
|
||
{
|
||
_moveHighlightTypeGroup.SetActive(false);
|
||
for (int i = 0; i < _moveHighlightTypeSlots.Length; i++)
|
||
if (_moveHighlightTypeSlots[i] != null)
|
||
_moveHighlightTypeSlots[i].SetActive(false);
|
||
return;
|
||
}
|
||
|
||
_moveHighlightTypeGroup.SetActive(true);
|
||
int slotIndex = 0;
|
||
foreach (var type in MoveHighlightDisplayOrder)
|
||
{
|
||
if ((MoveHighlightTypes & type) == 0)
|
||
continue;
|
||
if (slotIndex >= _moveHighlightTypeSlots.Length)
|
||
break;
|
||
|
||
var slot = _moveHighlightTypeSlots[slotIndex];
|
||
var renderer = _moveHighlightTypeRenderers[slotIndex];
|
||
if (slot == null || renderer == null)
|
||
{
|
||
slotIndex++;
|
||
continue;
|
||
}
|
||
|
||
if (!TryGetMoveHighlightVisual(type, out var visual) || visual.Sprite == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
renderer.sprite = visual.Sprite;
|
||
renderer.color = visual.Color;
|
||
slot.SetActive(true);
|
||
slotIndex++;
|
||
}
|
||
|
||
for (int i = slotIndex; i < _moveHighlightTypeSlots.Length; i++)
|
||
if (_moveHighlightTypeSlots[i] != null)
|
||
_moveHighlightTypeSlots[i].SetActive(false);
|
||
}
|
||
|
||
private static bool TryGetMoveHighlightVisual(MoveHighlightType type, out MoveHighlightVisual visual)
|
||
{
|
||
visual = null;
|
||
return ResourceCache.Instance?.SpriteCache?.TryGetMoveHighlightVisual(type, out visual) == true;
|
||
}
|
||
|
||
private static bool IsEnhancedMoveHighlightEnabled()
|
||
{
|
||
return ConfigManager.Instance?.Config?.EnhancedMoveHighlightEnabled ?? true;
|
||
}
|
||
|
||
public void SetSelectHighlight(bool v)
|
||
{
|
||
if (IsSelectHighlight == v)
|
||
return;
|
||
IsSelectHighlight = v;
|
||
MapRenderer.Instance.HighlightGridIdSet.Add(_gridId);
|
||
MapRenderer.Instance.HighlightGridIdSetRenderMark = true;
|
||
}
|
||
|
||
public void SetMoveHighlight(bool v)
|
||
{
|
||
SetMoveHighlight(v, MoveHighlightType.None);
|
||
}
|
||
|
||
public void SetMoveHighlight(bool v, MoveHighlightType types)
|
||
{
|
||
if (v && IsFogForSelfPlayer())
|
||
types = MoveHighlightType.None;
|
||
if (IsMoveHighlight == v && MoveHighlightTypes == types) return;
|
||
IsMoveHighlight = v;
|
||
MoveHighlightTypes = v ? types : MoveHighlightType.None;
|
||
MapRenderer.Instance.HighlightGridIdSet.Add(_gridId);
|
||
MapRenderer.Instance.HighlightGridIdSetRenderMark = true;
|
||
}
|
||
|
||
private bool IsFogForSelfPlayer()
|
||
{
|
||
if (_fog != null && _fog.activeSelf)
|
||
return true;
|
||
|
||
var sight = _mapData?.PlayerMap?.SelfPlayerData?.Sight;
|
||
return sight != null && !sight.CheckIsInSight(_gridId);
|
||
}
|
||
|
||
public void SetAttackHighlight(bool v)
|
||
{
|
||
if (IsAttackHighlight == v) return;
|
||
IsAttackHighlight = v;
|
||
MapRenderer.Instance.HighlightGridIdSet.Add(_gridId);
|
||
MapRenderer.Instance.HighlightGridIdSetRenderMark = true;
|
||
}
|
||
|
||
private void UpdateLand()
|
||
{
|
||
if(_land == null) return;
|
||
var com = _land?.GetComponent<SpriteRenderer>();
|
||
if (com == null) return;
|
||
var oldSprite = com.sprite;
|
||
if (oldSprite == null) return;
|
||
|
||
com.color = _gridData.Player(Main.MapData, out var _) && _gridData.Terrain == TerrainType.Land ? terriColor : Color.white;
|
||
|
||
var newSprite = Table.Instance.GridAndResourceDataAssets.GetTerrainSprite(_gridData);
|
||
|
||
if (_gridData.HasSpType(GridSpType.LeyLine)
|
||
&& !_gridData.HasSpType(GridSpType.RemiliaGrid)
|
||
&& !_gridData.HasSpType(GridSpType.KaguyaGrid))
|
||
{
|
||
var selfPlayer = Main.MapData.PlayerMap.SelfPlayerData;
|
||
if (selfPlayer.CivEnum != CivEnum.Indian)
|
||
newSprite = Table.Instance.GridAndResourceDataAssets.GetDefaultTerrainSprite(_gridData);
|
||
}
|
||
|
||
com.sprite = newSprite;
|
||
//_land.GetComponent<SpriteRenderer>().sprite = Table.Instance.GridAndResourceDataAssets.GetTerrainSprite(_gridData);
|
||
if (oldSprite != newSprite && _gridData.HasSpType(GridSpType.RemiliaGrid))
|
||
{
|
||
PlayVFXInSight(new GridVFXParams(GridVFXType.RedMistCreate));
|
||
}
|
||
|
||
}
|
||
|
||
private void UpdateGridSp()
|
||
{
|
||
if (_gridSp == null)
|
||
return;
|
||
|
||
var renderer = _gridSp.GetComponent<SpriteRenderer>();
|
||
if (renderer == null)
|
||
{
|
||
_gridSp.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
var sprite = Table.Instance.GridAndResourceDataAssets.GetGridSpSprite(_gridData);
|
||
if (renderer.sprite != sprite)
|
||
renderer.sprite = sprite;
|
||
|
||
_gridSp.SetActive(sprite != null);
|
||
}
|
||
|
||
private void UpdateRoad()
|
||
{
|
||
if (_gridData == null || _road == null || _mapData == null) return;
|
||
|
||
//如果当前的feature没有road
|
||
if (_gridData.Feature != TerrainFeature.Road)
|
||
{
|
||
for (int i = 1; i <= 9; i++)
|
||
{
|
||
int dirForHuman = i;
|
||
int dirForComputer = dirForHuman - 1;
|
||
var t = _road.transform.Find($"Road{dirForHuman}");
|
||
if (t != null)
|
||
GameObject.Destroy(t.gameObject);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
//TODO 最好把dir做成enum
|
||
for (int i = 1; i <= 9; i++)
|
||
{
|
||
int dirForHuman = i;
|
||
int dirForComputer = dirForHuman - 1;
|
||
var t = _road.transform.Find($"Road{dirForHuman}");
|
||
if (!_mapData.CheckIfNearByGridRoadCanConnenct(_gridData, dirForComputer))
|
||
{
|
||
if (t != null)
|
||
GameObject.Destroy(t.gameObject);
|
||
continue;
|
||
}
|
||
|
||
if (t == null)
|
||
{
|
||
GameObject road = new GameObject($"Road{dirForHuman}");
|
||
SpriteRenderer sr = road.AddComponent<SpriteRenderer>();
|
||
if(ResourceCache.Instance?.SpriteCache?.Roads?.TryGetValue((_gridData.Terrain == TerrainType.Land ? "Road" : "WaterRoad") + dirForComputer,out var tmpSprite) != null)
|
||
sr.sprite = tmpSprite;
|
||
road.transform.parent = _road.transform;
|
||
road.transform.localPosition = new Vector3(0, 0, 0);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
private void UpdateMountain()
|
||
{
|
||
var renderer = _mountain?.GetComponent<SpriteRenderer>();
|
||
if (!renderer) return;
|
||
renderer.sprite = Table.Instance.GridAndResourceDataAssets?.GetMountainSprite(_gridData);
|
||
}
|
||
|
||
private void UpdateForest()
|
||
{
|
||
var renderer = _forest?.GetComponent<SpriteRenderer>();
|
||
if (!renderer) return;
|
||
renderer.sprite = Table.Instance.GridAndResourceDataAssets?.GetVegetationSprite(_gridData);
|
||
}
|
||
|
||
|
||
private void UpdateResource()
|
||
{
|
||
//TODO 时序问题要处理 开游戏第一帧报错
|
||
if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return;
|
||
//if(!_freeland) forcesName = Table.Instance.QueryForcesName(_playerData.PlayerForceId);
|
||
|
||
bool glow = (!_freeland && _playerData.Id == _mapData.PlayerMap.SelfPlayerData.Id
|
||
&& ((_gridData.Resource == ResourceType.Fruit && _playerData.TechTree.CheckIfHasTechAtom(TechAtom.GainFruit))
|
||
|| (_gridData.Resource == ResourceType.Animal && _playerData.TechTree.CheckIfHasTechAtom(TechAtom.GainAnimal))
|
||
|| (_gridData.Resource == ResourceType.Animal && _playerData.TechTree.CheckIfHasTechAtom(TechAtom.TrainUnitKaguyaFrenchAnimalWarrior))
|
||
|| (_gridData.Resource == ResourceType.Fish && _playerData.TechTree.CheckActionCan(GainFishActionId))
|
||
|| (_gridData.Resource == ResourceType.Crop && _playerData.TechTree.CheckIfHasTechAtom(TechAtom.BuildFarm))
|
||
|| (_gridData.Resource == ResourceType.Metal && _playerData.TechTree.CheckIfHasTechAtom(TechAtom.BuildMine))));
|
||
|
||
|
||
if (_gridData.Resource == ResourceType.Starfish &&
|
||
_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTech(TechType.Navigation))
|
||
glow = true;
|
||
|
||
|
||
bool hasCity = _mapData.GetCityDataByTerritoryGid(_gridId, out var cityData);
|
||
|
||
//处理隐藏没有科技情况下 metal、starfish、crop的情况
|
||
bool skip = false;
|
||
if (_gridData.Resource == ResourceType.Crop)
|
||
if (!_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTech(TechType.Organization) &&
|
||
!_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTech(TechType.Farming) && !_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTech(TechType.RemiliaFarming))
|
||
skip = true;
|
||
if (_gridData.Resource == ResourceType.Metal)
|
||
if (!_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTechAtom(TechAtom.BuildMine) &&
|
||
!_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTechAtom(TechAtom.UnitSkillMOUNTAINMOVE))
|
||
skip = true;
|
||
if (_gridData.Resource == ResourceType.Starfish)
|
||
if (!_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTechAtom(TechAtom.UnitActionGather) &&
|
||
!_mapData.PlayerMap.SelfPlayerData.TechTree.CheckIfHasTechAtom(TechAtom.UnitSkillOCEANMOVE))
|
||
skip = true;
|
||
|
||
|
||
if (skip)
|
||
{
|
||
var renderer = _resource?.GetComponent<SpriteRenderer>();
|
||
if (!renderer) return;
|
||
renderer.sprite = null;
|
||
return;
|
||
}
|
||
|
||
//注意 playerData可能是null 对于中立格子来说
|
||
var resource = Table.Instance.GridAndResourceDataAssets.GetResourceSprite(_gridData.Resource,_playerData,_gridData);
|
||
|
||
//如果是桥梁 处理mirror的情况
|
||
if (_gridData.Resource == ResourceType.Bridge)
|
||
{
|
||
if(_mapData.GridMap.CalcBridgeMirror(_gridData))
|
||
resource = Table.Instance.GridAndResourceDataAssets.GetResourceSprite(_gridData.Resource,_playerData,_gridData,mirror:true);
|
||
}
|
||
|
||
//如果是citycenter并且有城市了,就变为null
|
||
if (_gridData.Resource == ResourceType.CityCenter && hasCity)
|
||
resource = null;
|
||
//如果是奇观,替换为对应奇观
|
||
if (_gridData.Resource == ResourceType.Wonder)
|
||
resource = Table.Instance.GridAndResourceDataAssets.GetWonderSprite(_gridData.Wonder);
|
||
|
||
|
||
var resRenderer = _resource?.GetComponent<SpriteRenderer>();
|
||
if (resRenderer)
|
||
{
|
||
if (resRenderer.sprite != resource) resRenderer.sprite = resource;
|
||
//处理高光效果
|
||
resRenderer.material = glow ? ResourceCache.Instance.MatCache.TH1URPShaders_Sprite_Glow:
|
||
ResourceCache.Instance.MatCache.TH1URPShaders_Default;
|
||
}
|
||
}
|
||
|
||
private void UpdateCityWall()
|
||
{
|
||
if (_cityWall.activeSelf)
|
||
return;
|
||
if (!_mapData.GetCityDataByGid(_gridId, out var cityData))
|
||
return;
|
||
if (!cityData.CityWall)
|
||
return;
|
||
_cityWallMark = true;
|
||
_cityWall.SetActive(true);
|
||
}
|
||
|
||
public void UpdateBorder()
|
||
{
|
||
//如果不是城市领土,不需要生成border
|
||
if (_freeland)
|
||
{
|
||
_borderDownLeft.SetActive(false);
|
||
_borderDownRight.SetActive(false);
|
||
_borderUpLeft.SetActive(false);
|
||
_borderUpRight.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
if (Table.Instance.PlayerDataAssets.GetPlayerInfo(_playerData, out var playerInfo))
|
||
{
|
||
var c = playerInfo.Color;
|
||
//c.a = 0.8f;
|
||
var downLeftRender = _borderDownLeft?.GetComponent<SpriteRenderer>();
|
||
if (downLeftRender) downLeftRender.color = c;
|
||
var downRightRender = _borderDownRight?.GetComponent<SpriteRenderer>();
|
||
if (downRightRender) downRightRender.color = c;
|
||
var upRightRender = _borderUpRight?.GetComponent<SpriteRenderer>();
|
||
if (upRightRender) upRightRender.color = c;
|
||
var upLeftRender = _borderUpLeft?.GetComponent<SpriteRenderer>();
|
||
if (upLeftRender) upLeftRender.color = c;
|
||
}
|
||
|
||
if (_mapData == null || _gridData == null) return;
|
||
_borderDownLeft?.SetActive(!_mapData.CheckIfNearByGridSamePlayer(_gridData,4));
|
||
_borderDownRight?.SetActive(!_mapData.CheckIfNearByGridSamePlayer(_gridData,2));
|
||
_borderUpRight?.SetActive(!_mapData.CheckIfNearByGridSamePlayer(_gridData,6));
|
||
_borderUpLeft?.SetActive(!_mapData.CheckIfNearByGridSamePlayer(_gridData,8));
|
||
}
|
||
|
||
private void UpdateCityBorder()
|
||
{
|
||
//如果没有rendermark 直接return
|
||
if (!_gridData.CityBorderRenderMark)
|
||
{
|
||
_cityBorderDownLeft.SetActive(false);
|
||
_cityBorderDownRight.SetActive(false);
|
||
_cityBorderUpLeft.SetActive(false);
|
||
_cityBorderUpRight.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
if (!_mapData.GetPlayerDataByTerritoryGridId(_gridData.Id, out var player))
|
||
return;
|
||
var color = Color.red;
|
||
if(player.Id == _mapData.PlayerMap.SelfPlayerId)
|
||
color = Color.green;
|
||
var cityBorderDownLeftRender = _cityBorderDownLeft?.GetComponent<SpriteRenderer>();
|
||
if (cityBorderDownLeftRender) cityBorderDownLeftRender.color = color;
|
||
var cityBorderDownRightRender = _cityBorderDownRight?.GetComponent<SpriteRenderer>();
|
||
if (cityBorderDownRightRender) cityBorderDownRightRender.color = color;
|
||
var cityBorderUpRightRender = _cityBorderUpRight?.GetComponent<SpriteRenderer>();
|
||
if (cityBorderUpRightRender) cityBorderUpRightRender.color = color;
|
||
var cityBorderUpLeftRender = _cityBorderUpLeft?.GetComponent<SpriteRenderer>();
|
||
if (cityBorderUpLeftRender) cityBorderUpLeftRender.color = color;
|
||
|
||
_cityBorderDownLeft.SetActive(!_mapData.CheckIfNearByGridSameCity(_gridData,4));
|
||
_cityBorderDownRight.SetActive(!_mapData.CheckIfNearByGridSameCity(_gridData,2));
|
||
_cityBorderUpRight.SetActive(!_mapData.CheckIfNearByGridSameCity(_gridData,6));
|
||
_cityBorderUpLeft.SetActive(!_mapData.CheckIfNearByGridSameCity(_gridData,8));
|
||
}
|
||
|
||
private void UpdateFog()
|
||
{
|
||
if (_mapData?.PlayerMap?.SelfPlayerData?.Sight?.SightGidSet == null || _gridData == null || _fog == null)
|
||
{
|
||
LogSystem.LogError($"GridRenderer.UpdateFog: missing map/sight/grid/fog data, gridId={_gridId}");
|
||
return;
|
||
}
|
||
|
||
bool isFog = !_mapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(_gridData.Id);
|
||
if (_fog.activeSelf != isFog)
|
||
{
|
||
if (isFog)
|
||
{
|
||
_fog.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
PlayVFXInSight(new GridVFXParams(GridVFXType.Fog));
|
||
//ClearHistoryRenderMark();
|
||
if (Timer.Instance == null)
|
||
{
|
||
_fog.SetActive(false);
|
||
}
|
||
else
|
||
{
|
||
Timer.Instance.TimerRegister(this, () =>
|
||
{
|
||
if (_fog == null || _gridData == null) return;
|
||
_fog.SetActive(false);
|
||
if(_gridData.Resource == ResourceType.CityCenter || _gridData.Resource == ResourceType.Treasure)
|
||
PlayVFXInSight(new GridVFXParams(GridVFXType.Treasure));
|
||
},RandomWait,"GridRenderer_UpdateFog");
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
_land?.SetActive(!isFog);
|
||
_gridSp?.SetActive(!isFog && _gridData.HasSpType(GridSpType.HakureiRune));
|
||
_road?.SetActive(!isFog);
|
||
_mountain?.SetActive(!isFog);
|
||
_forest?.SetActive(!isFog);
|
||
_cityWall?.SetActive(!isFog&&_cityWallMark);
|
||
_cityBuilding?.SetActive(!isFog);
|
||
_resource?.SetActive(!isFog);
|
||
if (isFog)
|
||
{
|
||
_borderDownLeft?.SetActive(false);
|
||
_borderDownRight?.SetActive(false);
|
||
_borderUpLeft?.SetActive(false);
|
||
_borderUpRight?.SetActive(false);
|
||
}
|
||
else
|
||
UpdateBorder();
|
||
}
|
||
|
||
private void UpdateGridVFX()
|
||
{
|
||
//目前仅仅处理Fire这一种VFX
|
||
var city = _gridData.CityOnGrid(Main.MapData);
|
||
if (city == null) return;
|
||
GridVFXPlayType playType = GridVFXPlayType.Play;
|
||
_gridData.MainSelfPlayerVisibleUnit(out var unit);
|
||
if(unit == null || unit.Player(Main.MapData) == city.Player(Main.MapData)) playType = GridVFXPlayType.Stop;
|
||
PlayVFXInSight(new GridVFXParams(GridVFXType.Fire),playType);
|
||
}
|
||
|
||
public void SetBounceAnim(bool NeedRandomWait=false, bool isLevelupBounce = false)
|
||
{
|
||
if (!_ROGrid) return;
|
||
if (needBounce) return;
|
||
levelupBounce = isLevelupBounce;
|
||
if(!NeedRandomWait)
|
||
_bounceWaitTime = 0f;
|
||
else
|
||
{
|
||
|
||
_bounceWaitTime = Random.Range(0,0.3f);
|
||
|
||
}
|
||
needBounce = true;
|
||
isBounceDown = true;
|
||
bounceTime = 0f;
|
||
bounceUpPos = _ROGrid.transform.position;
|
||
if(isLevelupBounce)
|
||
bounceDownPos = new Vector3(_ROGrid.transform.position.x, _ROGrid.transform.position.y - 1.5f, _ROGrid.transform.position.z);
|
||
else
|
||
bounceDownPos = new Vector3(_ROGrid.transform.position.x, _ROGrid.transform.position.y - 0.5f, _ROGrid.transform.position.z);
|
||
}
|
||
|
||
public Vector3 GridVector3()
|
||
{
|
||
if (_gridData != null)
|
||
return _gridData.V3();
|
||
return Vector3.zero;
|
||
}
|
||
}
|
||
}
|