private void Update() { if (!_isActive) { return; } if (grid == null || grid.Value == null) { return; } if (uiTilemap == null) { return; } // todo(chris) remove nasty hack for "is paused" if (Time.timeScale < float.Epsilon) { return; } var worldPoint = _camera.ScreenToWorldPoint(Input.mousePosition); var node = new Grid.Grid.Node(); if (grid.Value.TryGetNodeAtWorldPosition(worldPoint, ref node)) { if (_node?.Equals(node) != true) { _node = node; OnNewNode(node); } } }
private void OnNewNode(Grid.Grid.Node node) { switch (_mode) { case MouseMode.Moving: highlightedUiTilemap.ClearAllTiles(); _path = _pathfinding.CalculatePath(_player.transform.position, node.WorldPosition); if (_path != null && _path.Count > 0) { foreach (var n in _path) { var pos = grid.Value.Position00.ToVector2Int() + n.Position; highlightedUiTilemap.SetTile((Vector3Int)pos, up); } } else { var pos = grid.Value.Position00.ToVector2Int() + node.Position; if (uiTilemap.HasTile((Vector3Int)pos)) { highlightedUiTilemap.SetTile((Vector3Int)pos, attackTile); } } break; case MouseMode.RangedWeaponMode: var diff = node.Position - _player.CurrentNodeIdx; highlightedUiTilemap.ClearAllTiles(); if (diff.IsCardinal()) { HighlightCardinal(diff, highlightedUiTilemap); } break; case MouseMode.OtherWeapon: var effected = _item.FindAllPossibleEffectedNodes(_player.Occupant, grid.Value); if (effected.Contains(node)) { var pos = grid.Value.Position00.ToVector2Int() + node.Position; if (uiTilemap.HasTile((Vector3Int)pos)) { highlightedUiTilemap.SetTile((Vector3Int)pos, highlighted); } } break; default: break; } }
private void Start() { var offsetX = .5f; var offsety = .5f; Grid.Node[,] nodes = new Grid.Node[width, height]; StringBuilder sb = new StringBuilder(); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { var worldPosition = new Vector3(x + bottomLeft.x + offsetX, y + bottomLeft.y + offsety); var cellPos = impassable.WorldToCell(worldPosition); var tile = impassable.GetTile(cellPos); if (tile) { nodes[x, y] = new Grid.Node(x, y, -1, worldPosition); sb.Append(", -1"); continue; } cellPos = impassable.WorldToCell(worldPosition); tile = passable.GetTile(cellPos); if (tile) { nodes[x, y] = new Grid.Node(x, y, 1, worldPosition); sb.Append(", 1"); continue; } nodes[x, y] = new Grid.Node(x, y, -2, worldPosition); sb.Append(", -2"); } sb.Append("\n"); } // Debug.Log("grid:\n" + sb.ToString()); _grid = new SquareGrid(nodes, bottomLeft); output.Value = _grid; onGridGenerated.Raise(); }
public List <IUnitAction> CollideWith(GridOccupant other, Grid.Grid.Node otherNode) { // if I hurt things on collision then hurt them if (OnCollisionEffects?.CanTarget(other, _occupant.Occupant, _occupant.Grid) == true) { var diff = new Vector2Int(otherNode.X, otherNode.Y) - _occupant.CurrentNodeIdx; return(OnCollisionEffects.Use(_occupant.Occupant, diff, _occupant.Grid)); } else { return(null); } }
private bool IsNodeValid(Grid.Grid.Node node) { if (_onGoing.Contains(node)) { return(false); } foreach (var occupant in node.Occupants) { if (cantSpawnOn.Contains(occupant.Type)) { return(false); } } return(true); }
private IEnumerator OnCollision(Unit.Unit unit, Grid.Grid.Node startNode, Grid.Grid.Node lastNode, float speed, bool twoWayCollisions, Transform toMove) { if (_collisionBehaviour != null) { var colliderOccupant = _collider2D.gameObject.GetComponent <GridOccupantBehaviour>(); unit.QueueRange(_collisionBehaviour.CollideWith(colliderOccupant.Occupant, colliderOccupant.CurrentNode.Value)); } if (twoWayCollisions) { var collision = _collider2D.GetComponent <OnCollisionBehaviour>(); if (collision != null) { unit.QueueRange(collision.CollideWith(unit.Occupant.Occupant, startNode)); } } yield return(StartCoroutine(CoMove(unit, lastNode, speed, false, toMove))); // unit.QueueAction(new MoveToPointAction(unit, lastNode, toMove, false)); }
public List <Grid.Grid.Node> CalculatePath(Vector2 from, Vector2 to, bool considerEndCost = true) { var startNode = new Grid.Grid.Node(); var endNode = new Grid.Grid.Node(); if (grid == null) { grid = _grid.Get(); } if (!grid.Value.TryGetNodeAtWorldPosition(from, ref startNode)) { return(new List <Grid.Grid.Node>()); } if (!grid.Value.TryGetNodeAtWorldPosition(to, ref endNode)) { return(new List <Grid.Grid.Node>()); } return(CalculatePath(grid.Value, startNode, endNode, considerEndCost)); }
private IEnumerator CoMove(Unit.Unit unit, Grid.Grid.Node destination, float speed, bool twoWayCollisions, Transform toMove) { Vector2 endPoint = destination.WorldPosition; var startNode = unit.Occupant.CurrentNode; if (startNode == null) { yield break; } var lastNode = startNode.Value; var startPoint = (Vector2)toMove.position; var start = Time.time; var distance = (endPoint - startPoint).magnitude; var duration = distance / speed; var end = start + duration; _collider2D = null; onStartMove.Invoke(); while (Time.time < end && _collider2D == null) { var t = (Time.time - start) / duration; var x = Tween.Lerp(startPoint.x, endPoint.x, t); var y = Tween.Lerp(startPoint.y, endPoint.y, t); toMove.position = new Vector3(x, y, toMove.position.z); if (moveToLastNodeOnCollision) { var node = new Grid.Grid.Node(); if (!unit.Occupant.Grid.TryGetNodeAtWorldPosition(toMove.position, ref node)) { toMove.position = lastNode.WorldPosition; yield break; } if (!node.Equals(lastNode) && !node.Equals(destination)) { if (Vector2.Distance(toMove.position, node.WorldPosition) < .4f) { lastNode = node; } } } yield return(null); } OnStopMove.Invoke(); if (_collider2D == null && _myCollider != null) { var cached = _myCollider.enabled; _myCollider.enabled = false; _collider2D = Physics2D.OverlapCircle(toMove.position, .3f, layers); _myCollider.enabled = cached; } if (_collider2D == null) { toMove.position = new Vector3(endPoint.x, endPoint.y, toMove.position.z); } else { yield return(StartCoroutine(OnCollision(unit, startNode.Value, lastNode, speed, twoWayCollisions, toMove))); } }
private IEnumerator CoMove(Unit.Unit unit, Grid.Grid.Node destination, float speed, bool twoWayCollisions, Action onComplete, Transform toMove) { yield return(StartCoroutine(CoMove(unit, destination, speed, twoWayCollisions, toMove))); onComplete(); }
public void Move(Unit.Unit unit, Grid.Grid.Node destination, Action onComplete, bool twoWayCollisions = false, Transform toMove = null) { StartCoroutine(CoMove(unit, destination, speed, twoWayCollisions, onComplete, toMove ?? transform)); }
private IEnumerator BuildRoom() { LevelDefinition level = new LevelDefinition(); var adjustedHeight = height + 4; var adjustedWidth = width + 4; char[,] roomChars = new char[adjustedWidth, adjustedHeight]; char playerEntrance = 'b'; bool levelParsed = false; while (!levelParsed) { try { level = PickRoom(out playerEntrance, out var flipX, out var flipY); var roomString = level.Level; // var roomString = room.Template; roomChars = StringToCharTable(width, height, roomString); roomChars = ExpandChunks(roomChars); roomChars = AddBorder(roomChars); if (flipX) { roomChars = FlipX(roomChars, adjustedWidth, adjustedHeight); } if (flipY) { roomChars = FlipY(roomChars, adjustedWidth, adjustedHeight); } levelParsed = true; } catch (Exception e) { Debug.LogException(e); // without this we have no game, pick a a new room and try again } } var grid = new Grid.Node[adjustedWidth, adjustedHeight]; int tileIdx = 0; Vector3Int pos = Vector3Int.zero; Vector2 worldPos = Vector2.zero; bool playerSpawned = false; var enemySpawnPoints = new List <Vector3Int>(); var terrainSpawnPoints = new List <Vector3Int>(); var lootSpawnPoints = new List <Vector3Int>(); var specialLootSpawnPoints = new List <Vector3Int>(); for (int y = 0; y < adjustedHeight; ++y) { pos.y = y; worldPos.y = y + .5f; for (int x = 0; x < adjustedWidth; ++x) { pos.x = x; worldPos.x = x + .5f; switch (roomChars[x, y]) { case 'c': { chasm.SetTile(pos, tiles.ChasmTiles.RandomElement()); var go = Instantiate(tiles.Chasm, worldPos, Quaternion.identity); go.transform.parent = chasmParent; grid[x, y] = new Grid.Node(x, y, -2, worldPos); break; } case 'u': { var go = Instantiate(tiles.UnbreakableWall, worldPos, Quaternion.identity); go.transform.parent = unbreakableParent; grid[x, y] = new Grid.Node(x, y, -2, worldPos); break; } case 'w': { walls.SetTile(pos, tiles.Wall); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } case 'b': // entry/exit { playerSpawned = SpawnEntrance( 'b', playerEntrance, playerSpawned, worldPos, Vector2.down, tiles.BottomExit ); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } case 'l': // entry/exit { playerSpawned = SpawnEntrance( 'l', playerEntrance, playerSpawned, worldPos, Vector2.left, tiles.LeftExit ); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } case 't': // entry/exit { playerSpawned = SpawnEntrance( 't', playerEntrance, playerSpawned, worldPos, Vector2.up, tiles.TopExit ); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } case 'r': // entry/exit { playerSpawned = SpawnEntrance( 'r', playerEntrance, playerSpawned, worldPos, Vector2.right, tiles.RightExit ); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } case 'n': // entry/exit { floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } case 'h': // high value item { specialLootSpawnPoints.Add(pos); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } default: // must be floor so can spawns ememies and loot here { enemySpawnPoints.Add(pos); terrainSpawnPoints.Add(pos); lootSpawnPoints.Add(pos); floor.SetTile(pos, tiles.FloorTiles.RandomElement()); grid[x, y] = new Grid.Node(x, y, 1, worldPos); break; } } if (timelapse > 0) { yield return(new WaitForSeconds(timelapse)); } } } var enemiesAmount = UnityEngine.Random.Range(level.MinEnemies, level.MaxEnemies + 1); var terrainAmount = UnityEngine.Random.Range(level.MinTerrain, level.MaxTerrain + 1); var itemsAmount = UnityEngine.Random.Range(level.MinItems, level.MaxItems + 1); while (enemySpawnPoints.Count > 0 && enemiesAmount > 0) { var point = enemySpawnPoints.RandomElement(); worldPos = new Vector2(point.x + .5f, point.y + .5f); var spawned = false; foreach (var enemy in tiles.Enemies) { if (UnityEngine.Random.Range(1, enemy.Second) == 1) { var go = Instantiate(enemy.First, worldPos, Quaternion.identity); go.transform.parent = enemiesParent; spawned = true; break; } } if (spawned) { --enemiesAmount; enemySpawnPoints.Remove(point); } } while (terrainSpawnPoints.Count > 0 && terrainAmount > 0) { var point = terrainSpawnPoints.RandomElement(); worldPos = new Vector2(point.x + .5f, point.y + .5f); var spawned = false; foreach (var terrain in tiles.Terrain) { if (UnityEngine.Random.Range(1, terrain.Second) == 1) { var go = Instantiate(terrain.First, worldPos, Quaternion.identity); go.transform.parent = terrainParent; spawned = true; break; } } if (spawned) { --terrainAmount; terrainSpawnPoints.Remove(point); } } while (lootSpawnPoints.Count > 0 && itemsAmount > 0) { var point = lootSpawnPoints.RandomElement(); worldPos = new Vector2(point.x + .5f, point.y + .5f); var spawned = false; foreach (var item in tiles.Items) { if (UnityEngine.Random.Range(1, item.Second) == 1) { var go = Instantiate(tiles.Pickup, worldPos, Quaternion.identity); // go.transform.parent = enemiesParent; go.GetComponent <PickUpBehaviour>().SetItem(item.First); spawned = true; break; } } if (spawned) { --itemsAmount; lootSpawnPoints.Remove(point); } } output.Value = new SquareGrid(grid, Vector2.zero); yield return(null); onGridBuilt.Raise(); yield break; }
private List <Grid.Grid.Node> CalculatePath(Grid.Grid grid, Grid.Grid.Node start, Grid.Grid.Node end, bool considerEndCost) { var path = new List <Grid.Grid.Node>(); var frontier = new PriorityQueue <Grid.Grid.Node, int>(); var cameFrom = new Dictionary <Grid.Grid.Node, Grid.Grid.Node>(); var costSoFar = new Dictionary <Grid.Grid.Node, int>(); frontier.Enqueue(start, 0); cameFrom[start] = start; costSoFar[start] = 0; while (frontier.Count > 0) { var current = frontier.Dequeue(); if (current.Equals(end)) { var n = end; while (!n.Equals(start)) { path.Add(n); n = cameFrom[n]; } path.Reverse(); return(path); } var costToCurrent = costSoFar[current]; foreach (var next in grid.GetNeighbours(current)) { var cost = costToCurrent; if (next.Equals(end) && !considerEndCost) { cost += 1; } else if (next.Cost < 0) { continue; } else { cost += next.Cost; } if (costSoFar.ContainsKey(next) && cost >= costSoFar[next]) { continue; } costSoFar[next] = cost; int priority = cost + Heuristic(next, end); frontier.Enqueue(next, priority); cameFrom[next] = current; } } return(path); }
private int Heuristic(Grid.Grid.Node node, Grid.Grid.Node end) { return(Math.Abs(node.X - end.X) + Math.Abs(node.Y - end.Y)); }