/// <summary> /// A much slower GetRadius function, but more accurate. It uses collision box projectsions to determine blocked edges that break /// connections to neighboring hex cells, even if those cells exist. This is useful for finding valid paths through impassible game objects. /// ValidNeighbors is used as the main pathfinding function /// </summary> /// <param name="cell">Center AICell</param> /// <param name="searchHeight">How high (up or down) does the algorithm search for neighbors? -1 is unbounded</param> /// <returns></returns> public PathCell[] ValidNeighbors(PathCell cell, int searchHeight = 1) { //Get neighbors normally PathCell[] neighbors = (PathCell[])pathGrid.GetRadius(cell.q, cell.r, cell.h, 1, searchHeight); List <PathCell> returnNeighbors = new List <PathCell>(); //Loop through all possible neighbors foreach (PathCell n in neighbors) { //If the neighbor has a unit, don't bother checking if it is a valid move if (n.hasEnemy) { continue; } //Get the vector that points to the edge of the hex in the direction of the neighbor Vector3 toEdge = (n.centerPos - cell.centerPos) / 2; //Create a rotation for the collider box (so it is orientated along the edge) Quaternion rotation = new Quaternion(); rotation.SetLookRotation(toEdge.normalized, new Vector3(0, 1, 0)); //Get the collider center position (in between the cells, 1 unit up) Vector3 colliderPos = toEdge + cell.centerPos + new Vector3(0, 1, 0); //Check the location for physics collisions (if it collides with the middle third of the edge) if (!Physics.CheckBox(colliderPos, new Vector3(HexConst.radius / 6f, 0.5f, 0.1f), rotation)) { //If it is a valid location, add this to the list. returnNeighbors.Add(n); } } return(returnNeighbors.ToArray()); }
public PathCell(int x, int z, int dist, PathCell previousCell) { X = x; Z = z; Dist = dist; PreviousCell = previousCell; }
//Summons the particles for the explosion, sets center tile extra crispy, and starts killing monsters. IEnumerator StartExplosion() { Debug.Log("explosion start"); PathCell targetedCell = aiController[parentTile.q, parentTile.r, parentTile.h]; foreach (Monster m in aiController.monsters) { PathCell monsterLoc = aiController.pathGrid[m.CurrentCell[0], m.CurrentCell[1], m.CurrentCell[2]]; if (aiController.DistBetween(targetedCell, monsterLoc) <= 0) { m.gameObject.GetComponent <MonsterStats>().Health -= 50; } else if (aiController.DistBetween(targetedCell, monsterLoc) <= 1) //if we aren't in the immediate vicinity of the monsters, but they're in range of the fireball explosion... { markedMonsters.Add(m.gameObject.GetComponent <MonsterStats>()); //add the monster stats to the "you're already dead" list } } parentTile.gameObject.GetComponent <Renderer>().material = this.burntTileMaterial; fireball.SetActive(false); explosion.SetActive(true); ParticleSystem explosionParticles = explosion.GetComponent <ParticleSystem>(); explosionParticles.Play(); yield return(new WaitForSeconds(explosionStartTime)); Debug.Log("end explosion start"); StartCoroutine(FinishExplosion()); }
/// <summary> /// Recursively travel up the 'parent' chain and construct a list of integer coordinates that form a path. /// </summary> /// <param name="endCell">End of path</param> /// <param name="startCell">Start of path</param> /// <returns>A list of integer axial coordinate arrays that form a path</returns> private List <int[]> ReconstructPath(PathCell endCell, PathCell startCell) { //Create the return list List <int[]> returnList = new List <int[]>(); //If the end cell is the same as the start cell, return an empty list (no path) if (endCell.Equals(startCell)) { return(returnList); } //Create a temporary cell PathCell temp = endCell; do { //Add temp to the return list returnList.Add(new int[] { temp.q, temp.r, temp.h }); //Set temp to it's parent temp = temp.parent; //repeat //Loop while temp has not been set to the start cell } while (!temp.Equals(startCell)); //Finally, add the start cell to the list and return the path returnList.Add(new int[] { startCell.q, startCell.r, startCell.h }); return(returnList); }
List <int> MakePath(int _size) { List <int> Path = new List <int>(); size = _size; // PathCells = 미니게임이 이루어질 배열의 데이터화 PathCells = new PathCell[size * size]; PathCell tmp; for (int i = 0; i < PathCells.Length; i++) { tmp = new PathCell(i, false, true); PathCells[i] = tmp; } PathCells[0].IsRoad = true; // 길 만들기 반복 수행 // 가장 최근 만들어진 길에서, 다음 길이 될 Cell에 대한 판별 수행 int nowIDX = 0; while (nowIDX != size * size - 1) { nowIDX = SetDir(nowIDX); Path.Add(nowIDX); } return(Path); }
public void OnInstantiate(PathCell pathToStart) { _pathA = pathToStart; transform.position = _pathA.transform.position; _pathB = pathToStart.parentPath.GetNextPathCell(_pathA); _canMove = true; }
/// <summary> /// 单机模式玩家向指定格子移动 /// </summary> /// <param name="NowStandCell"></param> void StandMoveAnim(PathCell NowStandCell) { Debug.Log("玩家剩余步数:" + EpheMeralActor.StandDiceCount); if (NowStand.m_PlayerList.Contains(GetComponent <Player>())) //安全判断 { NowStand.m_PlayerList.Remove(GetComponent <Player>()); //先移除当前路径本玩家 } if (NowStandCell != null) { NowStand = NowStandCell; GetComponent <ImageOverturn>().FlipHorizontal = NowStand.Xturn; transform.DOLocalJump(NowStandCell.rect.anchoredPosition3D, MoveJump, 1, MoveSpeed); if (NowStand == StarPos)//如果是被打回到初始位置,则不需要添加停留位置 { return; } if (EpheMeralActor.StandDiceCount < 1) { if (StandEMagicAllCell()) { return; } NowStand.m_PlayerList.Add(GetComponent <Player>());//新停留位置添加此元素 NowStand.NowStandAll(); SceneGameController.Instance.UIGameControl.StandTakeToMove(); } } }
/// <summary> /// Get the distance between 2 cells (in hex cells) /// Basically, how many cells are needed to traverse from p1 to p2 /// NOTE: Does not account for height differences /// </summary> /// <param name="cell1">Start cell</param> /// <param name="cell2">End cell</param> /// <returns>Integer cell distance</returns> public int DistBetween(PathCell cell1, PathCell cell2) { //Convert the axial coordinates to cube coordinates for both cells int[] ac = HexConst.AxialToCube(cell1.q, cell1.r, cell1.h); int[] bc = HexConst.AxialToCube(cell2.q, cell2.r, cell2.h); //Calculate the cell distance return(((int)Mathf.Abs(ac[0] - bc[0]) + (int)Mathf.Abs(ac[1] - bc[1]) + (int)Mathf.Abs(ac[2] - bc[2])) / 2); }
public void DrawCellBase(PathCell cell, Rectangle rectangle) { if (cell.Path != null && cell.Path.IsValid) { spriteBatch.Draw(parent.BlankTexture, rectangle, Color.Blue); } rectangle.Inflate(-CellSize / 8, -CellSize / 8); spriteBatch.Draw(parent.BlankTexture, rectangle, cell.Color.ToXnaColor()); }
private void ResetPressedCellType() { ResetGrid(); GridCell cell = GetCellOnMouse(); PathCell pathCell = cell.GetComponent <PathCell>(); pathfindController.SetCellType(pathCell, PathCell.CellType.Empty); gridSavingController.SaveCell(pathCell); }
public void ServerMoveAnim(PathCell NowStandCell) { NowStand = NowStandCell; if (NowStand != null) { Vector3 dirMove = NowStand.rect.anchoredPosition3D; transform.DOLocalJump(dirMove, MoveJump, 1, MoveSpeed); } }
private void ChangeTarget() { _pathA = _pathB; _pathB = _pathA.parentPath.GetNextPathCell(_pathA); if (_pathB == null) { GotToFinishLine(); } }
public PinnedCharacterPosition(CharacterComponent cc) { Character = cc; Cell = cc.GetCell(); _originalX = Cell.X; _originalY = Cell.Y; _originalPosition = cc.transform.position; }
private void AddOpenCell(PathCell cell, PathCell previousCell) { int localGValue = CalculateHValue(previousCell, cell) > HValueMultiplier ? GValueFar : GValueNear; cell.gValue = previousCell.gValue + localGValue; cell.hValue = CalculateHValue(cell, endCell); cell.previousCell = previousCell; openCells.Add(cell); }
private PathCell getCellFromScreenPosition(Vector2 screenposition) { Vector2 gridLocation = camera.ToWorldLocation(screenposition); int x = (int)(gridLocation.X / (float)CellSize); int y = (int)(gridLocation.Y / (float)CellSize); PathCell cell = GetCell(x, y); return(cell); }
private void UpdateOpenCell(PathCell cell, PathCell previousCell) { int localGValue = CalculateHValue(previousCell, cell) > HValueMultiplier ? GValueFar : GValueNear; int totalNewGValue = previousCell.gValue + localGValue; if (cell.gValue > totalNewGValue) { cell.gValue = totalNewGValue; cell.previousCell = previousCell; } }
public void DrawLastCellIncompletePath(PathCell cell, Rectangle rect, string pathValue, CellColor color) { Vector2 cellCenter = new Vector2(rect.Center.X, rect.Center.Y); int size = CellSize / 4; Rectangle smallRect = new Rectangle((int)cellCenter.X - size, (int)cellCenter.Y - size, 2 * size, 2 * size); spriteBatch.Draw(parent.BlankTexture, smallRect, Color.LightSalmon); spriteBatch.DrawString(parent.Font, pathValue, cellCenter - (parent.Font.MeasureString(pathValue) / 2), Color.Black); }
public void Pathfind() { if (startCell == null) { Debug.LogError("Start cell is not specified"); return; } if (endCell == null) { Debug.LogError("End cell is not specified"); return; } ResetGrid(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); openCells.Add(startCell); bool pathFound = false; while (openCells.Count > 0) { PathCell currentCell = GetLowestValueCell(openCells); if (currentCell == endCell) { UpdateFoundPathCells(); pathFound = true; break; } openCells.Remove(currentCell); closedCells.Add(currentCell); ProcessNeighbors(currentCell); } stopwatch.Stop(); if (pathFound) { Debug.Log("Path found"); } else { Debug.Log("Path not found"); } Debug.Log("Elapsed time: " + stopwatch.Elapsed); }
/// <summary> /// AI逻辑,给定点数,求出最终位置 /// </summary> public PathCell AIMoveSetPosition() { PathCell cell = NowStand; for (int i = 0; i < EpheMeralActor.StandDiceCount; i++) { if (cell.NextCell != null) { cell = cell.NextCell; } } return(cell); }
public void SaveCell(PathCell cell) { string cellPrefKey = cell.x + " " + cell.y; if (cell.Type == PathCell.CellType.Empty) { PlayerPrefs.DeleteKey(cellPrefKey); } else { PlayerPrefs.SetInt(cellPrefKey, (int)cell.Type); } }
public static List <int> PathFind(Maze maze, int startCell, int targetCell, int maxLength) { Dictionary <int, int> cellDistances = new Dictionary <int, int>(); Dictionary <int, int> previousCells = new Dictionary <int, int>(); cellDistances.Add(startCell, 0); List <PathCell> toCheck = new List <PathCell>(); PathCell startPathCell = new PathCell(); startPathCell.cell = startCell; startPathCell.distance = 0; toCheck.Add(startPathCell); int closestCell = startCell; int iterationCount = 0; while (toCheck.Count > 0 && toCheck[0].distance <= maxLength) { iterationCount++; PathCell pathCell = toCheck[0]; toCheck.RemoveAt(0); for (int dir = 0; dir < 4; dir++) { int nextCell = Grid.GetNeighbourCell(maze, pathCell.cell, dir); Cell cell = new Cell(pathCell.cell % maze.w, pathCell.cell / maze.w); if (maze.IsMovementAllowed(cell, dir) && (!cellDistances.ContainsKey(nextCell) || cellDistances[nextCell] > pathCell.distance + 1)) { previousCells[nextCell] = pathCell.cell; cellDistances[nextCell] = pathCell.distance + 1; PathCell nextPathCell = new PathCell(); nextPathCell.cell = nextCell; nextPathCell.distance = pathCell.distance + 1; if (nextPathCell.cell == targetCell) { return(BuildPathFromPrecedents(startCell, targetCell, previousCells)); } toCheck.Add(nextPathCell); if (Grid.CellSqrdDistance(maze, closestCell, targetCell) > Grid.CellSqrdDistance(maze, nextCell, targetCell)) { closestCell = nextCell; } toCheck.Sort(delegate(PathCell A, PathCell B){ int ADist = Grid.CellSqrdDistance(maze, A.cell, targetCell); int BDist = Grid.CellSqrdDistance(maze, B.cell, targetCell); return(ADist.CompareTo(BDist)); }); } } } return(BuildPathFromPrecedents(startCell, closestCell, previousCells)); }
private PathCell GetLowestValueCell(HashSet <PathCell> list) { PathCell result = list.First(); foreach (PathCell cell in list) { if (cell.fValue < result.fValue) { result = cell; } } return(result); }
public void DrawCellText(PathCell cell, Rectangle location, string text, CellColor color) { float rgb = color.B + color.R + color.G; Color textColor = Color.Black; Vector2 cellCenter = new Vector2(location.Center.X, location.Center.Y); if (rgb < 0.25f) { textColor = Color.White; } spriteBatch.DrawString(parent.Font, text, cellCenter - (parent.Font.MeasureString(text) / 2), textColor); }
private void UpdateFoundPathCells() { PathCell currentCell = endCell; while (currentCell != startCell) { if (currentCell.Type == PathCell.CellType.Empty) { currentCell.gridCell.SetColor(PathCellColor); } currentCell = currentCell.previousCell; } }
private Stack <TileNode> BuildPathFromTile(PathCell goalCell) { Stack <TileNode> pathTile = new Stack <TileNode>(); PathCell current = goalCell; //Bug if current == null at start do { pathTile.Push(mapGrid[current.GridPosition]); current = current.Parent; } while (current != null); return(pathTile); }
private void UpdatePressedCellType() { ResetGrid(); GridCell cell = GetCellOnMouse(); if (!cell) { return; } Toggle activeToggle = cellTypeToggleGroup.ActiveToggles().First(); ToggleTypeHolder toggleTypeHolder = activeToggle.GetComponent <ToggleTypeHolder>(); PathCell pathCell = cell.GetComponent <PathCell>(); pathfindController.SetCellType(pathCell, toggleTypeHolder.cellType); gridSavingController.SaveCell(pathCell); }
/// <summary> /// 单机模式特殊格子移动动画处理 /// </summary> /// <param name="NowStandCell"></param> void StandMagicAnim(PathCell NowStandCell) { if (NowStand.m_PlayerList.Contains(GetComponent <Player>())) //安全判断 { NowStand.m_PlayerList.Remove(GetComponent <Player>()); //先移除当前路径本玩家 } if (NowStandCell != null) { NowStand = NowStandCell; GetComponent <ImageOverturn>().FlipHorizontal = NowStand.Xturn; transform.DOLocalJump(NowStandCell.rect.anchoredPosition3D, MoveJump, 1, MoveSpeed); if (NumAir < 1) { NowStand.m_PlayerList.Add(GetComponent <Player>());//新停留位置添加此元素 NowStand.NowStandAll(); SceneGameController.Instance.UIGameControl.StandTakeToMove(); } } }
/// <summary> /// AddCell is what the individual cell objects use to dynamically generate the level at runtime /// Cell objects detect their location in the world and pass that data to the LevelController via this method. /// This method generates corresponding entries in all relevant areas of the game state. /// </summary> /// <param name="q">column</param> /// <param name="r">row</param> /// <param name="h">height</param> /// <param name="cellObj">Hex cell object</param> public void AddCell(int q, int r, int h, GameObject cellObj) { //Create a hex data object to go into the level grid HexCellData newCell = new HexCellData(q, r, h, cellObj); levelGrid[q, r, h] = newCell; //Create an pathing hex object to go into the pathing grid PathCell pathCell = new PathCell(q, r, h); aiController[q, r, h] = pathCell; //Create a UI cell object to go into the UI grid UICell uiCell = new UICell(q, r, h); uiController.addCellToUIMap(uiCell); //Set the scale of the object to equal the world hex it represents uiController[q, r, h].setModelScale(cellObj.GetComponent <HexCellObj>().modelScale); cellsReady++; }
public void SetCellType(PathCell cell, PathCell.CellType type) { if (type == PathCell.CellType.Start) { StartCell = cell; } if (type == PathCell.CellType.End) { EndCell = cell; } if (cell.Type == PathCell.CellType.Start && type != PathCell.CellType.Start) { StartCell = null; } if (cell.Type == PathCell.CellType.End && type != PathCell.CellType.End) { EndCell = null; } cell.Type = type; }
private void ProcessNeighbors(PathCell cell) { for (int i = cell.x - 1; i <= cell.x + 1; i++) { for (int j = cell.y - 1; j <= cell.y + 1; j++) { if (!allowDiagonalMove && cell.x != i && cell.y != j) { continue; } if (gridExtension.GetCell(i, j)) { PathCell neighborCell = gridPathCells[i, j]; if (showCheckedCells && neighborCell.Type == PathCell.CellType.Empty) { neighborCell.gridCell.SetColor(CheckedCellColor); } if (neighborCell.Type == PathCell.CellType.Solid || (i == cell.x && j == cell.y) || closedCells.Contains(neighborCell)) { continue; } if (openCells.Contains(neighborCell)) { UpdateOpenCell(neighborCell, cell); } else { AddOpenCell(neighborCell, cell); } } } } }
public void DrawPath(PathCell cell, Rectangle pathRect, Microsoft.Xna.Framework.Point direction, CellColor color) { spriteBatch.Draw(parent.BlankTexture, pathRect, color.ToXnaColor()); }
protected void sortPathCell(PathCell currentPC) { _pathCells.Add(currentPC); foreach(System.Windows.UIElement ue in _mapCanvas.Children) { PathCell pc = ue as PathCell; if(pc==null||_pathCells.Contains(pc))continue; if ( (pc.X == (currentPC.X + 1) && pc.Y == currentPC.Y) || (pc.X == (currentPC.X - 1) && pc.Y == currentPC.Y) || (pc.Y == (currentPC.Y + 1) && pc.X == currentPC.X) || (pc.Y == (currentPC.Y - 1) && pc.X == currentPC.X) ) { sortPathCell(pc); } } }
public bool IsToRefresh(PathCell cell, Rectangle cellRect) { return camera.VisibilityRect.Intersects(cellRect) || camera.VisibilityRect.Contains(cellRect); }
//public void Draw(Canvas canvas) //{ // if (_mapCells == null) { throw new Exception("没有加载地图。"); } //} public bool Load(string filePathName) { releaseMapBitmap(); // 加载地图图片。 _mapBitmap = new Bitmap(filePathName); if (_mapBitmap.Width < Cols || _mapBitmap.Height < Rows) { return false; } for (int x = 0; x < Cols; x++) { for (int y = 0; y < Rows; y++) { System.Drawing.Color c = _mapBitmap.GetPixel(x, y); if (c.R == 255 && c.G == 255 && c.B == 255) // 白色,地面 { _mapCanvas.Children.Add(new LandCell(x,y)); } else { if (c.R == 0 && c.G == 255 && c.B == 0) // 绿色,树 { _mapCanvas.Children.Add(new TreeCell(x,y)); } else { if (c.R == 0 && c.G == 0 && c.B == 255) // 蓝色,怪物进攻路线 { _mapCanvas.Children.Add(new PathCell(x,y)); } else { if (c.R == 0 && c.G == 0 && c.B == 0) // 黑色,基地 { //if (_pathCells[x] != null) { throw new Exception("地图设计错误,基地只能有一个。"); } _baseCell = new BaseCell(x,y); _mapCanvas.Children.Add(_baseCell); } else { if (c.R == 255 && c.G == 0 && c.B == 0) // 红色,怪物入口 { //if (x != 0||_pathCells[0]!=null) { throw new Exception("地图设计错误,怪物入口必须在最左侧且只能有一个入口。"); } _entryCell = new PathCell(x, y); _mapCanvas.Children.Add(_entryCell); } } } } } } } initPathCells(); initGunCells(); return true; }