402 lines
14 KiB
C#
402 lines
14 KiB
C#
#if UNITY_EDITOR
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
|
|
[CustomEditor(typeof(World))]
|
|
public class WorldEditor : Editor
|
|
{
|
|
public override void OnInspectorGUI()
|
|
{
|
|
GUILayout.Label("Server file for a* pathfinding");
|
|
if (GUILayout.Button("Generate .mapdata"))
|
|
{
|
|
GenerateAStarMapData(World.WORLD_SIZE_X, World.WORLD_SIZE_Y);
|
|
}
|
|
|
|
GUILayout.Label("Server file for height data");
|
|
if (GUILayout.Button("Generate .heightmap"))
|
|
{
|
|
generateHeightMap();
|
|
}
|
|
|
|
//if (GUILayout.Button("Generate Object Data"))
|
|
//{
|
|
// generateObjectData();
|
|
//}
|
|
//if (GUILayout.Button("Turn All Box Colliders into Mesh Colliders"))
|
|
//{
|
|
// turnAllBoxCollidersIntoMesh();
|
|
//}
|
|
}
|
|
|
|
public void generateHeightMap()
|
|
{
|
|
int[] heightData = new int[World.WORLD_SIZE_X * World.WORLD_SIZE_Y];
|
|
for (int i = 0; i < World.WORLD_SIZE_Y; i++)
|
|
{
|
|
for (int j = 0; j < World.WORLD_SIZE_X; j++)
|
|
{
|
|
Vector3 position = new Vector3(j, 0.0f, i);
|
|
Terrain t = Misc.GetClosestCurrentTerrain(position);
|
|
float height = t.SampleHeight(position);
|
|
|
|
heightData[i * World.WORLD_SIZE_X + j] = (int)(height * 100);
|
|
}
|
|
}
|
|
using (FileStream fileStream = new FileStream("output/.heightmap", FileMode.Create)) // destiny file directory.
|
|
{
|
|
using (BinaryWriter binaryWriter = new BinaryWriter(fileStream))
|
|
{
|
|
byte[] mapWidth = convInt(World.WORLD_SIZE_X);
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
fileStream.WriteByte(mapWidth[i]);
|
|
}
|
|
byte[] mapHeight = convInt(World.WORLD_SIZE_Y);
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
fileStream.WriteByte(mapHeight[i]);
|
|
}
|
|
for (int i = 0; i < heightData.Length; i++)
|
|
{
|
|
byte[] value = convInt((int)(heightData[i]));
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
fileStream.WriteByte(value[j]);
|
|
}
|
|
}
|
|
|
|
fileStream.Close();
|
|
}
|
|
|
|
//now write the data file
|
|
//write world collision map to a png file
|
|
Texture2D texture = new Texture2D(World.WORLD_SIZE_X, World.WORLD_SIZE_Y, TextureFormat.RGB24, false); // create texture2D to store the map in, written to file at the end of the method
|
|
|
|
// set all pixels to black
|
|
for (int i = 0; i < World.WORLD_SIZE_Y; i++)
|
|
{
|
|
for (int j = 0; j < World.WORLD_SIZE_X; j++)
|
|
{
|
|
float f = (float)heightData[i * World.WORLD_SIZE_X + j];
|
|
Color c = new Color(f / 1000.0f, 0.0f, 0.0f);
|
|
texture.SetPixel(j, i, c);
|
|
}
|
|
}
|
|
|
|
texture.Apply();
|
|
byte[] fileData = texture.EncodeToPNG();
|
|
System.IO.File.WriteAllBytes("output/heightmap.png", fileData);
|
|
}
|
|
}
|
|
|
|
public void GenerateAStarMapData(int width, int height)
|
|
{
|
|
Debug.ClearDeveloperConsole();
|
|
Debug.Log("Generating A* Path Data...");
|
|
|
|
RaycastHit[] hits = new RaycastHit[5];
|
|
|
|
FileStream fileStream = new FileStream("output/.astar", FileMode.Create);
|
|
|
|
byte[] mapWidth = convInt(width);
|
|
for (int i = 0; i < 4; i++) { fileStream.WriteByte(mapWidth[i]); }
|
|
|
|
byte[] mapHeight = convInt(height);
|
|
for (int i = 0; i < 4; i++) { fileStream.WriteByte(mapHeight[i]); }
|
|
|
|
for (int z = 0; z < height; z++)
|
|
{
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
bool collision = false;
|
|
Terrain terrain = Misc.GetClosestCurrentTerrain(new Vector3(x, 0, z));
|
|
float terrainHeight = terrain.SampleHeight(new Vector3(x, 0, z)) - 0.1f;
|
|
float startingHeight = terrainHeight + 5.1f;
|
|
float distance = Mathf.Abs(startingHeight - terrainHeight);
|
|
Vector3 rayOrigin = new Vector3(x + 0.5f, startingHeight, z + 0.5f);
|
|
Ray ray = new Ray(rayOrigin, Vector3.down);
|
|
|
|
int ignoredLayers = LayerMask.GetMask("Ignore Raycast", "Water", "BlockPlayer");
|
|
int hitCount = Physics.SphereCastNonAlloc(ray.origin, .5f, ray.direction, hits, distance, ~ignoredLayers);
|
|
|
|
if (hitCount > 0)
|
|
{
|
|
bool isClosestHitWithObject = false;
|
|
float closestDistance = float.PositiveInfinity;
|
|
for (int i = 0; i < hitCount; i++)
|
|
{
|
|
if (hits[i].distance < closestDistance)
|
|
{
|
|
isClosestHitWithObject = !hits[i].collider.TryGetComponent(out Terrain _);
|
|
closestDistance = hits[i].distance;
|
|
}
|
|
}
|
|
collision = isClosestHitWithObject;
|
|
}
|
|
|
|
byte[] value = convInt(collision ? 1 : 0);
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
fileStream.WriteByte(value[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
fileStream.Close();
|
|
|
|
Debug.Log("Task complete.");
|
|
}
|
|
|
|
|
|
|
|
|
|
//We don't need this anymore. -Thomas09- I've made a system
|
|
private void turnAllBoxCollidersIntoMesh()
|
|
{
|
|
Debug.ClearDeveloperConsole();
|
|
Debug.Log("Converting All Box Colliders into Mesh Colliders");
|
|
|
|
var gameObjectsWithBoxColliders = FindObjectsOfType<BoxCollider>();
|
|
for (int i = 0; i < gameObjectsWithBoxColliders.Length; i++)
|
|
{
|
|
var go = gameObjectsWithBoxColliders[i].gameObject;
|
|
var meshCollider = go.GetComponent<MeshCollider>();
|
|
|
|
//If an existing MeshCollider exists, just Destroy it
|
|
if (go.GetComponent<MeshCollider>() != null)
|
|
{
|
|
DestroyImmediate(meshCollider);
|
|
}
|
|
|
|
meshCollider = go.AddComponent<MeshCollider>();
|
|
var meshfilter = go.GetComponent<MeshFilter>();
|
|
if (meshfilter != null)
|
|
{
|
|
meshCollider.sharedMesh = meshfilter.sharedMesh;
|
|
}
|
|
DestroyImmediate(go.GetComponent<BoxCollider>());
|
|
}
|
|
}
|
|
|
|
private void generateObjectData()
|
|
{
|
|
Debug.ClearDeveloperConsole();
|
|
Debug.Log("Generate Object Data...");
|
|
|
|
//Get All GameObjects in Scene with World Object Type
|
|
var initialArray_1 = FindObjectsOfType<WorldObject>();
|
|
|
|
//Filter WorldObject gameobjects that has MeshColliders;
|
|
List<GameObject> initialArray_2 = new List<GameObject>();
|
|
for (int i = 0; i < initialArray_1.Length; i++)
|
|
{
|
|
var go = initialArray_1[i];
|
|
if (go.GetComponent<MeshCollider>() != null)
|
|
{
|
|
initialArray_2.Add(go.gameObject);
|
|
}
|
|
}
|
|
|
|
//Get All GameObjects in initialArray_2 with MeshFilter Component
|
|
List<MeshAndTransform> meshAndTransform = new List<MeshAndTransform>();
|
|
for (int i = 0; i < initialArray_2.Count; i++)
|
|
{
|
|
var meshfilter = initialArray_2[i].GetComponent<MeshFilter>();
|
|
if (meshfilter != null)
|
|
{
|
|
meshAndTransform.Add(new MeshAndTransform
|
|
{
|
|
Mesh = meshfilter.sharedMesh,
|
|
Transform = meshfilter.transform
|
|
});
|
|
}
|
|
}
|
|
|
|
List<ObjectsAndTilesData> objectsAndTiles = new List<ObjectsAndTilesData>();
|
|
|
|
for (int i = 0; i < meshAndTransform.Count; i++)
|
|
{
|
|
List<Vector3> vertices = meshAndTransform[i].Mesh.vertices.ToList();
|
|
var transform = meshAndTransform[i].Transform;
|
|
HashSet<Vector2> overlapHashSet = new HashSet<Vector2>();
|
|
|
|
for (int j = 0; j < vertices.Count; j++)
|
|
{
|
|
var posV3 = transform.TransformPoint(vertices[j]);
|
|
var posX = posV3.x < 0 ? posV3.x - 1 : posV3.x;
|
|
var posY = posV3.z < 0 ? posV3.z - 1 : posV3.z;
|
|
overlapHashSet.Add(new Vector2((int)posX, (int)posY));
|
|
}
|
|
|
|
objectsAndTiles.Add(new ObjectsAndTilesData
|
|
{
|
|
GameObjectName = transform.gameObject.name,
|
|
OverlapHashSet = overlapHashSet
|
|
});
|
|
}
|
|
|
|
//Write it to file
|
|
using (FileStream fileStream = new FileStream("outputTileData.csv", FileMode.Create))
|
|
{
|
|
for (int i = 0; i < objectsAndTiles.Count; i++)
|
|
{
|
|
var name = objectsAndTiles[i].GameObjectName;
|
|
var overlaptiles = objectsAndTiles[i].OverlapHashSet.ToList();
|
|
var count = overlaptiles.Count;
|
|
string cov = name + ", " + count + ", ";
|
|
for (int j = 0; j < overlaptiles.Count; j++)
|
|
{
|
|
cov += overlaptiles[j].ToString();
|
|
if (j < overlaptiles.Count - 1)
|
|
{
|
|
cov += ", ";
|
|
}
|
|
}
|
|
if (i < objectsAndTiles.Count - 1)
|
|
{
|
|
cov += Environment.NewLine;
|
|
}
|
|
byte[] covByteArray = Encoding.Default.GetBytes(cov);
|
|
fileStream.Write(covByteArray, 0, covByteArray.Length);
|
|
}
|
|
fileStream.Close();
|
|
}
|
|
Debug.Log("Done! Check the root project folder! There should be a outputTileData.csv there!");
|
|
}
|
|
|
|
|
|
|
|
public byte[] convInt(int i)
|
|
{
|
|
byte[] b = new byte[4];
|
|
b[3] = (byte)i;
|
|
b[2] = (byte)(i >> 8);
|
|
b[1] = (byte)(i >> 16);
|
|
b[0] = (byte)(i >> 24);
|
|
return b;
|
|
}
|
|
|
|
public void generateNavigationHeightmap()
|
|
{
|
|
Debug.ClearDeveloperConsole();
|
|
Debug.Log("Generating Collision Maps.");
|
|
//find a reference to terrain for height checking
|
|
Terrain terrain = GameObject.Find("Terrain").GetComponent<Terrain>();
|
|
|
|
float[] navigationHeightData = new float[1024 * 1024];
|
|
|
|
//now loop through all tiles of the game
|
|
for (int i = 0; i < 1024; i++)
|
|
{
|
|
for (int j = 0; j < 1024; j++)
|
|
{
|
|
RaycastHit rch;
|
|
if (Physics.Raycast(new Vector3(j, terrain.SampleHeight(new Vector3(j, 0, i)) + 10.0f, i), new Vector3(0, -1.0f, 0), out rch, 20.0f))
|
|
{
|
|
navigationHeightData[i * 1024 + j] = rch.point.y;
|
|
}
|
|
}
|
|
}
|
|
|
|
//write world collision map to a png file
|
|
Texture2D texture = new Texture2D(1024, 1024, TextureFormat.RGB24, false); // create texture2D to store the map in, written to file at the end of the method
|
|
|
|
// set all pixels to black
|
|
for (int i = 0; i < 1024; i++)
|
|
{
|
|
for (int j = 0; j < 1024; j++)
|
|
{
|
|
Color c = Color.black;
|
|
c.r = navigationHeightData[i * 1024 + j] / 100.0f;
|
|
texture.SetPixel(j, i, c);
|
|
}
|
|
}
|
|
|
|
texture.Apply();
|
|
byte[] fileData = texture.EncodeToPNG();
|
|
System.IO.File.WriteAllBytes("NavigationHeightMap.png", fileData);
|
|
}
|
|
|
|
public void generateCollisionMap()
|
|
{
|
|
Debug.ClearDeveloperConsole();
|
|
Debug.Log("Generating Collision Maps.");
|
|
//find a reference to terrain for height checking
|
|
Terrain terrain;// = GameObject.Find("Terrain").GetComponent<Terrain>();
|
|
|
|
//create data for the map
|
|
bool[] collisionMapData = new bool[1024 * 1024];
|
|
for (int i = 0; i < collisionMapData.Length; i++) collisionMapData[i] = false;
|
|
|
|
//now loop through all tiles of the game
|
|
for (int i = 0; i < 1024; i++)
|
|
{
|
|
for (int j = 0; j < 1024; j++)
|
|
{
|
|
terrain = Misc.GetClosestCurrentTerrain(new Vector3(j, 0, i));
|
|
bool collision = false;
|
|
|
|
for (int y = 0; y < 10; y++)
|
|
{
|
|
for (int x = 0; x < 10; x++)
|
|
{
|
|
float rX = ((float)x / 10) + j + -0.5f;
|
|
float rZ = ((float)y / 10) + i + -0.5f;
|
|
float rY = terrain.SampleHeight(new Vector3(rX, 0, rZ)) - 0.05f;
|
|
Ray ray = new Ray(new Vector3(rX, rY, rZ), new Vector3(0, 1, 0));
|
|
RaycastHit rch;
|
|
if (Physics.Raycast(new Vector3(j, terrain.SampleHeight(new Vector3(j, 0, i)) + 10.0f, i), new Vector3(0, -1.0f, 0), out rch, 20.0f))
|
|
//if (Physics.Raycast(ray, 20.5f))
|
|
{
|
|
if (rch.collider.gameObject.GetComponent<WorldObject>() == null)
|
|
{
|
|
collision = true;
|
|
}
|
|
else if (rch.collider.gameObject.GetComponent<WorldObject>().canWalkOnTop == false)
|
|
{
|
|
collision = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (collision)
|
|
{
|
|
collisionMapData[i * 1024 + j] = true;
|
|
Debug.Log("Collision x:" + j + " y: " + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
//write world collision map to a png file
|
|
Texture2D texture = new Texture2D(1024, 1024, TextureFormat.RGB24, false); // create texture2D to store the map in, written to file at the end of the method
|
|
|
|
// set all pixels to black
|
|
for (int i = 0; i < 1024; i++)
|
|
{
|
|
for (int j = 0; j < 1024; j++)
|
|
{
|
|
Color c = Color.black;
|
|
if (collisionMapData[i * 1024 + j])
|
|
c = Color.red;
|
|
texture.SetPixel(j, i, c);
|
|
}
|
|
}
|
|
|
|
texture.Apply();
|
|
byte[] fileData = texture.EncodeToPNG();
|
|
System.IO.File.WriteAllBytes("collisionMap.png", fileData);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#endif |