Skip to content

Instantly share code, notes, and snippets.

@solsnare
Created August 20, 2022 02:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save solsnare/e5d9a9970497bb039d7e834db4410732 to your computer and use it in GitHub Desktop.
Save solsnare/e5d9a9970497bb039d7e834db4410732 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using Pathfinding.Util;
using UnityEngine;
public class RoomData : MonoBehaviour
{
public Color mapColor;
public TextAsset AStarCache;
public Vector3 startingPosition;
public Vector3 startingRotation;
private static bool _roomsMerged = false;
void Start()
{
//yield return new WaitForSeconds(5.0f);
if (AStarCache == null) return;
AstarPath.active.data.DeserializeGraphsAdditive(AStarCache.bytes);
Matrix4x4 graphMatrix = Matrix4x4.identity;
graphMatrix *= Matrix4x4.Translate(transform.position);
graphMatrix *= Matrix4x4.Rotate(transform.rotation);
graphMatrix *= Matrix4x4.Translate(-transform.position);
graphMatrix *= Matrix4x4.Translate(transform.position - startingPosition);
var graphs = AstarPath.active.graphs;
int pointGraphIndex = graphs.Length - 1;
int recastGraphIndex = graphs.Length - 2;
if (graphs[recastGraphIndex] is RecastGraph)
{
Debug.Log("Moving a recast graph!");
var g = graphs[recastGraphIndex] as RecastGraph;
g.RelocateNodes(graphMatrix);
}
if (graphs[pointGraphIndex] is PointGraph)
{
Debug.Log("Moving a point graph!");
var g = graphs[pointGraphIndex] as PointGraph;
g.RelocateNodes(graphMatrix);
g.Scan();
g.RebuildNodeLookup();
g.RebuildConnectionDistanceLookup();
g.ConnectNodes();
}
}
private RecastGraph masterGraph;
static List<RecastGraph> recasts;
void LateUpdate()
{
if (!_roomsMerged)
{
_roomsMerged = true;
masterGraph = AstarPath.active.data.AddGraph(typeof(RecastGraph)) as RecastGraph; //This will be the main graph with all merged stuff.
Debug.Log($"MASTER GRAPH tileXCount {masterGraph.tileXCount} tileZCount {masterGraph.tileZCount}");
Bounds b = new Bounds();
bool boundsEmpty = true;
float minCellSize = Mathf.Infinity;
recasts = new List<RecastGraph>();
for (int i = 0; i < AstarPath.active.data.graphs.Length - 1; i++) //The final graph will be ours, that's why we do -1.
{
if (AstarPath.active.data.graphs[i] is RecastGraph)
{
var g = AstarPath.active.data.graphs[i] as RecastGraph;
Debug.Log($"Graph {i} tileXCount {g.tileXCount} tileZCount {g.tileZCount}");
var bounds = g.GetTileBounds(new IntRect(0, 0, g.tileXCount-1, g.tileZCount-1));
if (boundsEmpty)
{
b = bounds;
boundsEmpty = false;
}
else
{
b.Encapsulate(bounds);
}
if (g.cellSize < minCellSize)
{
minCellSize = g.cellSize;
}
recasts.Add(g);
}
}
masterGraph.cellSize = minCellSize;
Debug.Log("DRAWNG RED LINE");
Debug.DrawLine(b.center - b.extents,b.center+b.extents,Color.red,100.0f);
//Based on the calculated bounds, let's calculate how many tiles we need to fill that
// Voxel grid size
int totalVoxelWidth = (int)(b.size.x / masterGraph.cellSize + 0.5f);
int totalVoxelDepth = (int)(b.size.z / masterGraph.cellSize + 0.5f);
int tileSizeX;
int tileSizeZ;
if (!masterGraph.useTiles)
{
tileSizeX = totalVoxelWidth;
tileSizeZ = totalVoxelDepth;
}
else
{
tileSizeX = masterGraph.editorTileSize;
tileSizeZ = masterGraph.editorTileSize;
}
// Number of tiles
int tileXCount = (totalVoxelWidth + tileSizeX - 1) / tileSizeX;
int tileZCount = (totalVoxelDepth + tileSizeZ - 1) / tileSizeZ;
if (tileXCount * tileZCount > NavmeshBase.TileIndexMask + 1)
{
throw new System.Exception("Too many tiles (" + (tileXCount * tileZCount) + ") maximum is " + (NavmeshBase.TileIndexMask + 1) +
"\nTry disabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* inspector.");
}
//Based on this, let's make the master graph big enough to contain all these.
masterGraph.tileXCount = tileXCount;
masterGraph.tileZCount = tileZCount;
Debug.Log($"CREATING GRAPH WITH X {tileXCount} Z {tileZCount}");
//Initialize the tile array:
masterGraph.InitializeTiles();
masterGraph.FillWithEmptyTiles();
Bounds nb = masterGraph.GetTileBounds(new IntRect(0, 0, masterGraph.tileXCount-1, masterGraph.tileZCount-1));
Debug.DrawLine(nb.center - nb.extents, nb.center + nb.extents, Color.yellow, 100);
//Debug.DrawLine(b.center - b.extents, b.center + b.extents, Color.green, 100);
//The issue here is that the graph is the right size, but it's not aligned properly.
//To align this properly, we need to shift it's current bounds to the calculated world bounds.
Vector3 boundDiff = b.center - nb.center;
Matrix4x4 graphMatrix = Matrix4x4.identity;
//Vector3 tileOffset = new Vector3(masterGraph.tileSizeX, 0, masterGraph.tileSizeZ);
//tileOffset = masterGraph.transform.Transform(tileOffset);
//Vector3 tileOffset = new Vector3(1.25f, 0, 1.25f);
Vector3 tileOffset = new Vector3(0, (nb.size.y - b.size.y)/2,0);
//Vector3 tileOffset = new Vector3(0, 0, 0);
graphMatrix *= Matrix4x4.Translate(boundDiff + tileOffset);
//graphMatrix *= Matrix4x4.Rotate(Quaternion.Euler(0, 90, 0));
masterGraph.RelocateNodes(graphMatrix);
//masterGraph.transform = recasts[0].transform;
//graph.RelocateNodes(recasts[1].transform);
Bounds nb2 = masterGraph.GetTileBounds(new IntRect(0, 0, masterGraph.tileXCount-1, masterGraph.tileZCount-1));
Debug.DrawLine(nb2.center - nb2.extents, nb2.center + nb2.extents, Color.magenta, 100);
Debug.Log("MASTER BOUNDS: " + nb2);
//----------------------------------
//Now we have a graph that is the right size, and placement
//We need to loop through all the recast graphs again, and place their tile data into this larger tilemap
//--------------------------------
//Bounds topLeftTile = recasts[2].GetTileBounds(0, 0, 1, 1);
//Bounds bottomRightTile = recasts[2].GetTileBounds(recasts[0].tileXCount - 2, recasts[0].tileZCount - 2, 1, 1);
//Debug.DrawLine(topLeftTile.center - topLeftTile.extents, topLeftTile.center + topLeftTile.extents, Color.green, 100);
//Debug.DrawLine(bottomRightTile.center - bottomRightTile.extents, bottomRightTile.center + bottomRightTile.extents, Color.magenta, 100);
TriangleMeshNode.SetNavmeshHolder(AstarPath.active.data.GetGraphIndex(masterGraph), masterGraph);
Debug.Log($"TILE SIZE MASTER {masterGraph.TileWorldSizeX} AND GRAPH: {recasts[0].TileWorldSizeX}");
Debug.Log($"World Size {masterGraph.TileWorldSizeX} Tile Count {masterGraph.tileXCount} Tile Size {masterGraph.tileSizeX} Editor Size {masterGraph.editorTileSize}");
AstarPath.active.AddWorkItem((context) =>
{
masterGraph.StartBatchTileUpdate();
foreach (RecastGraph rg in recasts)
{
for (int x = 0; x < rg.tileXCount; x++)
{
for (int z = 0; z < rg.tileZCount; z++)
{
//Given that the main graph bounds are aligned properly now
//We need to convert the tile position from it's space to masterGraphs space.
//To do this we want to convert this tile from local into world first.
var tile = rg.GetTile(x, z);
var tileB = rg.GetTileBounds(x, z, 1, 1);
//Bounds is in world space, so we can use that to convert into master graph local space.
var masterTileLoc = masterGraph.GetTileCoordinates(tileB.center);
//If this is not out of bounds
if (masterTileLoc.x >= 0 && masterTileLoc.x < masterGraph.tileXCount && masterTileLoc.y >= 0 &&
masterTileLoc.y < masterGraph.tileZCount)
{
}
else continue;
//var masterTileB = masterGraph.GetTileBounds(masterTileLoc.x,masterTileLoc.y,1,1);
//Debug.DrawLine(masterTileB.center - masterTileB.extents, masterTileB.center + masterTileB.extents, Color.white, 100);
//Debug.Log($"Replacing X:{masterTileLoc.x} Z:{masterTileLoc.y}");
Int3[] verts = new Int3[tile.vertsInGraphSpace.Length];
tile.vertsInGraphSpace.CopyTo(verts,0);
Matrix4x4 trans = Matrix4x4.identity;
trans *= Matrix4x4.Scale(Vector3.one * 0.1f);
GraphTransform newGraphTrans = new GraphTransform(trans);
//newGraphTrans.Transform(verts);
int xSize = (int)(masterGraph.TileWorldSizeX * 1000);
int zSize = (int)(masterGraph.TileWorldSizeZ * 1000);
for (int i = 0; i < verts.Length; i++)
{
verts[i].x -= (xSize * x);
verts[i].z -= (zSize * z);
}
//Let's replace the info.
masterGraph.ReplaceTile(masterTileLoc.x, masterTileLoc.y, verts, tile.tris);
//There is a problem with the vertices looking like they're scaled up by 3 or 4 times?
//Not only that but the vertices are kinda far apart, doesn't make cohesive tiles, it's weird.
//tile.vertsInGraphSpace
}
}
}
masterGraph.EndBatchTileUpdate();
});
//Clean up all the old graphs.
foreach (RecastGraph r in recasts)
{
AstarPath.active.data.RemoveGraph(r);
}
}
}
void OnDrawGizmos()
{
return;
if (!_roomsMerged) return;
Gizmos.color = Color.blue;
if (_roomsMerged && masterGraph != null)
{
for (int x = 0; x < masterGraph.tileXCount; x++)
{
for (int z = 0; z < masterGraph.tileZCount; z++)
{
var b = masterGraph.GetTileBounds(x, z, 1, 1);
Gizmos.DrawWireCube(b.center, b.size);
}
}
}
//Size of tile b 2.6 in worldspace.
return;
Bounds totalB = new Bounds();
bool firstBound = true;
Gizmos.color = Color.yellow;
if (_roomsMerged && masterGraph != null)
{
for (int x = 0; x < recasts[0].tileXCount; x++)
{
for (int z = 0; z < recasts[0].tileZCount; z++)
{
var b = recasts[0].GetTileBounds(x, z, 1, 1);
Gizmos.DrawWireCube(b.center, b.size);
if (firstBound)
{
totalB = b;
firstBound = false;
}
else totalB.Encapsulate(b);
}
}
}
Gizmos.color = Color.cyan;
var bounds = recasts[0].GetTileBounds(new IntRect(0, 0, recasts[0].tileXCount - 1, recasts[0].tileZCount - 1));
Gizmos.DrawWireCube(totalB.center, totalB.size);
}
[ContextMenu("Set Starting Position")]
void SetStartingPosition()
{
startingPosition = transform.position;
startingRotation = transform.rotation.eulerAngles;
}
void OnDestroy()
{
_roomsMerged = false;
recasts = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment