Hello, I’m currently following two tutorial series based on Nodes and pathfinding, both series have elements of what I want in my scripts but neither of them have all of what I want. To elaborate, one series has the Tile Movement and pathfinding script tuturials that I have used wheras the other has the ability to check for a collider that then converts that to a position on the node (something like that I think).
My ‘walkable’ bool uses Physics.CheckSphere to find that collider.
I am currently having trouble converting this ‘walkable’ bool to a Tile Type ( ‘tileTypes’ ) which doesn’t allow the Player ( ‘Unit’ ) to click and move onto that tile ( in other words a Tile Type that is labelled as 2 in my script is an obstacle tile so the pathfinding works its way around it). Here is my script (apologises but it is very long!!):
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
public class TileMap : MonoBehaviour {
public Transform player;
public Vector3 gridPos;
public GameObject selectedUnit;
public LayerMask unwalkableMask;
public Vector2 gridWorldSize;
public float nodeRadius;
float nodeDiameter;
public bool walkable;
public Vector3 worldPoint;
public TileType[] tileTypes;
public WallTile[] wallTile;
float[,] tilesTwo;
int[,] tiles;
int[,] wallTiles;
Node[,] graph;
int mapSizeX = 10;
int mapSizeZ = 10;
void Start() {
nodeDiameter = nodeRadius * 2;
mapSizeX = Mathf.RoundToInt (gridWorldSize.x / nodeDiameter);
mapSizeZ = Mathf.RoundToInt (gridWorldSize.y / nodeDiameter);
selectedUnit.GetComponent<Unit> ().tileX = (int)selectedUnit.transform.position.x;
selectedUnit.GetComponent<Unit> ().tileZ = (int)selectedUnit.transform.position.z;
selectedUnit.GetComponent<Unit> ().map = this;
GenerateMapData();
GeneratePathfindingGraph();
GenerateMapVisual();
GenerateWall();
}
void GenerateMapData() {
tiles = new int[mapSizeX,mapSizeZ];
wallTiles = new int[mapSizeX, mapSizeZ];
for(int x=0; x < mapSizeX; x++) {
for(int z=0; z < mapSizeX; z++) {
tiles[x,z] = 0;
}
}
for(int x=0; x < mapSizeX; x++) {
for (int z = 0; z < mapSizeX; z++) {
wallTiles [x, z] = 0;
}
}
}
public float CostToEnterTile(int sourceX, int sourceZ, int targetX, int targetZ) {
TileType tt = tileTypes [tiles[targetX, targetZ]];
if(UnitCanEnterTile(targetX, targetZ) == false)
return Mathf.Infinity;
if (UnitIsWalkable (targetX, targetZ) == false)
return Mathf.Infinity;
float cost = tt.movementCost;
if (sourceX != targetX && sourceZ != targetZ) {
cost += 0.001f;
}
return cost;
}
void GeneratePathfindingGraph() {
graph = new Node[mapSizeX, mapSizeZ];
Vector3 worldBottomLeft = gridPos - Vector3.right * gridWorldSize.x/2f - Vector3.forward * gridWorldSize.y/2f;
for (int x = 0; x < mapSizeX; x++) {
for (int z = 0; z < mapSizeZ; z++) {
worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (z * nodeDiameter + nodeRadius);
walkable = !(Physics.CheckSphere (worldPoint, nodeRadius, unwalkableMask));
graph [x, z] = new Node (walkable, worldPoint);
graph [x, z].x = x;
graph [x, z].z = z;
}
}
for (int x = 0; x < mapSizeX; x++) {
for (int z = 0; z < mapSizeX; z++) {
if (x > 0) {
graph [x, z].neighbours.Add (graph [x - 1, z]);
if (z > 0)
graph [x, z].neighbours.Add (graph [x - 1, z - 1]);
if (z < mapSizeZ - 1)
graph [x, z].neighbours.Add (graph [x - 1, z + 1]);
}
if (x < mapSizeX - 1) {
graph [x, z].neighbours.Add (graph [x + 1, z]);
if (z > 0)
graph [x, z].neighbours.Add (graph [x + 1, z - 1]);
if (z < mapSizeZ - 1)
graph [x, z].neighbours.Add (graph [x + 1, z + 1]);
}
if(z > 0)
graph [x, z].neighbours.Add (graph [x, z - 1]);
if(z < mapSizeZ-1)
graph [x, z].neighbours.Add (graph [x, z + 1]);
}
}
}
void GenerateWall() {
for (int x = 0; x < mapSizeX; x++) {
for (int z = 0; z < mapSizeX; z++) {
WallTile wt = wallTile [wallTiles [x, z]];
Instantiate (wt.wallTilePrefab, new Vector3 (x, 0, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.wallTilePrefab, new Vector3 (x, 1, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.wallTilePrefab, new Vector3 (x, 2, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.wallTilePrefab, new Vector3 (x, 3, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.wallTilePrefab, new Vector3 (x, 4, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.wallTilePrefabRight, new Vector3 (mapSizeX - 0.4f, 0, z), Quaternion.identity);
Instantiate (wt.wallTilePrefabRight, new Vector3 (mapSizeX - 0.4f, 1, z), Quaternion.identity);
Instantiate (wt.wallTilePrefabRight, new Vector3 (mapSizeX - 0.4f, 2, z), Quaternion.identity);
Instantiate (wt.wallTilePrefabRight, new Vector3 (mapSizeX - 0.4f, 3, z), Quaternion.identity);
Instantiate (wt.wallTilePrefabRight, new Vector3 (mapSizeX - 0.4f, 4, z), Quaternion.identity);
Instantiate (wt.WallTilePrefabCenter, new Vector3 (mapSizeX - 0.4f, 0, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.WallTilePrefabCenter, new Vector3 (mapSizeX - 0.4f, 1, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.WallTilePrefabCenter, new Vector3 (mapSizeX - 0.4f, 2, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.WallTilePrefabCenter, new Vector3 (mapSizeX - 0.4f, 3, mapSizeZ - 0.4f), Quaternion.identity);
Instantiate (wt.WallTilePrefabCenter, new Vector3 (mapSizeX - 0.4f, 4, mapSizeZ - 0.4f), Quaternion.identity);
}
}
}
void GenerateMapVisual() {
for(int x=0; x < mapSizeX; x++) {
for(int z=0; z < mapSizeX; z++) {
TileType tt = tileTypes[ tiles[x,z] ];
GameObject go = (GameObject)Instantiate( tt.tileVisualPrefab, new Vector3(x, 0 - 0.4f, z), Quaternion.identity );
ClickableTile ct = go.GetComponent<ClickableTile>();
ct.tileX = x;
ct.tileZ = z;
ct.map = this;
}
}
}
public Node NodeFromWorldPoint(Vector3 worldPosition) {
float percentX = (worldPosition.x) / gridWorldSize.x; //+ gridWorldSize.x/2) / gridWorldSize.x;
float percentZ = (worldPosition.z) / gridWorldSize.y;//+ gridWorldSize.y/2) / gridWorldSize.y;
percentX = Mathf.Clamp01 (percentX);
percentZ = Mathf.Clamp01 (percentZ);
int x = Mathf.RoundToInt((mapSizeX) * percentX);
int z = Mathf.RoundToInt((mapSizeZ) * percentZ);
return graph [x, z];
}
public Vector3 TileCoordToWorldCoord(int x, int z) {
return new Vector3 (x, 0, z);
}
public bool UnitCanEnterTile(int x, int z) {
return tileTypes [tiles [x, z]].isWalkable;
}
public bool UnitIsWalkable(int x, int z) {
return walkable;
}
public void GeneratePathTo(int x, int z) {
selectedUnit.GetComponent<Unit> ().currentPath = null;
if (UnitCanEnterTile (x, z) == false) {
return;
}
if (UnitIsWalkable (x, z)== false) {
return;
}
Dictionary<Node, float> dist = new Dictionary<Node, float> ();
Dictionary<Node, Node> prev = new Dictionary<Node, Node>();
List<Node> unvisited = new List<Node> ();
Node source = graph[
selectedUnit.GetComponent<Unit>().tileX,
selectedUnit.GetComponent<Unit>().tileZ
];
Node target = graph[
x,
z
];
dist[source] = 0;
prev[source] = null;
foreach(Node v in graph) {
if(v != source) {
dist [v] = Mathf.Infinity;
prev [v] = null;
}
unvisited.Add (v);
}
while(unvisited.Count > 0) {
Node u = null;
foreach (Node possibleU in unvisited) {
if (u == null || dist [possibleU] < dist [u]) {
u = possibleU;
}
}
if (u == target) {
break;
}
unvisited.Remove(u);
foreach(Node v in u.neighbours) {
float alt = dist [u] + CostToEnterTile (u.x, u.z, v.x, v.z);
if (alt < dist [v]) {
dist [v] = alt;
prev [v] = u;
}
}
}
if (prev [target] == null) {
return;
}
List<Node> currentPath = new List<Node> ();
Node curr = target;
while(curr != null) {
currentPath.Add (curr);
curr = prev[curr];
}
currentPath.Reverse ();
selectedUnit.GetComponent<Unit>().currentPath = currentPath;
}
void OnDrawGizmos () {
Gizmos.DrawWireCube (gridPos, new Vector3 (gridWorldSize.x, 1, gridWorldSize.y));
if (graph != null) {
Node playerNode = NodeFromWorldPoint (player.position);
foreach (Node n in graph) {
Gizmos.color = (n.walkable) ? Color.white : Color.red;
if (playerNode == n) {
Gizmos.color = Color.cyan;
}
Gizmos.DrawCube (n.worldPosition, Vector3.one * (nodeDiameter - .1f));
}
}
}
}
Your help would be greatly appreciated!