/// <summary> /// Creates grey boxes at each point the player has clicked before, but /// the player pawn hasn't caught up to yet. /// </summary> /// <param name="tilemap">The map</param> /// <returns>The line segments to render</returns> IEnumerable <SegmentProperties> GenerateCheckpointLines(IMap tilemap) { var segments = new List <SegmentProperties>(); foreach (var c in commandCheckpoints) { var worldSpace = GridSpaceConversion.GetWorldSpaceFromLogical(c, tilemap); var square = LineElements.SquareSelectionSegments(worldSpace, Color.grey); segments.AddRange(square); } return(segments); }
public void LogicalTick() { if (currentMotionPath.Any()) { animator.SetBool("IsMoving", true); } else { animator.SetBool("IsMoving", false); } while (currentMotionPath.Any()) { var nextPosLogical = currentMotionPath.Dequeue(); if (nextPosLogical == LogicalLocation) { continue; } else { var nextPosWorld = GridSpaceConversion.GetWorldSpaceFromLogical( nextPosLogical, tilePlacedComponent.Tilemap); float angle = 180.0f; if (nextPosLogical.x > LogicalLocation.x) { angle = 90.0f; } else if (nextPosLogical.x < LogicalLocation.x) { angle = -90.0f; } else if (nextPosLogical.y > LogicalLocation.y) { angle = 0.0f; } logicalLocation = nextPosLogical; gameObject.transform.localPosition = nextPosWorld; gameObject.transform.localRotation = Quaternion.AngleAxis(angle, Vector3.back) * Quaternion.Euler(-90.0f, 0.0f, 0.0f); break; } } }
void Update() { if (GameStats.GameOver) { return; } if (mapNeedsRebuild) { cellGraph = LogicalCellGraph.BuildCellGraph(Map, GetGateLogicalPositions()); playerController?.RebuildGraph(cellGraph); needsMouseUpdate = true; enemyBrain?.RebuildGraph(cellGraph); mapNeedsRebuild = false; } var mouseSceenSpace = Input.mousePosition; var mouseWorldSpace = Camera.main.ScreenToWorldPoint(mouseSceenSpace); var mouseGridSpace = Map.WorldToCell(mouseWorldSpace); var mouseLogicalSpace = GridSpaceConversion.GetLogicalSpaceFromGridSpace(mouseGridSpace, Map); if (playerController != null) { bool onGrid = mouseLogicalSpace.x >= 0 && mouseLogicalSpace.y >= 0 && mouseLogicalSpace.x < cellGraph.SizeX && mouseLogicalSpace.y < cellGraph.SizeY; if (mouseLogicalSpace != lastMouseLogicalPosition || needsMouseUpdate) { needsMouseUpdate = false; lastMouseLogicalPosition = mouseLogicalSpace; playerController.OnMouseMove(mouseLogicalSpace, !onGrid, cellGraph, Map); } if (Input.GetMouseButtonDown(0)) { playerController.OnMouseClick(); playerController.RebuildGraph(cellGraph); needsMouseUpdate = true; } var mesh = playerController.GenerateLineMesh(Map); meshFilter.mesh = mesh; } }
/// <summary> /// Creates line segments from a logical-coordinate-based path /// </summary> /// <param name="path">The logical path</param> /// <param name="tilemap">The map where the path originated from</param> /// <returns>A list of segments that can be drawn</returns> public static IEnumerable <SegmentProperties> SegmentsFromPath(LogicalPath path, IMap tilemap) { var points = new List <Vector3>(); foreach (var cell in path.Path) { var world = GridSpaceConversion.GetWorldSpaceFromLogical(cell, tilemap); points.Add(world); } if (points.Count <= 1) { return(new List <SegmentProperties>()); } Vector3 facingDir = Vector3.back; const float width = 0.08f; Color color = Color.white; var segments = new SegmentProperties[points.Count - 1]; Vector3 lastPoint = points.First(); int segIndex = 0; for (int n = 1; n < points.Count; ++n) { var point = points[n]; segments[segIndex++] = new SegmentProperties { Start = lastPoint, End = point, FacingDirection = facingDir, Style = SegmentStyle.Dashed, Width = width, Color = color }; lastPoint = point; } return(segments); }
/// <summary> /// Creates a box around where the user has their mouse targeted. /// The appears might vary depending on the validity of that location /// </summary> /// <param name="tilemap">The map</param> /// <returns>The line segments to render</returns> IEnumerable <SegmentProperties> GenerateSelectionBoxLines(IMap tilemap) { if (lastMouseLocationOffGrid) { return(new List <SegmentProperties>()); } List <SegmentProperties> segments = new List <SegmentProperties>(); var selectedCellWorldSpace = GridSpaceConversion.GetWorldSpaceFromLogical(lastMouseLocation, tilemap); Color boxColor = Color.white; if (!pendingTargetActive) { boxColor = Color.red; segments.AddRange(LineElements.XSegments(selectedCellWorldSpace, boxColor)); } segments.AddRange(LineElements.SquareSelectionSegments(selectedCellWorldSpace, boxColor)); return(segments); }
/// <summary> /// Builds a logical cell grid from the game data /// </summary> /// <param name="tilemap">The game map</param> /// <param name="gateLocations">The locations of all the locked doors/gates</param> /// <returns>A logical cell graph which contains useful neighboring data</returns> public static LogicalCellGraph BuildCellGraph(IMap tilemap, IEnumerable <Vector3Int> gateLocations) { LogicalCellGraph graph = new LogicalCellGraph(); var logicalSize = tilemap.CellBounds.size / 2; var sizeX = logicalSize.x; var sizeY = logicalSize.y; int[,,] colors = new int[sizeX, logicalSize.y, 4]; LogicalCell[,] cells = new LogicalCell[sizeX, logicalSize.y]; var gateLocationsSet = new HashSet <Vector3Int>(); foreach (var g in gateLocations) { gateLocationsSet.Add(g); } for (int y = 0; y < sizeY; ++y) { for (int x = 0; x < sizeX; ++x) { var cell = new LogicalCell { X = x, Y = y }; var logicalSpace = GridSpaceConversion.GetLogicalSpaceFromCell(cell); if (gateLocationsSet.Contains(logicalSpace)) { colors[x, y, 0] = 0; // Reserved for gates colors[x, y, 1] = 0; colors[x, y, 2] = 0; colors[x, y, 3] = 0; } else { var gridSpace = GridSpaceConversion.GetGridSpaceFromLogical(logicalSpace, tilemap); // I wouldn't typically depend on render state for logical stuff, // But this game will be all about color so I think it's OK. colors[x, y, 0] = tilemap.GetColor(new Vector3Int(gridSpace.x, gridSpace.y, 0)).GetHashCode(); colors[x, y, 1] = tilemap.GetColor(new Vector3Int(gridSpace.x + 1, gridSpace.y, 0)).GetHashCode(); colors[x, y, 2] = tilemap.GetColor(new Vector3Int(gridSpace.x, gridSpace.y + 1, 0)).GetHashCode(); colors[x, y, 3] = tilemap.GetColor(new Vector3Int(gridSpace.x + 1, gridSpace.y + 1, 0)).GetHashCode(); } cells[x, y] = cell; } } for (int y = 0; y < sizeY; ++y) { for (int x = 0; x < sizeX; ++x) { HashSet <int> colorsInThisCell = new HashSet <int>(new int[] { colors[x, y, 0], colors[x, y, 1], colors[x, y, 2], colors[x, y, 3], }); LogicalCell thisCell = cells[x, y]; LogicalCell upNeighbor = null; for (int up = y + 1; up < sizeY; ++up) { if (colorsInThisCell.Contains(colors[x, up, 0]) || colorsInThisCell.Contains(colors[x, up, 1]) || colorsInThisCell.Contains(colors[x, up, 2]) || colorsInThisCell.Contains(colors[x, up, 3])) { upNeighbor = cells[x, up]; break; } } LogicalCell downNeighbor = null; for (int down = y - 1; down >= 0; --down) { if (colorsInThisCell.Contains(colors[x, down, 0]) || colorsInThisCell.Contains(colors[x, down, 1]) || colorsInThisCell.Contains(colors[x, down, 2]) || colorsInThisCell.Contains(colors[x, down, 3])) { downNeighbor = cells[x, down]; break; } } LogicalCell rightNeighbor = null; for (int right = x + 1; right < sizeX; ++right) { if (colorsInThisCell.Contains(colors[right, y, 0]) || colorsInThisCell.Contains(colors[right, y, 1]) || colorsInThisCell.Contains(colors[right, y, 2]) || colorsInThisCell.Contains(colors[right, y, 3])) { rightNeighbor = cells[right, y]; break; } } LogicalCell leftNeighbor = null; for (int left = x - 1; left >= 0; --left) { if (colorsInThisCell.Contains(colors[left, y, 0]) || colorsInThisCell.Contains(colors[left, y, 1]) || colorsInThisCell.Contains(colors[left, y, 2]) || colorsInThisCell.Contains(colors[left, y, 3])) { leftNeighbor = cells[left, y]; break; } } thisCell.SetNeighbors(upNeighbor, leftNeighbor, rightNeighbor, downNeighbor); } } graph.indexedCells = cells; return(graph); }