/* * @Author: 白哉 * @Description: * @Date: 2025年04月03日 星期四 11:04:31 * @Modify: */ using System; using System.Collections.Generic; using Logic; using TH1Renderer; using UnityEngine; namespace RuntimeData { [Serializable] public class GridMapData : ISerializationCallbackReceiver { public List GridList; private Dictionary _posToGridDict; private Dictionary _gridIdToGridDict; private MapConfig _mapCfg; public GridMapData() { GridList = new List(); _posToGridDict = new Dictionary(); _gridIdToGridDict = new Dictionary(); } public GridMapData(MapConfig mapCfg, MapIdGenerator idGenerator) { _mapCfg = mapCfg; GridList = new List(); _posToGridDict = new Dictionary(); _gridIdToGridDict = new Dictionary(); for (int x = 0; x < mapCfg.Width; x++) { for (int y = 0; y < mapCfg.Height; y++) { var gridData = new GridData(x, y, idGenerator,mapCfg); GridList.Add(gridData); _gridIdToGridDict[gridData.Id] = gridData; _posToGridDict[gridData.Pos.PosId] = gridData; } } } public GridMapData(GridMapData copyData) { _mapCfg = copyData._mapCfg; GridList = new List(); _posToGridDict = new Dictionary(); _gridIdToGridDict = new Dictionary(); foreach (var grid in copyData.GridList) { var gridData = new GridData(grid); GridList.Add(gridData); _gridIdToGridDict[gridData.Id] = gridData; _posToGridDict[gridData.Pos.PosId] = gridData; } } public void DeepCopy(GridMapData copyData) { _mapCfg = copyData._mapCfg; _posToGridDict.Clear(); _gridIdToGridDict.Clear(); for (int i = 0; i < copyData.GridList.Count; i++) { var copyGrid = copyData.GridList[i]; if (i >= GridList.Count) { var gridData = new GridData(copyGrid); GridList.Add(gridData); _gridIdToGridDict[gridData.Id] = gridData; _posToGridDict[gridData.Pos.PosId] = gridData; } else { GridList[i].DeepCopy(copyGrid); _gridIdToGridDict[GridList[i].Id] = GridList[i]; _posToGridDict[GridList[i].Pos.PosId] = GridList[i]; } } for (int i = GridList.Count - 1; i >= copyData.GridList.Count; i--) { _gridIdToGridDict.Remove(GridList[i].Id); _posToGridDict.Remove(GridList[i].Pos.PosId); GridList.RemoveAt(i); } } public void OnBeforeSerialize() { } public void OnAfterDeserialize() { _posToGridDict ??= new Dictionary(); _gridIdToGridDict ??= new Dictionary(); _posToGridDict.Clear(); _gridIdToGridDict.Clear(); foreach (var grid in GridList) { _gridIdToGridDict[grid.Id] = grid; _posToGridDict[grid.Pos.PosId] = grid; } } public void BindMapConfig(MapConfig cfg) { _mapCfg = cfg; } public void OnTurnStart(MapData map) { foreach (var grid in GridList) grid.OnTurnStart(map); } public void OnTurnEnd(MapData map) { foreach (var grid in GridList) grid.OnTurnEnd(map); } // 通过 gid 获取格子数据 public bool GetGridDataByGid(uint gid, out GridData data) { return _gridIdToGridDict.TryGetValue(gid, out data); } // 通过坐标获取格子数据 public bool GetGridDataByPos(int x, int y, out GridData gridData) { return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(x, y), out gridData); } public bool GetGridDataByVector3Pos(Vector3 pos, out GridData gridData) { var p = Table.Instance.WorldToGrid(pos); return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(p.x, p.y), out gridData); } // 获取目标周围的所有格子 public List GetAroundGridData(int xOffset, int yOffset, GridData gridData) { List gridDataList = new List(); for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++) { for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++) { if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; gridDataList.Add(aroundGridData); } } return gridDataList; } // 获取目标周围的所有格子 public HashSet GetAroundGridDataSet(int xOffset, int yOffset, GridData gridData) { HashSet gridDataSet = new HashSet(); for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++) { for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++) { if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (x == gridData.Pos.X && y == gridData.Pos.Y) continue; gridDataSet.Add(aroundGridData); } } return gridDataSet; } // 获取目标周围的所有格子,但是按照优先2468方向,返回有序的List public List GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData) { List gridDataList = new List(); for (int i = 1; i <= 9; i++) { //下方的公式使得遍历顺序是 2468 13579 也就是优先bfs上下左右,再考虑斜的方向 int dirForHuman = (i <= 4) ? (2 * i) : (2 * (i - 5) + 1); int dirForComputer = dirForHuman - 1; int x = gridData.Pos.X + dirForComputer % 3 - 1; int y = gridData.Pos.Y + dirForComputer / 3 - 1; if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (x == gridData.Pos.X && y == gridData.Pos.Y) continue; gridDataList.Add(aroundGridData); } return gridDataList; } public List GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false) { List gridIdList = new List(); for (int x = gridData.Pos.X - radius; x <= gridData.Pos.X + radius; x++) { for (int y = gridData.Pos.Y - radius; y <= gridData.Pos.Y + radius; y++) { if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (!remainCenter && x == gridData.Pos.X && y == gridData.Pos.Y) continue; gridIdList.Add(aroundGridData.Id); } } return gridIdList; } // 获取周围某个格子 public bool GetUpGridData(GridData gridData, int xOffset, int yOffset, out GridData upGridData) { return GetGridDataByPos(gridData.Pos.X + xOffset, gridData.Pos.Y + yOffset, out upGridData); } // 判断是否在左右边界 public bool IsInLeftOrRightBorder(GridData gridData) { return gridData.Pos.X == 0 || gridData.Pos.X == _mapCfg.Width - 1; } // 判断是否在上下边界 public bool IsInUpOrDownBorder(GridData gridData) { return gridData.Pos.Y == 0 || gridData.Pos.Y == _mapCfg.Height - 1; } //-------- 计算类方法 --------// public int CalcDistance(GridData gridDataA, GridData gridDataB) { return Mathf.Max(Mathf.Abs(gridDataA.Pos.X - gridDataB.Pos.X),Mathf.Abs(gridDataA.Pos.Y - gridDataB.Pos.Y)); } public void RefreshConnectInfo() { } } public class GridVFXRenderMark { //1play 0stop public GridVFXType Type; public bool PlayOrStop; public bool RenderMark; public uint CivId; public int Damage; public GridVFXRenderMark(GridVFXType gridVFXType,bool renderMark = true, bool playOrStop = true) { Type = gridVFXType; RenderMark = renderMark; PlayOrStop = playOrStop; } public void CopyFrom(GridVFXRenderMark other) { if (other == null) return; Type = other.Type; PlayOrStop = other.PlayOrStop; RenderMark = other.RenderMark; CivId = other.CivId; Damage = other.Damage; } } // 每个格子包含5个层次的信息 [Serializable] public class GridData : IdentifierBase { //-------- BaseData ---------// // 位置信息 public MapPosition Pos; public bool CityBuildingRenderMark = false; // 海陆层 public TerrainType Terrain; // 地形层 public TerrainFeature Feature; // 植被层 public Vegetation Vegetation; // 资源层+建筑层 public ResourceType Resource; public WonderLibrary Wonder; public ResourceType ResourceUnderBuilding; public bool[] WaterRoadForceId; // 文明层 public uint CivId; //奇观Id //建筑level-只对部分建筑生效 public int buildingLevel; //建筑的建立时间,目前只对temple有效 public uint BuildTime; //-------- RenderData ---------// //gridVFX相关的RenderMark public bool VFXRenderMarkHurt = false; public bool VFXRenderMarkDie = false; public bool VFXRenderMarkDieHintStart = false; public int VFXRenderMarkDieHintStartParam = 0; public bool VFXRenderMarkDieHintEnd = false; public bool VFXRenderMarkTreasure = false; public bool VFXRenderMarkHeal = false; public bool VFXRenderMarkFlag = false; public uint VFXRenderMarkFlagCivId = 0; public bool VFXRenderMarkFog = false; public bool VFXRenderMark = false; public Dictionary RenderMarkVFXDict; //cityborder相关的RenderMark public bool CityBorderRenderMark = false; //所有gridData的特效走这个函数 //用来设置vfxRenderMark, 单独做成一个方法,是为了避免dict值为空的情况 public void SetGridVFXRenderMark(GridVFXRenderMark tmp) { if (RenderMarkVFXDict == null || !RenderMarkVFXDict.TryGetValue(tmp.Type, out var target)) { InitRenderMark(); if (!RenderMarkVFXDict.TryGetValue(tmp.Type, out target)) return; } target.CopyFrom(tmp); } public void InitRenderMark() { RenderMarkVFXDict = new Dictionary(); foreach(GridVFXType type in Enum.GetValues(typeof(GridVFXType))) RenderMarkVFXDict[type] = new GridVFXRenderMark(type,false); } public GridData(int x, int y,MapIdGenerator mapIdGenerator,MapConfig mapConfig) { Pos = new MapPosition(x,y); Id = mapIdGenerator.GeneratorId(); WaterRoadForceId = new bool[Table.Instance.MaxForceCount]; } //仅用于AI计算data,不需要render的部分 public GridData(GridData copyData) { Pos = new MapPosition(copyData.Pos.X, copyData.Pos.Y); Id = copyData.Id; Terrain = copyData.Terrain; Feature = copyData.Feature; Vegetation = copyData.Vegetation; Resource = copyData.Resource; ResourceUnderBuilding = copyData.ResourceUnderBuilding; CivId = copyData.CivId; Wonder = copyData.Wonder; buildingLevel = copyData.buildingLevel; WaterRoadForceId = new bool[copyData.WaterRoadForceId.Length]; Array.Copy(copyData.WaterRoadForceId, WaterRoadForceId, copyData.WaterRoadForceId.Length); foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill()); } public void DeepCopy(GridData copyData) { Pos.X = copyData.Pos.X; Pos.Y = copyData.Pos.Y; Id = copyData.Id; Terrain = copyData.Terrain; Feature = copyData.Feature; Vegetation = copyData.Vegetation; Resource = copyData.Resource; ResourceUnderBuilding = copyData.ResourceUnderBuilding; CivId = copyData.CivId; Wonder = copyData.Wonder; buildingLevel = copyData.buildingLevel; WaterRoadForceId = new bool[copyData.WaterRoadForceId.Length]; Array.Copy(copyData.WaterRoadForceId, WaterRoadForceId, copyData.WaterRoadForceId.Length); foreach (var skill in copyData.Skills) { AddSkill(skill.GetSkillType()); if (!GetSkill(skill.GetSkillType(), out var selfSkill)) continue; selfSkill.DeepCopy(skill); } for (int i = Skills.Count - 1; i >= 0; i--) { if (copyData.GetSkill(Skills[i].GetSkillType(), out _)) continue; Skills.RemoveAt(i); } } public void SetGridData(TerrainType ter,TerrainFeature fea,Vegetation veg, ResourceType res,uint civ) { Terrain = ter; Feature = fea; Vegetation = veg; Resource = res; ResourceUnderBuilding = ResourceType.None; CivId = civ; } public bool IsRoadBridgePort() { return Feature == TerrainFeature.Road || Resource == ResourceType.Port || Resource == ResourceType.Bridge; } // 全局通知调用 public void OnTurnStart(MapData map) { for (int i = Skills.Count - 1; i >= 0; i--) { var skill = Skills[i]; if (skill.IsFinished()) { Skills.RemoveAt(i); continue; } skill.OnTurnStart(this, map); } //TODO 不应该写在这里,应该由CityLogic处理或者PlayerLogic处理,反正应该在Logic模块,StartNextTurn那个函数处理 //处理神庙升级的模块 if (map.GetPlayerDataByTerritoryGridId(Id, out var player) && (Resource == ResourceType.Temple || Resource == ResourceType.WaterTemple || Resource == ResourceType.ForestTemple || Resource == ResourceType.MountainTemple) ) { int newLevel = (int)(player.Turn - BuildTime) / 2 + 1; if (newLevel > 5) newLevel = 5; if (newLevel != buildingLevel) { int delta = newLevel - buildingLevel; buildingLevel = newLevel; RenderMark = true; VFXRenderMarkFog = true; if (delta > 0) { var main = GameObject.Find("Main").GetComponent
(); //如果既是非AI的真实mapdata,又是玩家的各自 if (Main.MapData == map && player.Id == map.PlayerMap.SelfPlayerId) { var faithPanel = GameObject.Find("UICanvas/TopBarPanel/FaithPanel/Icon").transform; var startPos = Table.Instance.GridToWorld(this); var endPos = faithPanel.position; MapRenderer.Instance.ProjectileManager.CreateProjectile(startPos,endPos,ProjectileType.Faith,ProjectileMoveType.CoinParabola,delta * 50); } } } } } public void OnTurnEnd(MapData map) { foreach (var skill in Skills) skill.OnTurnEnd(this, map); } } // 位置基类 [Serializable] public class MapPosition { public int X; public int Y; public uint PosId => CalculatePosId(X, Y); public static uint CalculatePosId(int x, int y) { return (uint)(x * 1000 + y); } public MapPosition() { X = 0; Y = 0; } public MapPosition(int x,int y) { X = x; Y = y; } public void SetPosition(MapPosition pos) { X = pos.X; Y = pos.Y; } } }