692 lines
25 KiB
C#
692 lines
25 KiB
C#
/*
|
||
* @Author: 白哉
|
||
* @Description:
|
||
* @Date: 2025年04月03日 星期四 11:04:31
|
||
* @Modify:
|
||
*/
|
||
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using MemoryPack;
|
||
using TH1_Logic.Core;
|
||
using TH1Renderer;
|
||
using UnityEngine;
|
||
using UnityEngine.Animations;
|
||
|
||
|
||
namespace RuntimeData
|
||
{
|
||
[MemoryPackable]
|
||
public partial class GridMapData
|
||
{
|
||
public List<GridData> GridList;
|
||
|
||
private Dictionary<uint, GridData> _posToGridDict;
|
||
private Dictionary<uint, GridData> _gridIdToGridDict;
|
||
private MapConfig _mapCfg;
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
public GridMapData()
|
||
{
|
||
GridList = new List<GridData>();
|
||
_posToGridDict = new Dictionary<uint, GridData>();
|
||
_gridIdToGridDict = new Dictionary<uint, GridData>();
|
||
}
|
||
|
||
public GridMapData(MapConfig mapCfg, MapIdGenerator idGenerator)
|
||
{
|
||
_mapCfg = mapCfg;
|
||
GridList = new List<GridData>();
|
||
_posToGridDict = new Dictionary<uint, GridData>();
|
||
_gridIdToGridDict = new Dictionary<uint, GridData>();
|
||
|
||
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<GridData>();
|
||
_posToGridDict = new Dictionary<uint, GridData>();
|
||
_gridIdToGridDict = new Dictionary<uint, GridData>();
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
[MemoryPackOnDeserialized]
|
||
public void OnAfterMemoryPackDeserialize()
|
||
{
|
||
_posToGridDict ??= new Dictionary<uint, GridData>();
|
||
_gridIdToGridDict ??= new Dictionary<uint, GridData>();
|
||
_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<GridData> GetAroundGridData(int xOffset, int yOffset, GridData gridData)
|
||
{
|
||
List<GridData> gridDataList = new List<GridData>();
|
||
int radius = Mathf.Max(xOffset, yOffset);
|
||
//从内圈到外圈按顺序将格子加入list
|
||
for (int r = 0; r <= radius; r++)
|
||
{
|
||
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 (Mathf.Max(Mathf.Abs(x - gridData.Pos.X) , Mathf.Abs(y - gridData.Pos.Y)) != r) continue;
|
||
gridDataList.Add(aroundGridData);
|
||
}
|
||
}
|
||
}
|
||
|
||
return gridDataList;
|
||
}
|
||
|
||
// 获取目标周围的所有格子
|
||
public HashSet<GridData> GetAroundGridDataSet(int xOffset, int yOffset, GridData gridData)
|
||
{
|
||
HashSet<GridData> gridDataSet = new HashSet<GridData>();
|
||
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<GridData> GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData)
|
||
{
|
||
List<GridData> gridDataList = new List<GridData>();
|
||
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<uint> GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false)
|
||
{
|
||
List<uint> gridIdList = new List<uint>();
|
||
//从内圈到外圈按顺序将格子加入list
|
||
for (int r = 0; r <= radius; r++)
|
||
{
|
||
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 (Mathf.Max(Mathf.Abs(x - gridData.Pos.X) , Mathf.Abs(y - gridData.Pos.Y)) != r) 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 int CalcManhattanDistance(GridData gridDataA, GridData gridDataB)
|
||
{
|
||
return Mathf.Abs(gridDataA.Pos.X - gridDataB.Pos.X) + Mathf.Abs(gridDataA.Pos.Y - gridDataB.Pos.Y);
|
||
}
|
||
|
||
public void RefreshConnectInfo()
|
||
{
|
||
|
||
}
|
||
|
||
public bool CalcBridgeMirror(GridData gridData)
|
||
{
|
||
var x = gridData.Pos.X;
|
||
var y = gridData.Pos.Y;
|
||
if (!GetGridDataByPos(x, y - 1, out var grid1)) return true;
|
||
if (!GetGridDataByPos(x, y + 1, out var grid2)) return true;
|
||
if (grid1.Terrain != TerrainType.Land) return true;
|
||
if (grid2.Terrain != TerrainType.Land) return true;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public enum GridSpType { None,RemiliaGrid,KaguyaGrid,Max }
|
||
|
||
// 每个格子包含5个层次的信息
|
||
[MemoryPackable]
|
||
public partial 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 List<GridSpType> SpTypeList;
|
||
|
||
public bool[] WaterRoadForceId;
|
||
// 文明层
|
||
public uint CivId;
|
||
//奇观Id
|
||
|
||
//建筑level-只对部分建筑生效
|
||
public int buildingLevel;
|
||
|
||
//海军基底提供的每回合恢复次数
|
||
public int NavalBasePoint;
|
||
//建筑的建立时间,目前只对temple有效
|
||
public uint BuildTime;
|
||
|
||
//通用冷却cd参数,kaguyaFrenchAnimal吸引动物、EgyptianIrrigation生成农田,都会操纵这个参数 //建筑的kaguyaFrenchAnimal吸引量,每回合+1,>=2则可以在周围找个树林吸引一个动物,然后置0
|
||
public uint CommonColdTime;
|
||
//-------- RenderData ---------//
|
||
|
||
//cityborder相关的RenderMark
|
||
[MemoryPackIgnore]
|
||
public bool CityBorderRenderMark = false;
|
||
|
||
|
||
[MemoryPackConstructor]
|
||
public GridData()
|
||
{
|
||
SpTypeList = new List<GridSpType>();
|
||
}
|
||
|
||
public GridData(int x, int y,MapIdGenerator mapIdGenerator,MapConfig mapConfig)
|
||
{
|
||
SpTypeList = new List<GridSpType>();
|
||
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());
|
||
//拷贝Grid的SpTypeList
|
||
SpTypeList = new List<GridSpType>();
|
||
SpTypeList.Clear();
|
||
foreach (var SpType in copyData.SpTypeList) SpTypeList.Add(SpType);
|
||
}
|
||
|
||
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);
|
||
|
||
//拷贝Grid的SpTypeList
|
||
SpTypeList ??= new List<GridSpType>();
|
||
SpTypeList.Clear();
|
||
foreach (var SpType in copyData.SpTypeList) SpTypeList.Add(SpType);
|
||
|
||
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 Vector3 V3() => Table.Instance.GridToWorld(this,"");
|
||
|
||
public bool IsMainMap()
|
||
{
|
||
if (!Main.MapData.GridMap.GetGridDataByGid(Id, out var gridData)
|
||
|| gridData != this)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
public bool InMainSight()
|
||
{
|
||
if (!IsMainMap()) return false;
|
||
return Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(Id);
|
||
}
|
||
|
||
//返回该格子周围是否存在没有视野的格子
|
||
public bool UnsightNearby(MapData map, PlayerData player)
|
||
{
|
||
var gridList = map.GridMap.GetAroundGridData(1, 1, this);
|
||
foreach (var grid in gridList)
|
||
{
|
||
if (player.Sight.CheckIsInSight(grid.Id)) return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 全局通知调用
|
||
public void OnTurnStart(MapData map)
|
||
{
|
||
//Step #1 处理海军点 TODO 将来要并入skill去
|
||
NavalBasePoint = 1;
|
||
//Step #2 处理kaguyaFrenchAnimal(必须是该grid玩家的回合)
|
||
if (Resource == ResourceType.KaguyaFrenchYard && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id))
|
||
{
|
||
CommonColdTime++;
|
||
if (CommonColdTime >= 2)
|
||
{
|
||
var gridList = map.GridMap.GetAroundGridData(1, 1, this);
|
||
|
||
if (map.GetPlayerDataByTerritoryGridId(Id, out var player))
|
||
foreach (var grid in gridList)
|
||
{
|
||
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue;
|
||
if (gridPlayer.Id != player.Id) continue;
|
||
if (grid.Vegetation != Vegetation.Trees) continue;
|
||
if (grid.Resource != ResourceType.None) continue;
|
||
|
||
grid.Resource = ResourceType.Animal;
|
||
grid.Renderer(map)?.InstantUpdateGrid(true);
|
||
|
||
grid.Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Treasure));
|
||
CommonColdTime = 0;
|
||
|
||
Main.CityLogic.UpdateGridBuildingData(map,this);
|
||
Renderer(map)?.InstantUpdateGrid(true);
|
||
Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//Step #3 处理EgyptianIrrigation(必须是该grid玩家的回合)
|
||
if (Resource == ResourceType.EgyptianIrrigation && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id))
|
||
{
|
||
CommonColdTime++;
|
||
if (CommonColdTime >= 2)
|
||
{
|
||
var gridList = map.GridMap.GetAroundGridData(1, 1, this);
|
||
|
||
if (map.GetPlayerDataByTerritoryGridId(Id, out var player))
|
||
foreach (var grid in gridList)
|
||
{
|
||
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue;
|
||
if (gridPlayer.Id != player.Id) continue;
|
||
if (grid.Terrain != TerrainType.Land) continue;
|
||
if (grid.Vegetation == Vegetation.Trees) continue;
|
||
if (grid.Feature == TerrainFeature.Mountain) continue;
|
||
if (grid.Resource != ResourceType.None) continue;
|
||
|
||
grid.Resource = ResourceType.Crop;
|
||
grid.Renderer(map)?.InstantUpdateGrid(true);
|
||
|
||
grid.Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Treasure));
|
||
CommonColdTime = 0;
|
||
|
||
//Main.CityLogic.UpdateGridBuildingData(map,this);
|
||
//Renderer(map)?.SetUpdateGrid(true);
|
||
//Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//Step #3 处理所有技能
|
||
for (int i = Skills.Count - 1; i >= 0; i--)
|
||
{
|
||
var skill = Skills[i];
|
||
if (skill.IsFinished())
|
||
{
|
||
Skills.RemoveAt(i);
|
||
continue;
|
||
}
|
||
skill.OnTurnStart(this, map);
|
||
}
|
||
|
||
}
|
||
|
||
public void OnTurnEnd(MapData map)
|
||
{
|
||
foreach (var skill in Skills) skill.OnTurnEnd(this, map);
|
||
}
|
||
|
||
//皮肤层的一些基础属性调用
|
||
public bool HasSpType(GridSpType type)
|
||
{
|
||
foreach(var t in SpTypeList)
|
||
if (t == type)
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
public bool RemoveSpType(GridSpType type,MapData map)
|
||
{
|
||
foreach(var t in SpTypeList)
|
||
if (t == type)
|
||
{
|
||
SpTypeList.Remove(t);
|
||
if (type == GridSpType.RemiliaGrid && Unit(map, out var unit))
|
||
{
|
||
unit.RemoveSkill(SkillType.ScarletMistRealTimeVampire,map);
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
public bool AddSpType(GridSpType type,MapData map, UnitData origin)// = null)
|
||
{
|
||
if (HasSpType(type)) return false;
|
||
if (type == GridSpType.RemiliaGrid)
|
||
{
|
||
if(Resource == ResourceType.CityCenter) return false;
|
||
if (Terrain != TerrainType.Land) return false;
|
||
}
|
||
SpTypeList.Add(type);
|
||
origin?.HeroTask(map)?.OnAddSpType(map, type);
|
||
//如果是remiliaGrid,给当前的unit填加skill
|
||
if (type == GridSpType.RemiliaGrid && Unit(map,out var unit))
|
||
{
|
||
unit.AddSkill(SkillType.ScarletMistRealTimeVampire);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public UnitData Unit(MapData map)
|
||
{
|
||
map.GetUnitDataByGid(Id, out var unit);
|
||
return unit;
|
||
}
|
||
|
||
public bool Unit(MapData map,out UnitData unit)
|
||
{
|
||
return map.GetUnitDataByGid(Id, out unit);
|
||
}
|
||
|
||
public CityData City(MapData map)
|
||
{
|
||
map.GetCityDataByTerritoryGid(Id, out var city);
|
||
return city;
|
||
}
|
||
|
||
public bool City(MapData map ,out CityData city)
|
||
{
|
||
return map.GetCityDataByTerritoryGid(Id, out city);
|
||
}
|
||
|
||
public CityData CityOnGrid(MapData map)
|
||
{
|
||
map.GetCityDataByGid(Id, out var city);
|
||
return city;
|
||
}
|
||
|
||
public bool CityOnGrid(MapData map,out CityData city)
|
||
{
|
||
return map.GetCityDataByGid(Id, out city);
|
||
}
|
||
|
||
//返回当前grid提供了多少的cityExp
|
||
public int CityExp()
|
||
{
|
||
if (!Table.Instance.GridAndResourceDataAssets.GetResourceInfo(Resource, out var resourceInfo))
|
||
return 0;
|
||
if (resourceInfo.HasLevel)
|
||
return resourceInfo.CityExpPerLevel * buildingLevel;
|
||
return resourceInfo.Exp;
|
||
}
|
||
|
||
public GridRenderer Renderer(MapData map)
|
||
{
|
||
if (map != Main.MapData) return null;
|
||
MapRenderer.Instance.ROGridMap.TryGetValue(Id, out var renderer);
|
||
return renderer;
|
||
}
|
||
|
||
public PlayerData Player(MapData map)
|
||
{
|
||
map.GetPlayerDataByTerritoryGridId(Id, out var player);
|
||
return player;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// 位置基类
|
||
[MemoryPackable]
|
||
public partial class MapPosition
|
||
{
|
||
public int X;
|
||
public int Y;
|
||
public uint PosId => CalculatePosId(X, Y);
|
||
|
||
public Vector2Int V2() => new Vector2Int(X, Y);
|
||
public static uint CalculatePosId(int x, int y)
|
||
{
|
||
return (uint)(x * 1000 + y);
|
||
}
|
||
|
||
[MemoryPackConstructor]
|
||
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;
|
||
}
|
||
|
||
// 重载 GetHashCode
|
||
public override int GetHashCode()
|
||
{
|
||
return HashCode.Combine(X, Y);
|
||
// 或者更简单的方式:
|
||
// return X.GetHashCode() ^ Y.GetHashCode();
|
||
}
|
||
// 重载 Equals(object)
|
||
public override bool Equals(object obj)
|
||
{
|
||
return obj is MapPosition other && Equals(other);
|
||
}
|
||
// 实现 IEquatable<MapPosition>
|
||
public bool Equals(MapPosition other)
|
||
{
|
||
if (other == null) return false;
|
||
return X == other.X && Y == other.Y;
|
||
}
|
||
// 重载 == 操作符(推荐)
|
||
public static bool operator ==(MapPosition left, MapPosition right)
|
||
{
|
||
if (ReferenceEquals(left, right)) return true;
|
||
if (left is null || right is null) return false;
|
||
return left.Equals(right);
|
||
}
|
||
// 重载 != 操作符(推荐)
|
||
public static bool operator !=(MapPosition left, MapPosition right)
|
||
{
|
||
return !(left == right);
|
||
}
|
||
|
||
}
|
||
|
||
} |