using System.Collections.Generic; using System.IO; using TGS; using Unity.Mathematics; using UnityEngine; using NLDPB; using System.Diagnostics; using Gameplay; public class MapHex { public const float Length = 1.73205f; public const float Radius = 1.5f; public int index; public int Nx; public int Nz; public int Ax; public int Ay; public int Az; public float Wx; public float Wz; public int CityID; public int StaticCamp; public int Camp; public bool isChecked; public void SetData( int nWidth, int nHeight, int nIndex ) { //index = Nz * nWidth + Nx index = nIndex; Nz = nIndex/nWidth; Nx = nIndex - Nz *nWidth; Az = Nz; Ax = Nx-Nz/2; Ay = -Ax-Az; Wx = (Nx + Nz * 0.5f - Nz / 2 ) * (Radius*2.0f); Wz = Nz * (Length*1.5f); } public override string ToString() { return $"index={index}, NC=({Nx}, {Nz}), AC=({Ax}, {Ay}, {Az}), WC=({Wx}, 0, {Wz}), City ID={CityID}"; } public bool IsMyNext(MapHex hex) { int xOffset = math.abs(hex.Ax- Ax); int zOffset = math.abs(hex.Az-Az); int yOffset = math.abs(hex.Ay-Ay); return xOffset <= 1 && zOffset <= 1 && yOffset <= 1; } public bool IsMe(MapHex hex) { return hex.Nx == Nx && hex.Nz == Nz; } public int Distance(MapHex hex) { int xOffset = math.abs(hex.Ax- Ax); int zOffset = math.abs(hex.Az-Az); int yOffset = math.abs(hex.Ay-Ay); return math.max(yOffset, math.max(xOffset, zOffset)); } public bool CanPass(int startCityID, int endCityID) { if(CityID > 0) { return CityID == startCityID || CityID == endCityID; } else { return true; } } public bool IsCampSource() { return Camp == (int)BattlefieldActorCamp.CampAsource || Camp == (int)BattlefieldActorCamp.CampBsource; } public int GetRealCamp() { switch (Camp) { case (int)BattlefieldActorCamp.CampAsource: return (int)BattlefieldActorCamp.CampA; case (int)BattlefieldActorCamp.CampBsource: return (int)BattlefieldActorCamp.CampB; default: return Camp; } } public bool IsRealCamp() { switch(Camp) { case (int)BattlefieldActorCamp.CampAsource: case (int)BattlefieldActorCamp.CampBsource: case (int)BattlefieldActorCamp.CampA: case (int)BattlefieldActorCamp.CampB: return true; } return false; } } public class PathNode { public MapHex hex; public HexDir dir; //public List childs; public PathNode parent; public CityRoad cr; public int crIndex; public bool goRight; public PathNode() { //childs = new List(); } } public class CityRoad { public MapHex center; public MapHex [] road; public int Cover; public void GetNextHex(MapHex hex, out MapHex left, out int leftIndex, out MapHex right, out int rightIndex) { int index = -1; for(int i = 0; i < road.Length; i ++) { if(road[i].IsMe(hex)) { index = i; break; } } if(index == -1) { UnityEngine.Debug.LogError($"CityRoad GetNextHex not found index, hex={hex}"); left = null; right = null; leftIndex = 0; rightIndex = 0; return; } leftIndex = index -1; if(leftIndex < 0) leftIndex = road.Length - 1; rightIndex = index +1; if(rightIndex >= road.Length) rightIndex = 0; left = road[leftIndex]; right = road[rightIndex]; //UnityEngine.Debug.Log($"GetNextHex 1 rsult, index={index}, leftIndex={leftIndex}, rightIndex={rightIndex}"); //UnityEngine.Debug.Log($"hex={hex}"); //UnityEngine.Debug.Log($"left={left}"); //UnityEngine.Debug.Log($"right={right}"); } public void GetNextHex(int index, bool goRight, out MapHex next, out int nextIndex) { if(goRight) { index ++; if(index >= road.Length) index = 0; } else { index --; if(index < 0) index = road.Length - 1; } nextIndex = index; next = road[index]; //UnityEngine.Debug.Log($"GetNextHex 2 index={index}, goRight={goRight}, nextIndex={nextIndex}"); //UnityEngine.Debug.Log($"next={next}"); } } public enum HexDir { None = 0, RightUp, RightDown, LeftUp, LeftDown, Right, Left, UpRL, DownRL, } public class MapArea { public bool hasSource; public List hexes; public MapArea() { hexes = new List(); } public void Reverse() { for (int i = 0; i < hexes.Count; i ++) { var h = hexes[i]; if (h.Camp == (int)BattlefieldActorCamp.CampA) { h.Camp = (int)BattlefieldActorCamp.CampB; } else if (h.Camp == (int)BattlefieldActorCamp.CampB) { h.Camp = (int)BattlefieldActorCamp.CampA; } } } } public class MapGo { public int Camp; public GameObject go; } public class MapActor { public MapPathfind m_mp; public MapHex m_Current; public int m_Camp; public float m_Speed; bool IsMoving; GameObject go; List m_path; int pathIndex; public void Init(MapPathfind m, MapHex hex, int camp, float speed) { m_mp = m; m_Current = hex; m_Camp = camp; m_Speed = speed; go = GameObject.CreatePrimitive(PrimitiveType.Capsule); go.transform.position = new Vector3(m_Current.Wx, 0, m_Current.Wz); go.transform.localScale = new Vector3(2, 1, 2); m_mp.SetRoundCamp(false, hex, m_Camp, 3); } public void SetMove() { m_path = m_mp.DoFind2(this); if(m_path != null) { pathIndex = m_path.Count-1; IsMoving = true; } } public void Update() { if(IsMoving) { var curPos = go.transform.position; var target = new Vector3(m_path[pathIndex].Wx, 0, m_path[pathIndex].Wz); var moveDis = m_Speed * Time.deltaTime; var disCheck = Vector3.Distance(curPos, target); if(moveDis > disCheck) { var nextHex = m_path[pathIndex]; UnityEngine.Debug.Log($"m_Current.CityID={m_Current.CityID}, next City id={nextHex.CityID}"); if(m_Current.CityID > 0 && nextHex.CityID <= 0) { // 离开城了 UnityEngine.Debug.Log("离开城了,m_Current.CityID=" +m_Current.CityID); var cr = m_mp.GetCityRoad(m_Current.CityID); m_mp.SetRoundCamp(true, cr.center, (int)BattlefieldActorCamp.BacNone, cr.Cover); } else if (m_Current.CityID <= 0 && nextHex.CityID > 0) { UnityEngine.Debug.Log("进入城了,m_Current.CityID=" +m_Current.CityID); var cr = m_mp.GetCityRoad(nextHex.CityID); m_mp.SetRoundCamp(true, cr.center, m_Camp, cr.Cover); } m_Current = nextHex; m_mp.SetRoundCamp(false, m_Current, m_Camp, 3); go.transform.position = target; pathIndex --; if(pathIndex < 0) { IsMoving = false; } } else { var dir = target - curPos; dir.Normalize(); go.transform.position = curPos + dir * moveDis; } } } } public class MapPathfind : MonoBehaviour { public TerrainGridSystem TGS; MapData m_mapData; public bool Reload; public MapHex [] m_hexes; public MapGo [] m_hexCamps; // width x轴 // height z轴 public int ANx; public int ANz; public bool AMove; public int BNx; public int BNz; public bool BMove; public bool FindPath; MapHex m_Start; MapHex m_End; Dictionary m_Roads; public GameObject PathGo; public GameObject RoundGo; public GameObject CityGo; public GameObject StartGo; public GameObject EndGo; PathNode m_EndNode; public HashSet m_CloseList; public bool DestroyPath; List BornPosA; List BornPosB; public GameObject Blue; public GameObject BlueSource; public GameObject BlueBuilding; public GameObject Red; public GameObject RedSource; public GameObject RedBuilding; public Transform CampRoot; MapActor A; MapActor B; void Start() { Reload = true; // 19,3 0,15 } void CreateMap() { m_Roads = new Dictionary(); string jsonPath = Application.dataPath + "/Editor/MapPath/MapData_MapsTest.json"; string txt = File.ReadAllText(jsonPath); m_mapData = JsonUtility.FromJson(txt); UnityEngine.Debug.Log($"width={m_mapData.Width}, height={m_mapData.Height}, data length={m_mapData.BlocksData.Count}"); m_hexes = new MapHex[m_mapData.BlocksData.Count]; for(int i = 0; i < m_mapData.BlocksData.Count; i ++) { MapHex hex = new MapHex(); hex.SetData(m_mapData.Width, m_mapData.Height, i); m_hexes[i] = hex; //UnityEngine.Debug.Log(hex.ToString()); } AddCity(1, 5, 4, 1, 3 ); //AddCity(2, 12, 21, 1 ); //AddCity(3, 4, 19, 1 ); //AddCity(4, 16, 19, 1 ); //AddCity(5, 14, 18, 1 ); //AddCity(6, 12, 17, 1 ); //AddCity(7, 4, 16, 1 ); //AddCity(8, 2, 15, 1 ); //AddCity(9, 14, 13, 1, 3 ); //AddCity(10, 6, 12, 1 ); //AddCity(11, 15, 11, 1 ); //AddCity(12, 9, 10, 1 ); //AddCity(13, 9, 6, 1, 2 ); AddCity(14, 15, 6, 2, 4 ); //AddCity(15, 16, 16, 2 ); //AddCity(16, 3, 11, 2 ); AddCity(17, 14, 24, 2, 4 ); AddCity(18, 9, 15, 3, 5 ); m_hexCamps = new MapGo[m_hexes.Length]; for(int i = 0; i < m_hexes.Length; i ++) { m_hexCamps[i] = new MapGo(); } BornPosA = new List { m_hexes[GetIndex(0, 0)], m_hexes[GetIndex(1, 0)], m_hexes[GetIndex(0, 1)] }; BornPosB = new List { m_hexes[GetIndex(19, 29)], m_hexes[GetIndex(18, 29)], m_hexes[GetIndex(19, 28)] }; } public void AddCity(int nCityID, int Nx, int Nz, int range, int cover ) { MapHex center = m_hexes[GetIndex(Nx, Nz)]; // 找最外一圈路径 List RoundRoad = new List(); // 获取建筑所在的格子 int MaxX = center.Ax + range; int MinX = center.Ax - range; int MaxY = center.Ay + range; int MinY = center.Ay - range; int MaxZ = center.Az + range; int MinZ = center.Az - range; for(int x = MinX; x <= MaxX; x ++) { for(int y = MinY; y <= MaxY; y ++) { int z = -x-y; if(z >= MinZ && z <= MaxZ) { MapHex hex = GetMapHex(x, y, z); if(x == MinX || x == MaxX || y == MinY || y == MaxY || z == MinZ || z == MaxZ) { RoundRoad.Add(hex); } else { hex.CityID = nCityID; //UnityEngine.Debug.Log(hex.ToString()); var go = Instantiate(CityGo); go.transform.SetParent(transform); go.transform.position = new Vector3(hex.Wx, 0, hex.Wz); } } } } int RoadNodeCount = RoundRoad.Count; List rounds = new List(); MapHex next = RoundRoad[0]; rounds.Add(next); RoundRoad.RemoveAt(0); while(RoundRoad.Count > 0) { MapHex nextHex = null; for(int i = 0; i < RoundRoad.Count; i ++) { if(next.IsMyNext(RoundRoad[i])) { next = RoundRoad[i]; RoundRoad.RemoveAt(i); rounds.Add(next); nextHex = next; break; } } if(nextHex == null) { UnityEngine.Debug.LogError("nextHex not found ..."); break; } } for(int i = 0; i < rounds.Count; i ++) { UnityEngine.Debug.Log($"find next, city={nCityID}, count={rounds.Count}, current={rounds[i]}"); } if(rounds.Count == RoadNodeCount) { CityRoad cr = new CityRoad(); cr.center = center; cr.road = rounds.ToArray(); cr.Cover = cover; m_Roads.Add(nCityID, cr); /* for(int i = 0; i < cr.road.Length; i ++) { var go = Instantiate(RoundGo); go.transform.SetParent(transform); go.transform.position = new Vector3(cr.road[i].Wx, 0, cr.road[i].Wz); } //*/ } else { UnityEngine.Debug.LogError($"Road create error, city={nCityID}, rounds.Count:{rounds.Count} != RoadNodeCount:{RoadNodeCount}"); } /* UnityEngine.Debug.Log("Road Start ========================= count=" +rounds.Count); for(int i = 0; i < rounds.Count; i ++) { UnityEngine.Debug.Log(rounds[i]); } UnityEngine.Debug.Log("Road End ========================="); */ } int GetIndex(int Nx, int Nz) { return Nz*m_mapData.Width+Nx; } void clearChecked() { for(int i = 0; i < m_hexes.Length; i ++) { m_hexes[i].isChecked = false; } } void Update() { if(Reload) { Reload = false; CreateMap(); InitRange(BornPosA, BornPosB); A = new MapActor(); A.Init(this, BornPosA[0], (int)BattlefieldActorCamp.CampA, 3.0f); B = new MapActor(); B.Init(this, BornPosB[0], (int)BattlefieldActorCamp.CampB, 3.0f); } // if(FindPath) // { // Stopwatch stopwatch = new Stopwatch(); // stopwatch.Start(); // DoFind2(); // stopwatch.Stop(); // FindPath = false; // UnityEngine.Debug.Log($"DoFind2 执行时间: {stopwatch.ElapsedMilliseconds} 毫秒"); // } if(DestroyPath) { DestroyPath = false; //删除本节点下所有的GameObect while (transform.childCount > 0) { DestroyImmediate(transform.GetChild(0).gameObject); } } if(A != null) { if(AMove) { AMove = false; A.SetMove(); } A.Update(); } if(B != null) { if(BMove) { BMove = false; B.SetMove(); } B.Update(); } CheckRange(BornPosA[0]); for(int i = 0; i < m_hexes.Length; i ++) { if(m_hexCamps[i].Camp != m_hexes[i].Camp) { if(m_hexCamps[i].go != null) { GameObject.Destroy(m_hexCamps[i].go); m_hexCamps[i].go = null; } m_hexCamps[i].Camp = m_hexes[i].Camp; switch(m_hexCamps[i].Camp) { case (int)BattlefieldActorCamp.CampA: { m_hexCamps[i].go = GameObject.Instantiate(Blue); } break; case (int)BattlefieldActorCamp.CampAsource: { m_hexCamps[i].go = GameObject.Instantiate(BlueSource); } break; case (int)BattlefieldActorCamp.CampAbuilding: { m_hexCamps[i].go = GameObject.Instantiate(BlueBuilding); } break; case (int)BattlefieldActorCamp.CampB: { m_hexCamps[i].go = GameObject.Instantiate(Red); } break; case (int)BattlefieldActorCamp.CampBsource: { m_hexCamps[i].go = GameObject.Instantiate(RedSource); } break; case (int)BattlefieldActorCamp.CampBbuilding: { m_hexCamps[i].go = GameObject.Instantiate(RedBuilding); } break; } if(m_hexCamps[i].go != null) { m_hexCamps[i].go.transform.SetParent(CampRoot); m_hexCamps[i].go.transform.position = new Vector3(m_hexes[i].Wx, 0, m_hexes[i].Wz); } } } } HexDir GetTargetPositionDir(MapHex start, MapHex end) { var dir = GetLineDir(start, end); if(dir != HexDir.None) return dir; if(end.Az > start.Az) { if(end.Ax < start.Ax && end.Ay < start.Ay) { return HexDir.UpRL; } else if(end.Ay > start.Ay) { return HexDir.LeftUp; } else { return HexDir.RightUp; } } else { if(end.Ax > start.Ax && end.Ay > start.Ay) { return HexDir.DownRL; } else if(end.Ax < start.Ax) { return HexDir.LeftDown; } else { return HexDir.RightDown; } } } HexDir GetLineDir(MapHex start, MapHex end) { if(start.Ax == end.Ax) { if(end.Az > start.Az) { return HexDir.RightUp; } else { return HexDir.LeftDown; } } else if( start.Az == end.Az) { if(end.Ax > start.Ax) { return HexDir.Right; } else { return HexDir.Left; } } else if( start.Ay == end.Ay) { if(end.Az > start.Az) { return HexDir.LeftUp; } else { return HexDir.RightDown; } } return HexDir.None; } void AddPathNode(PathNode node, PathNode parent) { node.parent = parent; } bool GetNextNode(PathNode currentNode, List openList, int startCityID, int endCityID) { var dir = currentNode.dir; var nextHex = GetNextHex(currentNode.hex, dir); if(nextHex != null) { // 下一格是建筑,那当前这一格,肯定就在路点上 if(!nextHex.CanPass(startCityID, endCityID)) { // 如果当前格没有路点信息,则找左右两个路点作为下一格 if(currentNode.cr == null) { m_Roads.TryGetValue(nextHex.CityID, out CityRoad cr); if(cr == null) { UnityEngine.Debug.LogError("City road not found, city id=" + nextHex.CityID); return false; } cr.GetNextHex(currentNode.hex, out MapHex left, out int leftIndex, out MapHex right, out int rightIndex); if(!m_CloseList.TryGetValue(left.index, out int hexIndex)) { PathNode nodeLeft = new PathNode(); nodeLeft.hex = left; nodeLeft.dir = GetTargetPositionDir(left, m_End); nodeLeft.cr = cr; nodeLeft.crIndex = leftIndex; nodeLeft.goRight = false; //nodeLeft.parent = currentNode; AddPathNode(nodeLeft, currentNode); if(m_End.IsMe(left)) { m_EndNode = nodeLeft; return true; } openList.Add(nodeLeft); } if(!m_CloseList.TryGetValue(right.index, out int hexIndex2)) { PathNode nodeRight = new PathNode(); nodeRight.hex = right; nodeRight.dir = GetTargetPositionDir(right, m_End); nodeRight.cr = cr; nodeRight.crIndex = rightIndex; nodeRight.goRight = true; //nodeRight.parent = currentNode; AddPathNode(nodeRight, currentNode); if(m_End.IsMe(right)) { m_EndNode = nodeRight; return true; } openList.Add(nodeRight); } } else // 当前格本身就在路点上,则找下一格路点 { currentNode.cr.GetNextHex(currentNode.crIndex, currentNode.goRight, out MapHex next, out int nextIndex); if(!m_CloseList.TryGetValue(next.index, out int hexIndex2)) { PathNode nodeNext = new PathNode(); nodeNext.hex = next; nodeNext.cr = currentNode.cr; nodeNext.dir = GetTargetPositionDir(next, m_End); nodeNext.goRight = currentNode.goRight; nodeNext.crIndex = nextIndex; //nodeNext.parent = currentNode; AddPathNode(nodeNext, currentNode); if(m_End.IsMe(next)) { m_EndNode = nodeNext; return true; } openList.Add(nodeNext); } } } else { PathNode nextNode = new PathNode(); nextNode.hex = nextHex; nextNode.dir = dir; var dirNext = GetLineDir(nextHex, m_End); if(dirNext != HexDir.None) { nextNode.dir = dirNext; } nextNode.parent = currentNode; AddPathNode(nextNode, currentNode); if(m_End.IsMe(nextHex)) { m_EndNode = nextNode; return true; } openList.Add(nextNode); } } return false; } public List DoFind2(MapActor actor) { m_EndNode = null; m_CloseList = new HashSet(); m_Start = actor.m_Current; var StartCityID = m_Start.CityID; if(actor.m_Camp == (int)BattlefieldActorCamp.CampA) { if(m_Start.Nx == ANx && m_Start.Nz == ANz) { return null; } m_End = m_hexes[GetIndex(ANx, ANz)]; } else { if(m_Start.Nx == BNx && m_Start.Nz == BNz) { return null; } m_End = m_hexes[GetIndex(BNx, BNz)]; } // var EndCityID = m_End.CityID; StartGo.transform.position = new Vector3(m_Start.Wx, 0, m_Start.Wz); EndGo.transform.position = new Vector3(m_End.Wx, 0, m_End.Wz); List openList = new List(); PathNode path = new PathNode(); path.hex = m_Start; path.dir = GetTargetPositionDir(m_Start, m_End); openList.Add(path); List hexList = new List(); while(openList.Count > 0) { //UnityEngine.Debug.Log("START ============================================== openList.Count=" + openList.Count); List newOpenList = new List(); for(int i = 0; i < openList.Count; i ++) { hexList.Clear(); var node = openList[i]; m_CloseList.Add(node.hex.index); //UnityEngine.Debug.Log($"node.dir={node.dir}, node={node.hex}"); switch(node.dir) { case HexDir.DownRL: { node.dir = HexDir.LeftDown; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("LeftDown go end"); goto End; } node.dir = HexDir.RightDown; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("RightDown go end"); goto End; } } break; case HexDir.UpRL: { node.dir = HexDir.LeftUp; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("LeftUp go end"); goto End; } node.dir = HexDir.RightUp; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("RightUp go end"); goto End; } } break; //* case HexDir.LeftUp: { node.dir = HexDir.Left; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("LeftUp HexDir.Left go end"); goto End; } node.dir = HexDir.LeftUp; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("HexDir.LeftUp go end"); goto End; } } break; case HexDir.LeftDown: { node.dir = HexDir.Left; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("LeftDown HexDir.Left go end"); goto End; } node.dir = HexDir.LeftDown; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("HexDir.LeftDown go end"); goto End; } } break; case HexDir.RightUp: { node.dir = HexDir.Right; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("RightUp HexDir.Right go end"); goto End; } node.dir = HexDir.RightUp; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("HexDir.RightUp go end"); goto End; } } break; case HexDir.RightDown: { node.dir = HexDir.Right; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("RightDown HexDir.Right go end"); goto End; } node.dir = HexDir.RightDown; if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("HexDir.RightDown go end"); goto End; } } break; //*/ default: { if(GetNextNode(node, newOpenList, StartCityID, EndCityID)) { UnityEngine.Debug.Log("default go end"); goto End; } } break; } } openList.Clear(); openList.AddRange(newOpenList); //UnityEngine.Debug.Log("NEXT ============================================== openList.Count=" + openList.Count); } End: /* PathNode pathNode2 = m_EndNode; while(pathNode2.parent != null) { PathNode check = pathNode2.parent; while(check.parent != null) { var dir = GetLineDir(pathNode2.hex, check.hex); if(dir != HexDir.None) { List list = new List(); MapHex hex = pathNode2.hex; while(true) { MapHex nextHex = GetNextHex(hex, dir); if(nextHex.CityID <= 0) { if(nextHex.IsMe(check.hex)) { break; } list.Add(nextHex); hex = nextHex; } else { list.Clear(); break; } } if(list.Count > 0) { PathNode newAdd = pathNode2; while(list.Count > 0) { PathNode newNext = new PathNode(); newNext.hex = list[0]; newAdd.parent = newNext; newAdd = newNext; list.RemoveAt(0); } newAdd.parent = check; } } check = check.parent; } pathNode2 = pathNode2.parent; } //*/ List result = new List(); int nCount = 0; PathNode pathNode = m_EndNode; while(pathNode.parent != null) { UnityEngine.Debug.Log(pathNode.hex); result.Add(pathNode.hex); //var go = Instantiate(PathGo); //go.transform.SetParent(transform); //go.transform.position = new Vector3(pathNode.hex.Wx, 0, pathNode.hex.Wz); nCount ++; pathNode = pathNode.parent; } UnityEngine.Debug.Log("all path node count="+ nCount); return result; } MapHex GetMapHex(int Ax, int Ay, int Az) { int Nz = Az; int Nx = Ax+Az/2; //UnityEngine.Debug.Log($"GetMapHex Ax={Ax}, Ay={Ay}, Az={Az}, Nx={Nx}, Nz={Nz}"); if(Nx < 0 || Nx > m_mapData.Width-1) { //UnityEngine.Debug.LogError($"GetMapHex 1 not found Nx={Nx}, Nz={Nz}"); return null; } if(Nz < 0 || Nz > m_mapData.Height-1) { //UnityEngine.Debug.LogError($"GetMapHex 2 not found Nx={Nx}, Nz={Nz}"); return null; } int index = GetIndex(Nx, Nz); return m_hexes[index]; } public CityRoad GetCityRoad(int cityID) { if(m_Roads.TryGetValue(cityID, out CityRoad v)) { return v; } return null; } /* */ MapHex GetNextHex(MapHex hex, HexDir dir) { switch(dir) { case HexDir.RightUp: { //往右上走,Ax不变,Az+1 int NextAx = hex.Ax; int NextAz = hex.Az+1; int NextAy = -NextAx-NextAz; return GetMapHex(NextAx, NextAy, NextAz); } case HexDir.RightDown: { // 往右下走,Ay不变,Az-1 int NextAz = hex.Az-1; int NextAy = hex.Ay; int NextAx = -NextAz-NextAy; return GetMapHex(NextAx, NextAy, NextAz); } case HexDir.LeftUp: { //往左上走,Ay不变,Az+1 int NextAy = hex.Ay; int NextAz = hex.Az+1; int NextAx = -NextAz-NextAy; return GetMapHex(NextAx, NextAy, NextAz); } case HexDir.LeftDown: { //往左下走,Ax不变,Az-1 int NextAx = hex.Ax; int NextAz = hex.Az-1; int NextAy = -NextAx-NextAz; return GetMapHex(NextAx, NextAy, NextAz); } case HexDir.Right: { //往右走,Az不变,Ay-1 int NextAz = hex.Az; int NextAy = hex.Ay-1; int NextAx = -NextAz-NextAy; return GetMapHex(NextAx, NextAy, NextAz); } case HexDir.Left: { //往左走,Az不变,Ay+1 int NextAz = hex.Az; int NextAy = hex.Ay+1; int NextAx = -NextAz-NextAy; return GetMapHex(NextAx, NextAy, NextAz); } default: UnityEngine.Debug.LogError("GetNextHex invalid dir, dir=" + dir); return null; } } // 获取指定阵营的空格子 List GetRoundEmptyHex(MapHex center) { List result = new List(); int MaxX = center.Ax + 1; int MinX = center.Ax - 1; int MaxY = center.Ay + 1; int MinY = center.Ay - 1; int MaxZ = center.Az + 1; int MinZ = center.Az - 1; ; for (int x = MinX; x <= MaxX; x++) { for (int y = MinY; y <= MaxY; y++) { int z = -x - y; if (z >= MinZ && z <= MaxZ) { var hex = GetMapHex(x, y, z); if (hex != null && hex != center && hex.CityID == 0 && !hex.isChecked) { hex.isChecked = true; result.Add(hex); } } } } return result; } public void SetRoundCamp(bool isBuilding, MapHex center, int camp , int length ) { length--; int MaxX = center.Ax + length; int MinX = center.Ax - length; int MaxY = center.Ay + length; int MinY = center.Ay - length; int MaxZ = center.Az + length; int MinZ = center.Az - length; for (int x = MinX; x <= MaxX; x++ ) { for (int y = MinY; y <= MaxY; y++) { int z = -x - y; if (z >= MinZ && z <= MaxZ) { var hex = GetMapHex(x, y, z); if (hex != null) { if (isBuilding) { if(camp == (int)BattlefieldActorCamp.CampA) { hex.Camp = (int)BattlefieldActorCamp.CampAbuilding; } else if(camp == (int)BattlefieldActorCamp.CampB) { hex.Camp = (int)BattlefieldActorCamp.CampBbuilding; } else if (camp == (int)BattlefieldActorCamp.BacNone) { if(hex.CityID <= 0) { hex.Camp = hex.StaticCamp; } else { hex.Camp = camp; } } else { hex.Camp = camp; } } else { if (hex.CityID == 0 && hex.Camp < (int)BattlefieldActorCamp.CampMax) { // 如果不是设置建筑范围,则周围有建筑范围,不能更新 hex.Camp = camp; } } } } } } } // 获取周围相同阵营,并且没有检查过的格子 List GetRoundUnchecked(MapHex center) { List result = new List(); int MaxX = center.Ax + 1; int MinX = center.Ax - 1; int MaxY = center.Ay + 1; int MinY = center.Ay - 1; int MaxZ = center.Az + 1; int MinZ = center.Az - 1; for (int x = MinX; x <= MaxX; x++) { for (int y = MinY; y <= MaxY; y++) { int z = -x - y; if (z >= MinZ && z <= MaxZ) { var hex = GetMapHex(x, y, z); if( hex != null && !hex.isChecked && hex.CityID == 0 && hex.GetRealCamp() == center.GetRealCamp() ){ hex.isChecked = true; result.Add(hex); } } } } return result; } // 获取任意一个未检查过的格子 MapHex GetNextUnchecked() { for(int i = 0; i < m_hexes.Length; i ++) { var h = m_hexes[i]; if (!h.isChecked && h.CityID == 0 && h.IsRealCamp() ) { h.isChecked = true; return h; } } return null; } void CheckRange(MapHex start) { clearChecked(); List areas = new List(); var nextHex = start; while(nextHex != null) { var area = new MapArea(); areas.Add(area); int checkIndex = 0; List checkList = new List(); checkList.Add(nextHex); while(checkIndex < checkList.Count) { var current = checkList[checkIndex]; current.isChecked = true; checkIndex++; area.hexes.Add(current); if (current.IsCampSource()) { area.hasSource = true; } var result = GetRoundUnchecked(current); if (result.Count > 0 ){ checkList.AddRange(result); } } nextHex = GetNextUnchecked(); } for (int i = 0; i < areas.Count; i ++) { if (!areas[i].hasSource ){ areas[i].Reverse(); } } } // 采用膨胀算法初始化势力范围 void InitRange( List BornPosA, List BornPosB) { clearChecked(); int checkIndexA = 0; List checkListA = new List(); checkListA.AddRange(BornPosA); for (int i = 0; i < checkListA.Count; i ++) { checkListA[i].isChecked = true; checkListA[i].Camp = (int)BattlefieldActorCamp.CampAsource; } int checkIndexB = 0; List checkListB = new List(); checkListB.AddRange(BornPosB); for (int i = 0; i < checkListB.Count; i ++) { checkListB[i].isChecked = true; checkListB[i].Camp = (int)BattlefieldActorCamp.CampBsource; } bool working = true; while(working) { working = false; if (checkIndexA < checkListA.Count) { var current = checkListA[checkIndexA]; current.isChecked = true; if (current.Camp == (int)BattlefieldActorCamp.BacNone) { current.Camp = (int)BattlefieldActorCamp.CampA; // 设置格子所属势力 current.StaticCamp = (int)BattlefieldActorCamp.CampA; } var result = GetRoundEmptyHex(current); // 只获取周围没有阵营的空格子 if (result.Count > 0) { checkListA.AddRange(result); } checkIndexA++; if (checkIndexA < checkListA.Count) { working = true; } } if (checkIndexB < checkListB.Count) { var current = checkListB[checkIndexB]; current.isChecked = true; if (current.Camp == (int)BattlefieldActorCamp.BacNone) { current.Camp = (int)BattlefieldActorCamp.CampB; // 设置格子所属势力 current.StaticCamp = (int)BattlefieldActorCamp.CampB; } var result = GetRoundEmptyHex(current); // 只获取周围没有阵营的空格子 if (result.Count > 0) { checkListB.AddRange(result); } checkIndexB++; if (checkIndexB < checkListB.Count) { working = true; } } } } }