OctoCore 0.0.1
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e212b1c0974558f40ac2ccaa96db495d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for ceiling tiles.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Ceiling_", menuName = "Octo/Level Builder/Ceiling")]
|
||||
public class OctoLevelBuilderCeilingData : OctoLevelBuilderData
|
||||
{
|
||||
public GameObject Prefab;
|
||||
|
||||
public override GameObject GetPrefab(int angle, WallShape shape = WallShape.Straight)
|
||||
{
|
||||
return Prefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 663b230d0aa40fb448ac219c0c7d57f6
|
||||
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for tile data.
|
||||
/// </summary>
|
||||
public abstract class OctoLevelBuilderData : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The referenece grid for the tile.
|
||||
/// </summary>
|
||||
public OctoLevelBuilderGridData Grid;
|
||||
|
||||
/// <summary>
|
||||
/// Get the prefab to instantiate for this tile configuration.
|
||||
/// </summary>
|
||||
public abstract GameObject GetPrefab(int angle, WallShape shape = WallShape.Straight);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8ed7c7ac825b7e49aa3695b5393da29
|
||||
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for fence tiles.
|
||||
/// Similar to walls but typically lower and more decorative.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Fence_", menuName = "Octo/Level Builder/Fence")]
|
||||
public class OctoLevelBuilderFenceData : OctoLevelBuilderData
|
||||
{
|
||||
[Header("Fence Prefabs")]
|
||||
public GameObject FenceStraight;
|
||||
public GameObject FenceCorner;
|
||||
public GameObject FenceT;
|
||||
public GameObject FenceDeadEnd;
|
||||
|
||||
public override GameObject GetPrefab(int angle, WallShape shape = WallShape.Straight)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
WallShape.Straight => FenceStraight,
|
||||
WallShape.Corner => FenceCorner,
|
||||
WallShape.T => FenceT,
|
||||
WallShape.DeadEnd => FenceDeadEnd,
|
||||
_ => FenceStraight
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d87d7d32e3833944be2a3972446de25
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for floor tiles.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Floor_", menuName = "Octo/Level Builder/Floor")]
|
||||
public class OctoLevelBuilderFloorData : OctoLevelBuilderData
|
||||
{
|
||||
public GameObject Prefab;
|
||||
|
||||
public override GameObject GetPrefab(int angle, WallShape shape = WallShape.Straight)
|
||||
{
|
||||
return Prefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8e08d3fd3a3b694da03a093f5b375cf
|
||||
@@ -0,0 +1,21 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for grid data.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Grid_", menuName = "Octo/Level Builder/Grid")]
|
||||
public class OctoLevelBuilderGridData : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Width en depth of a tile.
|
||||
/// </summary>
|
||||
public float TileSize = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// Floor height.
|
||||
/// </summary>
|
||||
public float FloorHeight = 3.5f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b13c2498f7c6bd499d3dc1815e1758d
|
||||
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for stairs tiles.
|
||||
/// Connects two floor levels.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Stairs_", menuName = "Octo/Level Builder/Stairs")]
|
||||
public class OctoLevelBuilderStairsData : OctoLevelBuilderData
|
||||
{
|
||||
[Header("Stairs Prefab")]
|
||||
public GameObject StairsPrefab;
|
||||
|
||||
public override GameObject GetPrefab(int angle, WallShape shape = WallShape.Straight)
|
||||
{
|
||||
return StairsPrefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77641830072b3944882267f440086535
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for grid data.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Style_", menuName = "Octo/Level Builder/Style")]
|
||||
public class OctoLevelBuilderStyleData : ScriptableObject
|
||||
{
|
||||
public OctoLevelBuilderGridData Grid;
|
||||
public OctoLevelBuilderCeilingData Ceiling;
|
||||
public OctoLevelBuilderWallData Wall;
|
||||
public OctoLevelBuilderFloorData Floor;
|
||||
public OctoLevelBuilderStairsData Stairs;
|
||||
public OctoLevelBuilderFenceData Fence;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0d5c998a010b2243b41c3eb69285ff5
|
||||
@@ -0,0 +1,36 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for wall tiles.
|
||||
/// Supports different shapes: straight, corner, T-junction, cross, dead-end, door, window.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "Wall_", menuName = "Octo/Level Builder/Wall")]
|
||||
public class OctoLevelBuilderWallData : OctoLevelBuilderData
|
||||
{
|
||||
[Header("Wall Prefabs")]
|
||||
public GameObject WallStraight;
|
||||
public GameObject WallCorner;
|
||||
public GameObject WallT;
|
||||
public GameObject WallCross;
|
||||
public GameObject WallDeadEnd;
|
||||
public GameObject WallDoor;
|
||||
public GameObject WallWindow;
|
||||
|
||||
public override GameObject GetPrefab(int angle, WallShape shape = WallShape.Straight)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
WallShape.Straight => WallStraight,
|
||||
WallShape.Corner => WallCorner,
|
||||
WallShape.T => WallT,
|
||||
WallShape.Cross => WallCross,
|
||||
WallShape.DeadEnd => WallDeadEnd,
|
||||
WallShape.Door => WallDoor,
|
||||
WallShape.Window => WallWindow,
|
||||
_ => WallStraight
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5eb6603754edde4f85b7713df5381a4
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
public enum TileType
|
||||
{
|
||||
Wall,
|
||||
Floor,
|
||||
Stairs,
|
||||
Fence
|
||||
}
|
||||
|
||||
public enum WallShape
|
||||
{
|
||||
Straight,
|
||||
Corner,
|
||||
T,
|
||||
Cross,
|
||||
DeadEnd,
|
||||
Door,
|
||||
Window
|
||||
}
|
||||
|
||||
public enum WallType
|
||||
{
|
||||
Wall,
|
||||
Door,
|
||||
Window,
|
||||
Fence
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d4bac6e1a95c924db7e2c026cc28e70
|
||||
@@ -0,0 +1,337 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class OctoLevelBuilderMap : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
private class MapRow
|
||||
{
|
||||
public OctoLevelBuilderTile[] Rows;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class MapColumn
|
||||
{
|
||||
public MapRow[] Columns;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Map
|
||||
{
|
||||
private bool _isMapUpToDate;
|
||||
[SerializeField] private Vector3Int _minBounds;
|
||||
[SerializeField] private Vector3Int _maxBounds;
|
||||
[SerializeField] private Transform _tilesRoot;
|
||||
[SerializeField] private List<OctoLevelBuilderTile> _tiles = new List<OctoLevelBuilderTile>();
|
||||
private List<OctoLevelBuilderTile> _tilesToRefresh = new List<OctoLevelBuilderTile>();
|
||||
[SerializeField] private MapColumn[] _floors = new MapColumn[0];
|
||||
|
||||
public Transform TilesRoot => _tilesRoot;
|
||||
public OctoLevelBuilderTile[] Tiles => _tiles.ToArray();
|
||||
|
||||
public void SetTilesRoot(Transform tilesRoot)
|
||||
{
|
||||
_tilesRoot = tilesRoot;
|
||||
}
|
||||
|
||||
public void RequireMapRefresh()
|
||||
{
|
||||
_isMapUpToDate = false;
|
||||
}
|
||||
|
||||
public void RequireTileRefresh(OctoLevelBuilderTile tile)
|
||||
{
|
||||
if (tile && !_tilesToRefresh.Contains(tile))
|
||||
_tilesToRefresh.Add(tile);
|
||||
}
|
||||
|
||||
public void AddTile(OctoLevelBuilderTile tile)
|
||||
{
|
||||
if (!_tiles.Contains(tile))
|
||||
{
|
||||
_tiles.Add(tile);
|
||||
RequireMapRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveTile(OctoLevelBuilderTile tile)
|
||||
{
|
||||
if (_tiles.Contains(tile))
|
||||
{
|
||||
_tiles.Remove(tile);
|
||||
RequireMapRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
public OctoLevelBuilderTile GetTile(Vector3Int position)
|
||||
{
|
||||
Vector3Int p = position - _minBounds;
|
||||
|
||||
if (p.y < 0 || p.y >= _floors.Length)
|
||||
return null;
|
||||
|
||||
if (p.z < 0 || p.z >= _floors[p.y].Columns.Length)
|
||||
return null;
|
||||
|
||||
if (p.x < 0 || p.x >= _floors[p.y].Columns[p.z].Rows.Length)
|
||||
return null;
|
||||
|
||||
return _floors[p.y].Columns[p.z].Rows[p.x];
|
||||
}
|
||||
|
||||
public void RefreshMap(string name)
|
||||
{
|
||||
if (_isMapUpToDate)
|
||||
return;
|
||||
|
||||
_minBounds = new Vector3Int(int.MaxValue, int.MaxValue, int.MaxValue);
|
||||
_maxBounds = new Vector3Int(int.MinValue, int.MinValue, int.MinValue);
|
||||
|
||||
// Get map bounds
|
||||
|
||||
foreach (OctoLevelBuilderTile tile in _tiles)
|
||||
{
|
||||
Vector3Int p = tile.GetCoordinates(true);
|
||||
|
||||
if (p.x < _minBounds.x)
|
||||
_minBounds.x = p.x;
|
||||
if (p.x > _maxBounds.x)
|
||||
_maxBounds.x = p.x;
|
||||
if (p.y < _minBounds.y)
|
||||
_minBounds.y = p.y;
|
||||
if (p.y > _maxBounds.y)
|
||||
_maxBounds.y = p.y;
|
||||
if (p.z < _minBounds.z)
|
||||
_minBounds.z = p.z;
|
||||
if (p.z > _maxBounds.z)
|
||||
_maxBounds.z = p.z;
|
||||
}
|
||||
|
||||
// Copy previous map
|
||||
|
||||
MapColumn[] previousFloors = new MapColumn[_floors.Length];
|
||||
|
||||
for (int y = 0; y < previousFloors.Length; y++)
|
||||
{
|
||||
previousFloors[y] = new MapColumn();
|
||||
previousFloors[y].Columns = new MapRow[_floors[y].Columns.Length];
|
||||
|
||||
for (int z = 0; z < previousFloors[y].Columns.Length; z++)
|
||||
{
|
||||
previousFloors[y].Columns[z] = new MapRow();
|
||||
previousFloors[y].Columns[z].Rows = new OctoLevelBuilderTile[_floors[y].Columns[z].Rows.Length];
|
||||
|
||||
for (int x = 0; x < previousFloors[y].Columns[z].Rows.Length; x++)
|
||||
previousFloors[y].Columns[z].Rows[x] = _floors[y].Columns[z].Rows[x];
|
||||
}
|
||||
}
|
||||
|
||||
// Init map
|
||||
|
||||
Vector3Int size = _maxBounds - _minBounds + Vector3Int.one;
|
||||
_floors = new MapColumn[size.y];
|
||||
|
||||
for (int y = 0; y < size.y; y++)
|
||||
{
|
||||
_floors[y] = new MapColumn();
|
||||
_floors[y].Columns = new MapRow[size.z];
|
||||
|
||||
for (int z = 0; z < size.z; z++)
|
||||
{
|
||||
_floors[y].Columns[z] = new MapRow();
|
||||
_floors[y].Columns[z].Rows = new OctoLevelBuilderTile[size.x];
|
||||
}
|
||||
}
|
||||
|
||||
// Assing tiles to the map
|
||||
|
||||
foreach (OctoLevelBuilderTile tile in _tiles)
|
||||
{
|
||||
Vector3Int p = tile.GetCoordinates(true) - _minBounds;
|
||||
|
||||
_floors[p.y].Columns[p.z].Rows[p.x] = tile;
|
||||
}
|
||||
|
||||
// Refresh tiles
|
||||
|
||||
for (int y = 0; y < size.y; y++)
|
||||
{
|
||||
for (int z = 0; z < size.z; z++)
|
||||
{
|
||||
for (int x = 0; x < size.x; x++)
|
||||
{
|
||||
OctoLevelBuilderTile tile = _floors[y].Columns[z].Rows[x];
|
||||
|
||||
if (tile)
|
||||
{
|
||||
bool refreshTile = !tile.IsUpToDate;
|
||||
|
||||
if (!refreshTile)
|
||||
{
|
||||
OctoLevelBuilderTile previousTile = null;
|
||||
if (previousFloors.Length > y && previousFloors[y].Columns.Length > z && previousFloors[y].Columns[z].Rows.Length > x)
|
||||
previousTile = previousFloors[y].Columns[z].Rows[x];
|
||||
|
||||
refreshTile = tile != previousTile;
|
||||
}
|
||||
|
||||
if (refreshTile)
|
||||
{
|
||||
RequireTileRefresh(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isMapUpToDate = true;
|
||||
Debug.Log($"[OctoLevelGrid] {name}: Updated");
|
||||
}
|
||||
|
||||
public void RefreshTiles()
|
||||
{
|
||||
if (_tilesToRefresh.Count == 0)
|
||||
return;
|
||||
|
||||
OctoLevelBuilderTile[] _tmpTilesToRefresh = _tilesToRefresh.ToArray();
|
||||
_tilesToRefresh.Clear();
|
||||
|
||||
foreach (OctoLevelBuilderTile tile in _tmpTilesToRefresh)
|
||||
if (tile)
|
||||
tile.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public static float DEFAULT_TILE_SIZE = 2f;
|
||||
public static float DEFAULT_FLOOR_HEIGHT = 3.5f;
|
||||
|
||||
[SerializeField] private OctoLevelBuilderStyleData _defaultStyle;
|
||||
[SerializeField, OctoReadOnly] private Map _map;
|
||||
|
||||
public OctoLevelBuilderStyleData DefaultStyle => _defaultStyle;
|
||||
public OctoLevelBuilderGridData Grid => DefaultStyle ? DefaultStyle.Grid : null;
|
||||
public float TileSize => Grid ? Grid.TileSize : DEFAULT_TILE_SIZE;
|
||||
public float FloorHeight => Grid ? Grid.FloorHeight : DEFAULT_FLOOR_HEIGHT;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
return;
|
||||
|
||||
_map.RefreshTiles();
|
||||
_map.RefreshMap(name);
|
||||
}
|
||||
|
||||
public void SetLayer(string layer)
|
||||
{
|
||||
LayerMask layerMask = LayerMask.NameToLayer(layer);
|
||||
SetLayerRecursively(gameObject, layerMask);
|
||||
}
|
||||
|
||||
public void RegisterTile(OctoLevelBuilderTile tile)
|
||||
{
|
||||
if (tile == null)
|
||||
return;
|
||||
|
||||
_map.AddTile(tile);
|
||||
}
|
||||
|
||||
public void UnregisterTile(OctoLevelBuilderTile tile)
|
||||
{
|
||||
if (tile == null)
|
||||
return;
|
||||
|
||||
_map.RemoveTile(tile);
|
||||
}
|
||||
|
||||
public void RequireMapRefresh()
|
||||
{
|
||||
_map.RequireMapRefresh();
|
||||
}
|
||||
|
||||
public void RequireTileRefresh(OctoLevelBuilderTile tile)
|
||||
{
|
||||
if (tile)
|
||||
_map.RequireTileRefresh(tile);
|
||||
}
|
||||
|
||||
public bool GetTile(Vector3Int gridPosition, out OctoLevelBuilderTile tile)
|
||||
{
|
||||
tile = _map.GetTile(gridPosition);
|
||||
return tile;
|
||||
}
|
||||
|
||||
public Vector3 GridToWorld(Vector3Int gridPosition)
|
||||
{
|
||||
return new Vector3(
|
||||
gridPosition.x * TileSize,
|
||||
gridPosition.y * FloorHeight,
|
||||
gridPosition.z * TileSize
|
||||
);
|
||||
}
|
||||
|
||||
public Vector3Int WorldToGrid(Vector3 worldPosition, int floorLevel)
|
||||
{
|
||||
return new Vector3Int(
|
||||
Mathf.RoundToInt(worldPosition.x / TileSize),
|
||||
floorLevel,
|
||||
Mathf.RoundToInt(worldPosition.z / TileSize)
|
||||
);
|
||||
}
|
||||
|
||||
[ContextMenu("GenerateMap (5x5)")] public void GenerateMap5x5() { GenerateMap(new Vector3Int(5, 1, 5)); }
|
||||
[ContextMenu("GenerateMap (7x7)")] public void GenerateMap7x7() { GenerateMap(new Vector3Int(7, 1, 7)); }
|
||||
[ContextMenu("GenerateMap (9x9)")] public void GenerateMap9x9() { GenerateMap(new Vector3Int(9, 1, 9)); }
|
||||
public void GenerateMap(Vector3Int size)
|
||||
{
|
||||
if (!_map.TilesRoot)
|
||||
{
|
||||
GameObject tilesRoot = new GameObject("Tiles");
|
||||
tilesRoot.transform.parent = transform;
|
||||
|
||||
_map.SetTilesRoot(tilesRoot.transform);
|
||||
}
|
||||
|
||||
int xMin = size.x / -2;
|
||||
int yMin = size.y / -2;
|
||||
int zMin = size.z / -2;
|
||||
|
||||
int xMax = xMin + size.x;
|
||||
int yMax = yMin + size.y;
|
||||
int zMax = zMin + size.z;
|
||||
|
||||
for (int y = yMin; y < yMax; y++)
|
||||
{
|
||||
for (int z = zMin; z < zMax; z++)
|
||||
{
|
||||
for (int x = xMin; x < xMax; x++)
|
||||
{
|
||||
GameObject tileObj = new GameObject();
|
||||
tileObj.transform.parent = _map.TilesRoot;
|
||||
tileObj.transform.localPosition = new Vector3(x * TileSize, y * FloorHeight, z * TileSize);
|
||||
|
||||
OctoLevelBuilderTile tile = tileObj.AddComponent<OctoLevelBuilderTile>();
|
||||
tile.Init(x == xMin || x == xMax - 1 || z == zMin || z == zMax - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("[OctoLevelBluiderMap] Map generated");
|
||||
}
|
||||
|
||||
private void SetLayerRecursively(GameObject obj, int newLayer)
|
||||
{
|
||||
obj.layer = newLayer;
|
||||
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
SetLayerRecursively(child.gameObject, newLayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 078c608cc8fc63b40beb970edf317e56
|
||||
@@ -0,0 +1,614 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.LevelBuilder
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class OctoLevelBuilderTile : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
private class Configuration
|
||||
{
|
||||
public OctoLevelBuilderStyleData _overrideStyle;
|
||||
public bool Ceiling;
|
||||
public bool Wall;
|
||||
public bool Floor;
|
||||
public bool Stairs;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class References
|
||||
{
|
||||
[OctoReadOnly] public OctoLevelBuilderMap Map;
|
||||
[OctoReadOnly] public GameObject CeilingInstance;
|
||||
[OctoReadOnly] public GameObject WallInstance;
|
||||
[OctoReadOnly] public GameObject FloorInstance;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class WallConnections
|
||||
{
|
||||
public OctoLevelBuilderTile North;
|
||||
public OctoLevelBuilderTile Est;
|
||||
public OctoLevelBuilderTile South;
|
||||
public OctoLevelBuilderTile West;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class WallConfiguration
|
||||
{
|
||||
public bool AutoConnect = true;
|
||||
[Range(0, 3)] public int Orientation = 0;
|
||||
public WallType Type = WallType.Wall;
|
||||
public WallShape Shape = WallShape.Straight;
|
||||
[OctoReadOnly] public WallConnections Connections = new WallConnections();
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class Infos
|
||||
{
|
||||
public Vector3Int Coordinates;
|
||||
public Vector3 Position;
|
||||
}
|
||||
|
||||
[SerializeField] private Configuration _configuration = new Configuration();
|
||||
[SerializeField] private WallConfiguration _wall = new WallConfiguration();
|
||||
[SerializeField] private References _references = new References();
|
||||
[SerializeField, OctoReadOnly] private Infos _infos = new Infos();
|
||||
|
||||
private bool _isMapUpToDate;
|
||||
|
||||
public bool IsUpToDate => _isMapUpToDate;
|
||||
public bool HasWall => _configuration.Wall;
|
||||
public bool HasFloor => _configuration.Floor;
|
||||
public bool HasCeiling => _configuration.Ceiling;
|
||||
public bool HasStairs => _configuration.Stairs;
|
||||
public float TileSize => Map ? Map.TileSize : OctoLevelBuilderMap.DEFAULT_TILE_SIZE;
|
||||
public float FloorHeight => Map ? Map.FloorHeight : OctoLevelBuilderMap.DEFAULT_FLOOR_HEIGHT;
|
||||
public OctoLevelBuilderMap Map => _references.Map;
|
||||
public OctoLevelBuilderStyleData Style => _configuration._overrideStyle ? _configuration._overrideStyle : _references.Map ? _references.Map.DefaultStyle : null;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnValidate()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (this != null)
|
||||
RequireMapRefresh();
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
RegisterToMap();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnregisterFromMap();
|
||||
//DestroyInstance(_wallInstance);
|
||||
//DestroyInstance(_floorInstance);
|
||||
//DestroyInstance(_ceilingInstance);
|
||||
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.North);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.Est);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.South);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.West);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
DrawTileGizmo(new Color(0, 1, 0, 0.2f));
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
DrawTileGizmo(new Color(0, 1, 0, 0.5f));
|
||||
}
|
||||
|
||||
private void DrawTileGizmo(Color color)
|
||||
{
|
||||
float tileSize = Map ? Map.TileSize : 2;
|
||||
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawCube(Vector3.up * tileSize * .025f, new Vector3(tileSize * .2f, tileSize * .05f, tileSize * .2f));
|
||||
|
||||
/*if (!HasWall())
|
||||
{
|
||||
Gizmos.color = color;
|
||||
Gizmos.DrawCube(transform.position + Vector3.up * 0.5f, new Vector3(1.8f, 1f, 1.8f));
|
||||
return;
|
||||
}
|
||||
|
||||
float rotation = Placement.Angle * -90f;
|
||||
if (Wall.Shape == WallShape.Straight)
|
||||
rotation += 90f;
|
||||
|
||||
Matrix4x4 oldMatrix = Gizmos.matrix;
|
||||
Gizmos.matrix = Matrix4x4.TRS(transform.position + Vector3.up * 1.5f, Quaternion.Euler(0, rotation, 0), Vector3.one);
|
||||
Gizmos.color = color;
|
||||
|
||||
float size = 2f;
|
||||
float thickness = 0.3f;
|
||||
float height = 3f;
|
||||
|
||||
switch (Wall.Shape)
|
||||
{
|
||||
case WallShape.Straight:
|
||||
Gizmos.DrawCube(Vector3.zero, new Vector3(size, height, thickness));
|
||||
break;
|
||||
|
||||
case WallShape.Corner:
|
||||
Vector3 arm1Pos = new Vector3(size / 4f, 0, 0);
|
||||
Vector3 arm2Pos = new Vector3(0, 0, size / 4f);
|
||||
Gizmos.DrawCube(arm1Pos, new Vector3(size / 2f, height, thickness));
|
||||
Gizmos.DrawCube(arm2Pos, new Vector3(thickness, height, size / 2f));
|
||||
break;
|
||||
|
||||
case WallShape.T:
|
||||
Vector3 basePos = new Vector3(0, 0, 0);
|
||||
Vector3 crossPos = new Vector3(0, 0, size / 4f);
|
||||
Gizmos.DrawCube(basePos, new Vector3(size, height, thickness));
|
||||
Gizmos.DrawCube(crossPos, new Vector3(thickness, height, size / 2f));
|
||||
break;
|
||||
|
||||
case WallShape.Cross:
|
||||
Gizmos.DrawCube(Vector3.zero, new Vector3(size, height, thickness));
|
||||
Gizmos.DrawCube(Vector3.zero, new Vector3(thickness, height, size));
|
||||
break;
|
||||
|
||||
case WallShape.DeadEnd:
|
||||
Vector3 deadEndPos = new Vector3(0, 0, size / 4f);
|
||||
Gizmos.DrawCube(deadEndPos, new Vector3(thickness, height, size / 2f));
|
||||
break;
|
||||
|
||||
case WallShape.Door:
|
||||
case WallShape.Window:
|
||||
Gizmos.DrawCube(Vector3.zero, new Vector3(size, height, thickness));
|
||||
break;
|
||||
|
||||
default:
|
||||
Gizmos.DrawCube(Vector3.zero, new Vector3(size * 0.5f, height, size * 0.5f));
|
||||
break;
|
||||
}
|
||||
|
||||
Gizmos.matrix = oldMatrix;*/
|
||||
}
|
||||
#endif
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_infos.Position != transform.localPosition)
|
||||
{
|
||||
_infos.Position = transform.localPosition;
|
||||
|
||||
SetName();
|
||||
RequireMapRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Init(bool wall)
|
||||
{
|
||||
Debug.Log(wall);
|
||||
SetName();
|
||||
|
||||
_configuration.Ceiling = true;
|
||||
_configuration.Wall = wall;
|
||||
_configuration.Floor = true;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
SetConnections();
|
||||
ClearChildren();
|
||||
RefreshWall();
|
||||
RefreshFloor();
|
||||
RefreshCeiling();
|
||||
|
||||
_isMapUpToDate = true;
|
||||
//Debug.Log($"[OctoTile] {name}: Updated");
|
||||
}
|
||||
|
||||
public Vector3Int GetCoordinates(bool update = false)
|
||||
{
|
||||
if (update)
|
||||
SetCoordinates();
|
||||
|
||||
return _infos.Coordinates;
|
||||
}
|
||||
|
||||
private void SetCoordinates()
|
||||
{
|
||||
Vector3 pos = transform.position;
|
||||
|
||||
_infos.Coordinates = new Vector3Int(
|
||||
Mathf.RoundToInt(pos.x / TileSize),
|
||||
Mathf.RoundToInt(pos.y / FloorHeight),
|
||||
Mathf.RoundToInt(pos.z / TileSize)
|
||||
);
|
||||
}
|
||||
|
||||
public void SetConnections()
|
||||
{
|
||||
GetMap();
|
||||
if (!_references.Map)
|
||||
return;
|
||||
|
||||
// Require update for previous connections
|
||||
|
||||
OctoLevelBuilderTile previousNorth = _wall.Connections.North;
|
||||
OctoLevelBuilderTile previousEst = _wall.Connections.Est;
|
||||
OctoLevelBuilderTile previousSouth = _wall.Connections.South;
|
||||
OctoLevelBuilderTile previousWest = _wall.Connections.West;
|
||||
|
||||
// Get new connections
|
||||
|
||||
OctoLevelBuilderTile newNorth = GetNextTile(Vector3Int.forward);
|
||||
OctoLevelBuilderTile newEst = GetNextTile(Vector3Int.right );
|
||||
OctoLevelBuilderTile newSouth = GetNextTile(Vector3Int.back );
|
||||
OctoLevelBuilderTile newWest = GetNextTile(Vector3Int.left );
|
||||
|
||||
_wall.Connections.North = newNorth && newNorth.HasWall ? newNorth : null;
|
||||
_wall.Connections.Est = newEst && newEst .HasWall ? newEst : null;
|
||||
_wall.Connections.South = newSouth && newSouth.HasWall ? newSouth : null;
|
||||
_wall.Connections.West = newWest && newWest .HasWall ? newWest : null;
|
||||
|
||||
bool wallChanged = HasWall != (_references.WallInstance ? true : false);
|
||||
|
||||
// Require update for new connections
|
||||
|
||||
if (_wall.Connections.North != previousNorth || wallChanged)
|
||||
{
|
||||
Debug.Log(_wall.Connections.North);
|
||||
Debug.Log(previousNorth);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.North);
|
||||
_references.Map.RequireTileRefresh(previousNorth);
|
||||
}
|
||||
if (_wall.Connections.Est != previousEst || wallChanged)
|
||||
{
|
||||
Debug.Log(_wall.Connections.Est);
|
||||
Debug.Log(previousEst);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.Est);
|
||||
_references.Map.RequireTileRefresh(previousEst);
|
||||
}
|
||||
if (_wall.Connections.South != previousSouth || wallChanged)
|
||||
{
|
||||
Debug.Log(_wall.Connections.South);
|
||||
Debug.Log(previousSouth);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.South);
|
||||
_references.Map.RequireTileRefresh(previousSouth);
|
||||
}
|
||||
if (_wall.Connections.West != previousWest || wallChanged)
|
||||
{
|
||||
Debug.Log(_wall.Connections.West);
|
||||
Debug.Log(previousWest);
|
||||
_references.Map.RequireTileRefresh(_wall.Connections.West);
|
||||
_references.Map.RequireTileRefresh(previousWest);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshShape()
|
||||
{
|
||||
if (!HasWall || !_wall.AutoConnect)
|
||||
return;
|
||||
|
||||
int connectionHash = (_wall.Connections.North ? 1000 : 0) + (_wall.Connections.Est ? 100 : 0) + (_wall.Connections.South ? 10 : 0) + (_wall.Connections.West ? 1 : 0);
|
||||
int connectionCount = (_wall.Connections.North ? 1 : 0) + (_wall.Connections.Est ? 1 : 0) + (_wall.Connections.South ? 1 : 0) + (_wall.Connections.West ? 1 : 0);
|
||||
|
||||
switch (connectionCount)
|
||||
{
|
||||
default:
|
||||
_wall.Shape = WallShape.DeadEnd;
|
||||
switch(connectionHash)
|
||||
{
|
||||
case 0010:
|
||||
_wall.Orientation = 0;
|
||||
break;
|
||||
case 0001:
|
||||
_wall.Orientation = 1;
|
||||
break;
|
||||
case 1000:
|
||||
_wall.Orientation = 2;
|
||||
break;
|
||||
case 0100:
|
||||
_wall.Orientation = 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ((_wall.Connections.North && _wall.Connections.South) || (_wall.Connections.Est && _wall.Connections.West))
|
||||
{
|
||||
_wall.Shape = WallShape.Straight;
|
||||
switch (connectionHash)
|
||||
{
|
||||
case 0101:
|
||||
_wall.Orientation = 0;
|
||||
break;
|
||||
case 1010:
|
||||
_wall.Orientation = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_wall.Shape = WallShape.Corner;
|
||||
switch (connectionHash)
|
||||
{
|
||||
case 1001:
|
||||
_wall.Orientation = 0;
|
||||
break;
|
||||
case 1100:
|
||||
_wall.Orientation = 1;
|
||||
break;
|
||||
case 0110:
|
||||
_wall.Orientation = 2;
|
||||
break;
|
||||
case 0011:
|
||||
_wall.Orientation = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_wall.Shape = WallShape.T;
|
||||
switch (connectionHash)
|
||||
{
|
||||
case 1101:
|
||||
_wall.Orientation = 0;
|
||||
break;
|
||||
case 1110:
|
||||
_wall.Orientation = 1;
|
||||
break;
|
||||
case 0111:
|
||||
_wall.Orientation = 2;
|
||||
break;
|
||||
case 1011:
|
||||
_wall.Orientation = 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
_wall.Shape = WallShape.Cross;
|
||||
_wall.Orientation = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private OctoLevelBuilderTile GetNextTile(Vector3Int direction)
|
||||
{
|
||||
Vector3Int nextCoordinates = _infos.Coordinates + direction;
|
||||
|
||||
if (!_references.Map)
|
||||
{
|
||||
Debug.LogWarning("[OctoTile] No Map found");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_references.Map.GetTile(nextCoordinates, out OctoLevelBuilderTile nexTile))
|
||||
return nexTile;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ClearChildren()
|
||||
{
|
||||
for (int i = transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
GameObject instance = transform.GetChild(i).gameObject;
|
||||
|
||||
if (instance != _references.CeilingInstance &&
|
||||
instance != _references.WallInstance &&
|
||||
instance != _references.FloorInstance)
|
||||
{
|
||||
DestroyInstance(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshWall()
|
||||
{
|
||||
if (!HasWall)
|
||||
{
|
||||
DestroyInstance(_references.WallInstance);
|
||||
_references.WallInstance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshShape();
|
||||
|
||||
if (!Style)
|
||||
return;
|
||||
|
||||
GameObject prefab = GetWallPrefab(Style.Wall, _wall.Shape, _wall.Type);
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
DestroyInstance(_references.WallInstance);
|
||||
_references.WallInstance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsInstanceCorrespondingToPrefab(_references.WallInstance, prefab))
|
||||
{
|
||||
DestroyInstance(_references.WallInstance);
|
||||
_references.WallInstance = InstantiatePrefab(prefab, "Wall");
|
||||
}
|
||||
|
||||
if (_references.WallInstance != null)
|
||||
{
|
||||
float angle = _wall.Orientation * 90f;
|
||||
_references.WallInstance.transform.localRotation = Quaternion.Euler(0, angle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private GameObject GetWallPrefab(OctoLevelBuilderWallData wallData, WallShape shape, WallType type)
|
||||
{
|
||||
if (type == WallType.Door)
|
||||
return wallData.WallDoor;
|
||||
if (type == WallType.Window)
|
||||
return wallData.WallWindow;
|
||||
|
||||
return wallData.GetPrefab(_wall.Orientation, shape);
|
||||
}
|
||||
|
||||
private void RefreshFloor()
|
||||
{
|
||||
if (!HasFloor)
|
||||
{
|
||||
DestroyInstance(_references.FloorInstance);
|
||||
_references.FloorInstance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Style)
|
||||
return;
|
||||
|
||||
GameObject prefab = Style.Floor.Prefab;
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
DestroyInstance(_references.FloorInstance);
|
||||
_references.FloorInstance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsInstanceCorrespondingToPrefab(_references.FloorInstance, prefab))
|
||||
{
|
||||
DestroyInstance(_references.FloorInstance);
|
||||
_references.FloorInstance = InstantiatePrefab(prefab, "Floor");
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshCeiling()
|
||||
{
|
||||
if (!HasCeiling)
|
||||
{
|
||||
DestroyInstance(_references.CeilingInstance);
|
||||
_references.CeilingInstance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Style)
|
||||
return;
|
||||
|
||||
GameObject prefab = Style.Ceiling.Prefab;
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
DestroyInstance(_references.CeilingInstance);
|
||||
_references.CeilingInstance = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsInstanceCorrespondingToPrefab(_references.CeilingInstance, prefab))
|
||||
{
|
||||
DestroyInstance(_references.CeilingInstance);
|
||||
_references.CeilingInstance = InstantiatePrefab(prefab, "Ceiling");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsInstanceCorrespondingToPrefab(GameObject instance, GameObject prefab)
|
||||
{
|
||||
if (instance == null)
|
||||
return true;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
GameObject source = (GameObject)UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(instance);
|
||||
return source != prefab;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void DestroyInstance(GameObject instance)
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
DestroyImmediate(instance);
|
||||
else
|
||||
#endif
|
||||
Destroy(instance);
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
private GameObject InstantiatePrefab(GameObject prefab, string childName)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
GameObject instance = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab(prefab, transform);
|
||||
SceneVisibilityManager.instance.DisablePicking(instance, true);
|
||||
#else
|
||||
GameObject instance = Instantiate(prefab, transform);
|
||||
#endif
|
||||
instance.name = childName;
|
||||
instance.transform.localPosition = Vector3.zero;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void GetMap()
|
||||
{
|
||||
if (!_references.Map)
|
||||
_references.Map = GetComponentInParent<OctoLevelBuilderMap>();
|
||||
}
|
||||
|
||||
private bool GetMap(out OctoLevelBuilderMap map)
|
||||
{
|
||||
GetMap();
|
||||
map = _references.Map;
|
||||
return map;
|
||||
}
|
||||
|
||||
private void RequireMapRefresh()
|
||||
{
|
||||
_isMapUpToDate = false;
|
||||
if (GetMap(out OctoLevelBuilderMap map))
|
||||
map.RequireMapRefresh();
|
||||
}
|
||||
|
||||
private void RegisterToMap()
|
||||
{
|
||||
if (GetMap(out OctoLevelBuilderMap map))
|
||||
map.RegisterTile(this);
|
||||
}
|
||||
|
||||
private void UnregisterFromMap()
|
||||
{
|
||||
if (GetMap(out OctoLevelBuilderMap map))
|
||||
map.UnregisterTile(this);
|
||||
}
|
||||
|
||||
private void SetName()
|
||||
{
|
||||
int x = _infos.Coordinates.x;
|
||||
int y = _infos.Coordinates.z;
|
||||
|
||||
//string tmpName = "Tile " + (x < 0 ? '-' : '+') + Mathf.Abs(x).ToString().PadLeft(3, '0') + " " + (y < 0 ? '-' : '+') + Mathf.Abs(y).ToString().PadLeft(3, '0');
|
||||
string tmpName = "Tile_" + transform.GetSiblingIndex().ToString().PadLeft(3, '0');
|
||||
|
||||
if (name != tmpName)
|
||||
name = tmpName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52265b52f92cb4846aa9f736eb80cfe1
|
||||
Reference in New Issue
Block a user