mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-12-31 11:08:09 +00:00
no message
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
using HPJ.Simulation;
|
||||
using HPJ.Simulation.Enums;
|
||||
using HPJ.Simulation.Map;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HPJ.Presentation.Obstacle
|
||||
{
|
||||
/// <summary>
|
||||
/// The Base class for all navigation obstacles
|
||||
/// </summary>
|
||||
public abstract class NavigationObstacle : MonoBehaviour
|
||||
{
|
||||
#region Unity
|
||||
|
||||
// Start is called before the first frame update
|
||||
public virtual void Start()
|
||||
{
|
||||
if (!NavigationManager.Instance.Initialized)
|
||||
{
|
||||
Invoke(nameof(Start), 01f);
|
||||
return;
|
||||
}
|
||||
UpdatePosition(transform.position, true);
|
||||
NavigationManager.Instance?.AddObstacle(this);
|
||||
}
|
||||
|
||||
public virtual void OnDestroy()
|
||||
{
|
||||
NavigationManager.Instance?.RemoveObstacle(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Obstacle
|
||||
|
||||
/// <summary>
|
||||
/// Does the obstacle update automatically through the built in systems
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected bool _automaticUpdate = true;
|
||||
public bool AutomaticUpdate { get { return _automaticUpdate; } set { _automaticUpdate = value; } }
|
||||
/// <summary>
|
||||
/// The Height difference from the map to count as being on top of the map
|
||||
/// </summary>
|
||||
[SerializeField, Tooltip("The Height from the transform y position to the ground that this counts as an obstacle")]
|
||||
protected float _checkMapHeight = 1f;
|
||||
public float CheckMapHeight { get { return _checkMapHeight; } set { _checkMapHeight = value; } }
|
||||
/// <summary>
|
||||
/// The tile type the obstacle changes the tiles beneath it too
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected TileTypes _obstacleTileType = TileTypes.Obstacle;
|
||||
public TileTypes ObstacleTileType { get { return _obstacleTileType; } }
|
||||
|
||||
/// <summary>
|
||||
/// The Update cycle of the obstacle
|
||||
/// </summary>
|
||||
public virtual void UpdateObstacle()
|
||||
{
|
||||
if (_automaticUpdate)
|
||||
{
|
||||
UpdatePosition(transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The tiles and map relationship data with this obstacle
|
||||
/// </summary>
|
||||
public Dictionary<MapSet, MapObstacleRelationshipData> MapTileRelationships { get; protected set; }
|
||||
/// <summary>
|
||||
/// Checks to see if the new position changes and if so it changes the mesh to block out the new corresponding tiles
|
||||
/// </summary>
|
||||
/// <param name="NewPosition"></param>
|
||||
/// <param name="ForceCheck"></param>
|
||||
public abstract void UpdatePosition(Vector3 NewPosition, bool ForceCheck = false);
|
||||
|
||||
/// <summary>
|
||||
/// What happens the the obstacle mesh position changes
|
||||
/// </summary>
|
||||
/// <param name="NewPosition"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract bool PositionChanged(Vector3 NewPosition);
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the obstacle based on the desired Rotation. Basic NavigationObstacle will only swap the object size x and y values. Inherit to ovverride this behaviour
|
||||
/// </summary>
|
||||
/// <param name="Rotation"></param>
|
||||
public abstract void Rotate(Quaternion Rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Revalidates the tiles of the obstacle in case another obstacle travels over top of this one
|
||||
/// </summary>
|
||||
public abstract void RevalidateTiles();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct PositionSquareRect
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector2 Size;
|
||||
public Vector3[] Corners;
|
||||
|
||||
public PositionSquareRect(Vector3 position, Vector2 size)
|
||||
{
|
||||
Position = position;
|
||||
Size = size;
|
||||
Corners = new Vector3[4];
|
||||
|
||||
Corners[0] = Position + new Vector3(Size.x / 2, 0, Size.y / 2);
|
||||
Corners[1] = Position + new Vector3(Size.x / 2, 0, -Size.y / 2);
|
||||
Corners[2] = Position + new Vector3(-Size.x / 2, 0, -Size.y / 2);
|
||||
Corners[3] = Position + new Vector3(-Size.x / 2, 0, Size.y / 2);
|
||||
}
|
||||
|
||||
public PositionSquareRect(Vector3 position, Vector3 LowerBounds, Vector3 HigherBounds)
|
||||
{
|
||||
Position = position;
|
||||
Size = new Vector2(HigherBounds.x - LowerBounds.x, HigherBounds.z - LowerBounds.z);
|
||||
Corners = new Vector3[4];
|
||||
LowerBounds.y = 0;
|
||||
HigherBounds.y = 0;
|
||||
|
||||
Corners[0] = HigherBounds;
|
||||
Corners[1] = new Vector3(HigherBounds.x, 0, LowerBounds.z);
|
||||
Corners[2] = LowerBounds;
|
||||
Corners[3] = new Vector3(LowerBounds.x, 0, HigherBounds.z);
|
||||
}
|
||||
|
||||
public void UpdatePosition(Vector3 position)
|
||||
{
|
||||
Position = position;
|
||||
|
||||
Corners[0] = Position + new Vector3(Size.x / 2, 0, Size.y / 2);
|
||||
Corners[1] = Position + new Vector3(Size.x / 2, 0, -Size.y / 2);
|
||||
Corners[2] = Position + new Vector3(-Size.x / 2, 0, -Size.y / 2);
|
||||
Corners[3] = Position + new Vector3(-Size.x / 2, 0, Size.y / 2);
|
||||
}
|
||||
|
||||
public void UpdateSize(Vector2 newSize)
|
||||
{
|
||||
Size = newSize;
|
||||
|
||||
Corners[0] = Position + new Vector3(Size.x / 2, 0, Size.y / 2);
|
||||
Corners[1] = Position + new Vector3(Size.x / 2, 0, -Size.y / 2);
|
||||
Corners[2] = Position + new Vector3(-Size.x / 2, 0, -Size.y / 2);
|
||||
Corners[3] = Position + new Vector3(-Size.x / 2, 0, Size.y / 2);
|
||||
}
|
||||
|
||||
public bool InBounds(Vector3 Point)
|
||||
{
|
||||
if (Point.x > Corners[0].x || Point.x < Corners[2].x || Point.z > Corners[0].z || Point.z < Corners[2].z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class MapObstacleRelationshipData
|
||||
{
|
||||
public MapSet Map;
|
||||
public NavigationObstacle Obstacle;
|
||||
public Dictionary<IntVector3, ObstacleData> RelatedTilesData;
|
||||
public HashSet<IntVector3> ValidatedTiles;
|
||||
public HashSet<IntVector3> InvalidatedTiles;
|
||||
public HashSet<IntVector3> AddedTiles;
|
||||
public TileTypes ObstacleTileType;
|
||||
|
||||
public MapObstacleRelationshipData(MapSet map, NavigationObstacle obstacle, TileTypes ObstacleType)
|
||||
{
|
||||
ValidatedTiles = new HashSet<IntVector3>();
|
||||
InvalidatedTiles = new HashSet<IntVector3>();
|
||||
AddedTiles = new HashSet<IntVector3>();
|
||||
RelatedTilesData = new Dictionary<IntVector3, ObstacleData>();
|
||||
Map = map;
|
||||
Obstacle = obstacle;
|
||||
ObstacleTileType = ObstacleType;
|
||||
}
|
||||
|
||||
public void UnvalidateTiles()
|
||||
{
|
||||
InvalidatedTiles.Clear();
|
||||
ValidatedTiles.Clear();
|
||||
AddedTiles.Clear();
|
||||
foreach (ObstacleData Data in RelatedTilesData.Values)
|
||||
{
|
||||
InvalidatedTiles.Add(Data.TileIndexKey);
|
||||
Data.UnValidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddOrValidateTile(IntVector3 tileIndex)
|
||||
{
|
||||
if (RelatedTilesData.ContainsKey(tileIndex))
|
||||
{
|
||||
RelatedTilesData[tileIndex].Validate();
|
||||
InvalidatedTiles.Remove(tileIndex);
|
||||
ValidatedTiles.Add(tileIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObstacleData NewTile = new ObstacleData(tileIndex);
|
||||
RelatedTilesData.Add(tileIndex, NewTile);
|
||||
AddedTiles.Add(tileIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SortRelatedTileData()
|
||||
{
|
||||
foreach(IntVector3 InvalidatedTile in InvalidatedTiles)
|
||||
{
|
||||
RelatedTilesData.Remove(InvalidatedTile);
|
||||
}
|
||||
}
|
||||
|
||||
public ChangeMapJob GenerateMapChangeJob()
|
||||
{
|
||||
if (AddedTiles.Count == 0 && InvalidatedTiles.Count == 0)
|
||||
{
|
||||
//Debug.Log("No Tiles Changed");
|
||||
return null;
|
||||
}
|
||||
|
||||
ChangeMapJob MapChange = new ChangeMapJob();
|
||||
|
||||
// Set to Obstacle type
|
||||
foreach (IntVector3 Tile in AddedTiles)
|
||||
{
|
||||
MapChange.AddTileChange(Tile.Vector2(), Obstacle.ObstacleTileType);
|
||||
}
|
||||
|
||||
// Set back to default
|
||||
foreach (IntVector3 Tile in InvalidatedTiles)
|
||||
{
|
||||
MapChange.AddTileChange(Tile.Vector2(), (TileTypes)Map.SetSettings.MapSettings.MapInfo.SavedTiles[Tile.x, Tile.y]);
|
||||
}
|
||||
//Debug.Log($"Tiles To Change {MapChange.TilesToBeChanged.Count} -> Added {AddedTiles.Count} -> Removed {InvalidatedTiles.Count}");
|
||||
|
||||
return MapChange;
|
||||
}
|
||||
|
||||
internal void Revalidate()
|
||||
{
|
||||
ChangeMapJob MapChange = new ChangeMapJob();
|
||||
|
||||
bool ChangedTiles = false;
|
||||
foreach (IntVector3 Tile in ValidatedTiles)
|
||||
{
|
||||
if (Map.GetTileType(Tile.Vector2()) != ObstacleTileType)
|
||||
{
|
||||
ChangedTiles = true;
|
||||
MapChange.AddTileChange(Tile.Vector2(), ObstacleTileType);
|
||||
}
|
||||
}
|
||||
|
||||
if (ChangedTiles)
|
||||
{
|
||||
Map.ChangeMap(MapChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bc9ffc400bd794459494c21a8e1c02a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,590 @@
|
||||
using HPJ.Simulation;
|
||||
using HPJ.Simulation.Enums;
|
||||
using HPJ.Simulation.Map;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HPJ.Presentation.Obstacle
|
||||
{
|
||||
/// <summary>
|
||||
/// A Navigation Obstacle that adjusts the Map based on the given mesh, position and rotation
|
||||
/// </summary>
|
||||
public class NavigationObstacleMesh : NavigationObstacle
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Mesh Renderer we want to use for the obstacle
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected MeshRenderer ObstacleRenderer;
|
||||
/// <summary>
|
||||
/// Mesh we want to use for the obstacle
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected MeshFilter ObstacleFilter;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Generate all the connection points that will need to be tested for collision
|
||||
Vertices.Clear();
|
||||
VertexConnections.Clear();
|
||||
|
||||
VertexCount = 0;
|
||||
for (int i = 0; i < ObstacleFilter.mesh.vertices.Length; i++)
|
||||
{
|
||||
if (!Points.ContainsKey(ObstacleFilter.mesh.vertices[i]))
|
||||
{
|
||||
VertexPoints NewVertex = new VertexPoints(ObstacleFilter.mesh.vertices[i], VertexCount);
|
||||
Points.Add(ObstacleFilter.mesh.vertices[i], NewVertex);
|
||||
Vertices.Add(NewVertex);
|
||||
VertexCount++;
|
||||
}
|
||||
|
||||
VertexPoints Vertex = Points[ObstacleFilter.mesh.vertices[i]];
|
||||
Vertex.SharedPoints.Add(i);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
Vector3Int CurrentTriangle = new Vector3Int();
|
||||
foreach (int vertexIndex in ObstacleFilter.mesh.triangles)
|
||||
{
|
||||
count++;
|
||||
if (count == 1)
|
||||
{
|
||||
CurrentTriangle.x = vertexIndex;
|
||||
}
|
||||
else if (count == 2)
|
||||
{
|
||||
CurrentTriangle.y = vertexIndex;
|
||||
}
|
||||
else if (count == 3)
|
||||
{
|
||||
CurrentTriangle.z = vertexIndex;
|
||||
|
||||
foreach (VertexPoints Vertex in Points.Values)
|
||||
{
|
||||
if (Vertex.ContainsTriangeIndex(CurrentTriangle))
|
||||
{
|
||||
if (!Vertex.ContainsTriange(CurrentTriangle))
|
||||
{
|
||||
Vertex.Triangles.Add(CurrentTriangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Triangles.Add(CurrentTriangle);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (VertexPoints Vertex in Points.Values)
|
||||
{
|
||||
foreach (Vector3Int Triange in Vertex.Triangles)
|
||||
{
|
||||
Vector3 PositionX = ObstacleFilter.mesh.vertices[Triange.x];
|
||||
if (PositionX != Vertex.VertexPosition)
|
||||
{
|
||||
VertexPoints OtherVertex = Points[PositionX];
|
||||
if (!Vertex.ConnectedVertex.Contains(OtherVertex))
|
||||
{
|
||||
Vertex.ConnectedVertex.Add(OtherVertex);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 PositionY = ObstacleFilter.mesh.vertices[Triange.y];
|
||||
if (PositionY != Vertex.VertexPosition)
|
||||
{
|
||||
VertexPoints OtherVertex = Points[PositionY];
|
||||
if (!Vertex.ConnectedVertex.Contains(OtherVertex))
|
||||
{
|
||||
Vertex.ConnectedVertex.Add(OtherVertex);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 PositionZ = ObstacleFilter.mesh.vertices[Triange.z];
|
||||
if (PositionZ != Vertex.VertexPosition)
|
||||
{
|
||||
VertexPoints OtherVertex = Points[PositionZ];
|
||||
if (!Vertex.ConnectedVertex.Contains(OtherVertex))
|
||||
{
|
||||
Vertex.ConnectedVertex.Add(OtherVertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (VertexPoints Vertex in Points.Values)
|
||||
{
|
||||
foreach (VertexPoints ConnectedVertex in Vertex.ConnectedVertex)
|
||||
{
|
||||
Vector2Int IndexKey = new Vector2Int();
|
||||
if (Vertex.VertexIndex < ConnectedVertex.VertexIndex)
|
||||
{
|
||||
IndexKey.x = Vertex.VertexIndex;
|
||||
IndexKey.y = ConnectedVertex.VertexIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
IndexKey.x = ConnectedVertex.VertexIndex;
|
||||
IndexKey.y = Vertex.VertexIndex;
|
||||
}
|
||||
|
||||
if (!Connections.ContainsKey(IndexKey))
|
||||
{
|
||||
VertexConnection NewConnection = new VertexConnection(Vertex, ConnectedVertex);
|
||||
Connections.Add(IndexKey, NewConnection);
|
||||
VertexConnections.Add(NewConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start is called before the first frame update
|
||||
public override void Start()
|
||||
{
|
||||
MapTileRelationships = new Dictionary<MapSet, MapObstacleRelationshipData>();
|
||||
OrientationChanged(transform.rotation, transform.position);
|
||||
base.Start();
|
||||
}
|
||||
|
||||
public virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
foreach (VertexConnection Connection in VertexConnections)
|
||||
{
|
||||
Vector3 A = ObstacleRenderer.transform.localToWorldMatrix.MultiplyPoint3x4(Connection.PointA.VertexPosition);
|
||||
Vector3 B = ObstacleRenderer.transform.localToWorldMatrix.MultiplyPoint3x4(Connection.PointB.VertexPosition);
|
||||
|
||||
Gizmos.DrawLine(A, B);
|
||||
}
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
foreach (Vector3Int Triange in Triangles)
|
||||
{
|
||||
Vector3 A = ObstacleRenderer.transform.localToWorldMatrix.MultiplyPoint3x4(ObstacleFilter.mesh.vertices[Triange.x]);
|
||||
A.y = transform.position.y;
|
||||
Vector3 B = ObstacleRenderer.transform.localToWorldMatrix.MultiplyPoint3x4(ObstacleFilter.mesh.vertices[Triange.y]);
|
||||
B.y = transform.position.y;
|
||||
Vector3 C = ObstacleRenderer.transform.localToWorldMatrix.MultiplyPoint3x4(ObstacleFilter.mesh.vertices[Triange.z]);
|
||||
C.y = transform.position.y;
|
||||
|
||||
Gizmos.DrawLine(A, B);
|
||||
Gizmos.DrawLine(A, C);
|
||||
Gizmos.DrawLine(C, B);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Obstacle
|
||||
|
||||
/// <summary>
|
||||
/// Type of Collision we want to use for this obstacle
|
||||
/// </summary>
|
||||
public ObstacleCollisionCheckType CollisionCheckMode = ObstacleCollisionCheckType.Both;
|
||||
|
||||
/// <summary>
|
||||
/// A Dictionary of the Vertex points based on their physical position relative to the default mesh
|
||||
/// </summary>
|
||||
public Dictionary<Vector3, VertexPoints> Points = new Dictionary<Vector3, VertexPoints>();
|
||||
/// <summary>
|
||||
/// A List of the Vertex points for this mesh
|
||||
/// </summary>
|
||||
public List<VertexPoints> Vertices = new List<VertexPoints>();
|
||||
/// <summary>
|
||||
/// A Dictionary of the connection based on index of the smallest vertex point index as Vector2Int.x and the largest vertex point index as Vector2Int.y
|
||||
/// </summary>
|
||||
public Dictionary<Vector2Int, VertexConnection> Connections = new Dictionary<Vector2Int, VertexConnection>();
|
||||
/// <summary>
|
||||
/// A List of the Vertex connections for this mesh
|
||||
/// </summary>
|
||||
public List<VertexConnection> VertexConnections = new List<VertexConnection>();
|
||||
/// <summary>
|
||||
/// A List of the traingles for the mesh
|
||||
/// </summary>
|
||||
public List<Vector3Int> Triangles = new List<Vector3Int>();
|
||||
|
||||
/// <summary>
|
||||
/// The number of Vertex on this Mesh
|
||||
/// </summary>
|
||||
public int VertexCount { get; protected set; }
|
||||
|
||||
protected Vector3 _previousPosition = new Vector3();
|
||||
/// <summary>
|
||||
/// Checks to see if the new position changes and if so it changes the mesh to block out the new corresponding tiles
|
||||
/// </summary>
|
||||
/// <param name="NewPosition"></param>
|
||||
/// <param name="ForceCheck"></param>
|
||||
public override void UpdatePosition(Vector3 NewPosition, bool ForceCheck = false)
|
||||
{
|
||||
if (NewPosition != _previousPosition || _previousRotation != transform.rotation)
|
||||
{
|
||||
OrientationChanged(transform.rotation, NewPosition);
|
||||
transform.position = NewPosition;
|
||||
_previousPosition = NewPosition;
|
||||
_previousRotation = transform.rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
RevalidateTiles();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Revalidate tiles
|
||||
/// </summary>
|
||||
public override void RevalidateTiles()
|
||||
{
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
Data.Revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What happens the the obstacle mesh position changes
|
||||
/// </summary>
|
||||
/// <param name="NewPosition"></param>
|
||||
/// <returns></returns>
|
||||
protected override bool PositionChanged(Vector3 NewPosition)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Quaternion _previousRotation = Quaternion.identity;
|
||||
/// <summary>
|
||||
/// Rotates the obstacle based on the desired Rotation. Basic NavigationObstacle will only swap the object size x and y values. Inherit to ovverride this behaviour
|
||||
/// </summary>
|
||||
/// <param name="Rotation"></param>
|
||||
public override void Rotate(Quaternion Rotation)
|
||||
{
|
||||
if (_previousPosition != transform.position || transform.rotation != Rotation)
|
||||
{
|
||||
OrientationChanged(Rotation, transform.position);
|
||||
transform.rotation = Rotation;
|
||||
}
|
||||
}
|
||||
|
||||
protected PositionSquareRect OrientationRect;
|
||||
/// <summary>
|
||||
/// Changes the mesh to block out the new corresponding tiles
|
||||
/// </summary>
|
||||
/// <param name="Rotation"></param>
|
||||
/// <param name="NewPosition"></param>
|
||||
protected virtual void OrientationChanged(Quaternion Rotation, Vector3 NewPosition)
|
||||
{
|
||||
ResizeBoundsEstimate();
|
||||
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
Data.UnvalidateTiles();
|
||||
}
|
||||
|
||||
foreach (MapSet Set in NavigationManager.Instance.MapSets)
|
||||
{
|
||||
if (!NavigationManager.Instance.RectOnMap(Set, OrientationRect, _checkMapHeight))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MapObstacleRelationshipData RelationshipData;
|
||||
if (MapTileRelationships.ContainsKey(Set))
|
||||
{
|
||||
RelationshipData = MapTileRelationships[Set];
|
||||
}
|
||||
else
|
||||
{
|
||||
RelationshipData = new MapObstacleRelationshipData(Set, this, _obstacleTileType);
|
||||
MapTileRelationships.Add(Set, RelationshipData);
|
||||
}
|
||||
|
||||
IntVector2 HigherBound = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(OrientationRect.Corners[0]));
|
||||
IntVector2 LowerBound = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(OrientationRect.Corners[2]));
|
||||
for (int x = LowerBound.x; x <= HigherBound.x; x++)
|
||||
{
|
||||
for (int y = LowerBound.y; y <= HigherBound.y; y++)
|
||||
{
|
||||
if (Set.GetTileType(x, y) != TileTypes.OutOfBounds)
|
||||
{
|
||||
//Debug.Log("Change Tile");
|
||||
TileBounds Bounds = NavigationManager.Instance.GetTileBoundsForMap(x, y, Set);
|
||||
if (ObstacleCollidesWithBounds(Bounds, CollisionCheckMode))
|
||||
{
|
||||
IntVector3 TileKey = new IntVector3(x, y, Set.InstanceID);
|
||||
RelationshipData.AddOrValidateTile(TileKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
ChangeMapJob GeneratedMapChangeJob = Data.GenerateMapChangeJob();
|
||||
if (GeneratedMapChangeJob != null)
|
||||
{
|
||||
//Debug.Log("Change Map From Job");
|
||||
Data.Map.ChangeMap(GeneratedMapChangeJob);
|
||||
}
|
||||
Data.SortRelatedTileData();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collision Check for the obstacle and the maps Tiles
|
||||
/// </summary>
|
||||
/// <param name="Bounds"></param>
|
||||
/// <param name="CheckMode"></param>
|
||||
/// <returns></returns>
|
||||
public bool ObstacleCollidesWithBounds(TileBounds Bounds, ObstacleCollisionCheckType CheckMode = ObstacleCollisionCheckType.Both)
|
||||
{
|
||||
if (CheckMode == ObstacleCollisionCheckType.LineCollisions)
|
||||
{
|
||||
return ObstacleLinesCollide(Bounds);
|
||||
}
|
||||
else if (CheckMode == ObstacleCollisionCheckType.AreaCollisions)
|
||||
{
|
||||
return ObstacleAreaCollide(Bounds);
|
||||
}
|
||||
else if (CheckMode == ObstacleCollisionCheckType.Both)
|
||||
{
|
||||
return ObstacleAreaCollide(Bounds) || ObstacleLinesCollide(Bounds);
|
||||
}
|
||||
|
||||
return OrientationRect.InBounds(Bounds.BottomRight) || OrientationRect.InBounds(Bounds.BottomLeft) || OrientationRect.InBounds(Bounds.TopLeft) || OrientationRect.InBounds(Bounds.TopRight) || Bounds.InBounds(OrientationRect.Corners[0]) || Bounds.InBounds(OrientationRect.Corners[1]) || Bounds.InBounds(OrientationRect.Corners[2]) || Bounds.InBounds(OrientationRect.Corners[3]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Line Line Collision between all the vertex points and the map tiles
|
||||
/// </summary>
|
||||
/// <param name="Bounds"></param>
|
||||
/// <returns></returns>
|
||||
protected bool ObstacleLinesCollide(TileBounds Bounds)
|
||||
{
|
||||
foreach (VertexConnection connection in VertexConnections)
|
||||
{
|
||||
if (Bounds.IntersectsBounds(GetVertexPosition(connection.PointB.VertexPosition), GetVertexPosition(connection.PointA.VertexPosition)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Area Collision between all the vertex triangles and the map tiles
|
||||
/// </summary>
|
||||
/// <param name="Bounds"></param>
|
||||
/// <returns></returns>
|
||||
protected bool ObstacleAreaCollide(TileBounds Bounds)
|
||||
{
|
||||
foreach (Vector3Int Triange in Triangles)
|
||||
{
|
||||
Vector3 TriangePoint1 = GetVertexPosition(ObstacleFilter.mesh.vertices[Triange.x]);
|
||||
Vector3 TriangePoint2 = GetVertexPosition(ObstacleFilter.mesh.vertices[Triange.y]);
|
||||
Vector3 TriangePoint3 = GetVertexPosition(ObstacleFilter.mesh.vertices[Triange.z]);
|
||||
|
||||
if (IsInsideTriange(TriangePoint1, TriangePoint2, TriangePoint3, Bounds))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Area of the triange with the given points
|
||||
/// </summary>
|
||||
/// <param name="point1"></param>
|
||||
/// <param name="point2"></param>
|
||||
/// <param name="point3"></param>
|
||||
/// <returns></returns>
|
||||
public float TriangeArea(Vector3 point1, Vector3 point2, Vector3 point3)
|
||||
{
|
||||
return Mathf.Abs((point1.x * (point2.z - point3.z) + point2.x * (point3.z - point1.z) + point3.x * (point1.z - point2.z)) / 2.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if a given point is withen a triangle
|
||||
/// </summary>
|
||||
/// <param name="TriangePoint1"></param>
|
||||
/// <param name="TriangePoint2"></param>
|
||||
/// <param name="TriangePoint3"></param>
|
||||
/// <param name="CheckingPoint"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInsideTriange(Vector3 TriangePoint1, Vector3 TriangePoint2, Vector3 TriangePoint3, Vector3 CheckingPoint)
|
||||
{
|
||||
// Calculate area of triangle ABC
|
||||
float A = TriangeArea(TriangePoint1, TriangePoint2, TriangePoint3);
|
||||
|
||||
// Calculate area of triangle PBC
|
||||
float A1 = TriangeArea(CheckingPoint, TriangePoint2, TriangePoint3);
|
||||
|
||||
// Calculate area of triangle APC
|
||||
float A2 = TriangeArea(TriangePoint1, CheckingPoint, TriangePoint3);
|
||||
|
||||
//Calculate area of triangle ABP
|
||||
float A3 = TriangeArea(TriangePoint1, TriangePoint2, CheckingPoint);
|
||||
|
||||
// Check if sum of A1, A2 and A3 is same as A
|
||||
int AInt = Mathf.RoundToInt(A * 100);
|
||||
int SumA123 = Mathf.RoundToInt((A1 + A2 + A3) * 100);
|
||||
|
||||
return AInt == SumA123;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if a given tile is withen a triangle
|
||||
/// </summary>
|
||||
/// <param name="TriangePoint1"></param>
|
||||
/// <param name="TriangePoint2"></param>
|
||||
/// <param name="TriangePoint3"></param>
|
||||
/// <param name="CheckingPoint"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInsideTriange(Vector3 TriangePoint1, Vector3 TriangePoint2, Vector3 TriangePoint3, TileBounds TileBounds)
|
||||
{
|
||||
return IsInsideTriange(TriangePoint1, TriangePoint2, TriangePoint3, TileBounds.BottomLeft) ||
|
||||
IsInsideTriange(TriangePoint1, TriangePoint2, TriangePoint3, TileBounds.TopRight) ||
|
||||
IsInsideTriange(TriangePoint1, TriangePoint2, TriangePoint3, TileBounds.BottomRight) ||
|
||||
IsInsideTriange(TriangePoint1, TriangePoint2, TriangePoint3, TileBounds.TopLeft) ||
|
||||
IsInsideTriange(TriangePoint1, TriangePoint2, TriangePoint3, TileBounds.Center);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a position relative to the local transforms roation and scale
|
||||
/// </summary>
|
||||
/// <param name="Position"></param>
|
||||
/// <returns></returns>
|
||||
public Vector3 GetVertexPosition(Vector3 Position)
|
||||
{
|
||||
return ObstacleRenderer.transform.localToWorldMatrix.MultiplyPoint3x4(Position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the bounds of the mesh
|
||||
/// </summary>
|
||||
public void ResizeBoundsEstimate()
|
||||
{
|
||||
if (Vertices.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 LowerBounds = GetVertexPosition(Vertices[0].VertexPosition);
|
||||
Vector3 HigherBounds = LowerBounds;
|
||||
|
||||
for(int i = 1; i < Vertices.Count; i++)
|
||||
{
|
||||
Vector3 VertexWorldPosition = GetVertexPosition(Vertices[i].VertexPosition);
|
||||
|
||||
if (VertexWorldPosition.x < LowerBounds.x)
|
||||
{
|
||||
LowerBounds.x = VertexWorldPosition.x;
|
||||
}
|
||||
else if (VertexWorldPosition.x > HigherBounds.x)
|
||||
{
|
||||
HigherBounds.x = VertexWorldPosition.x;
|
||||
}
|
||||
|
||||
if (VertexWorldPosition.y < LowerBounds.y)
|
||||
{
|
||||
LowerBounds.y = VertexWorldPosition.y;
|
||||
}
|
||||
else if (VertexWorldPosition.y > HigherBounds.y)
|
||||
{
|
||||
HigherBounds.y = VertexWorldPosition.y;
|
||||
}
|
||||
|
||||
if (VertexWorldPosition.z < LowerBounds.z)
|
||||
{
|
||||
LowerBounds.z = VertexWorldPosition.z;
|
||||
}
|
||||
else if (VertexWorldPosition.z > HigherBounds.z)
|
||||
{
|
||||
HigherBounds.z = VertexWorldPosition.z;
|
||||
}
|
||||
}
|
||||
|
||||
OrientationRect = new PositionSquareRect(transform.position, LowerBounds, HigherBounds);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// A Vertex Point based on the obstacle mesh
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class VertexPoints
|
||||
{
|
||||
public int VertexIndex;
|
||||
public Vector3 VertexPosition;
|
||||
public List<int> SharedPoints = new List<int>();
|
||||
public List<Vector3Int> Triangles = new List<Vector3Int>();
|
||||
|
||||
[NonSerialized] public List<VertexPoints> ConnectedVertex = new List<VertexPoints>();
|
||||
|
||||
public VertexPoints(Vector3 Position, int vertexIndex)
|
||||
{
|
||||
VertexPosition = Position;
|
||||
VertexIndex = vertexIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if this triange shares a mesh index with this vertex point
|
||||
/// </summary>
|
||||
/// <param name="currentTriangle"></param>
|
||||
/// <returns></returns>
|
||||
public bool ContainsTriangeIndex(Vector3Int currentTriangle)
|
||||
{
|
||||
if (SharedPoints.Contains(currentTriangle.x) || SharedPoints.Contains(currentTriangle.y) || SharedPoints.Contains(currentTriangle.z))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if this triange shares has this specific triange
|
||||
/// </summary>
|
||||
/// <param name="currentTriangle"></param>
|
||||
/// <returns></returns>
|
||||
public bool ContainsTriange(Vector3Int currentTriangle)
|
||||
{
|
||||
return Triangles.Contains(currentTriangle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a connection between two vertex points
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class VertexConnection
|
||||
{
|
||||
public VertexPoints PointA;
|
||||
public VertexPoints PointB;
|
||||
|
||||
public VertexConnection(VertexPoints A, VertexPoints B)
|
||||
{
|
||||
PointA = A;
|
||||
PointB = B;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Type of Collision the Obstacle Mesh attempts
|
||||
/// </summary>
|
||||
public enum ObstacleCollisionCheckType
|
||||
{
|
||||
None,
|
||||
LineCollisions,
|
||||
AreaCollisions,
|
||||
Both,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b17b55d52e05634985d0f59c45f969b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,208 @@
|
||||
using HPJ.Simulation;
|
||||
using HPJ.Simulation.Enums;
|
||||
using HPJ.Simulation.Map;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HPJ.Presentation.Obstacle
|
||||
{
|
||||
public class NavigationObstacleSimpleSquare : NavigationObstacle
|
||||
{
|
||||
#region Unity
|
||||
|
||||
// Start is called before the first frame update
|
||||
public override void Start()
|
||||
{
|
||||
if (!NavigationManager.Instance.Initialized)
|
||||
{
|
||||
Invoke(nameof(Start), 01f);
|
||||
return;
|
||||
}
|
||||
MapTileRelationships = new Dictionary<MapSet, MapObstacleRelationshipData>();
|
||||
_previousPositionRect = new PositionSquareRect(Vector3.one * 1000, _obstacleSize);
|
||||
_newPositionRect = new PositionSquareRect(transform.position, _obstacleSize);
|
||||
base.Start();
|
||||
}
|
||||
|
||||
public virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
PositionSquareRect obstacleRect = new PositionSquareRect(transform.position, _obstacleSize);
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
for (int i = 1; i < obstacleRect.Corners.Length; i++)
|
||||
{
|
||||
Gizmos.DrawLine(obstacleRect.Corners[i], obstacleRect.Corners[i - 1]);
|
||||
}
|
||||
Gizmos.DrawLine(obstacleRect.Corners[0], obstacleRect.Corners[3]);
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawLine(transform.position, transform.position - Vector3.up * _checkMapHeight);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Obstacle
|
||||
|
||||
/// <summary>
|
||||
/// Revalidate Tiles
|
||||
/// </summary>
|
||||
public override void RevalidateTiles()
|
||||
{
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
Data.Revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The size of the obstacle in the x and z world directions
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private Vector2 _obstacleSize = Vector2.one;
|
||||
public Vector2 ObstacleSize { get { return _obstacleSize; } set { _obstacleSize = value; } }
|
||||
|
||||
private PositionSquareRect _previousPositionRect;
|
||||
private PositionSquareRect _newPositionRect;
|
||||
/// <summary>
|
||||
/// Checks to see if the new position changes and if so it changes the mesh to block out the new corresponding tiles
|
||||
/// </summary>
|
||||
/// <param name="NewPosition"></param>
|
||||
/// <param name="ForceCheck"></param>
|
||||
public override void UpdatePosition(Vector3 NewPosition, bool ForceCheck = false)
|
||||
{
|
||||
if (!NavigationManager.Instance.Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_previousPositionRect.Position != NewPosition || ForceCheck)
|
||||
{
|
||||
_newPositionRect.UpdatePosition(NewPosition);
|
||||
// No need to update if no tiles need updating
|
||||
if (PositionChanged(NewPosition))
|
||||
{
|
||||
_previousPositionRect.UpdatePosition(NewPosition);
|
||||
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
Data.UnvalidateTiles();
|
||||
}
|
||||
|
||||
foreach (MapSet Set in NavigationManager.Instance.MapSets)
|
||||
{
|
||||
if (!NavigationManager.Instance.RectOnMap(Set, _newPositionRect, _checkMapHeight))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MapObstacleRelationshipData RelationshipData;
|
||||
if (MapTileRelationships.ContainsKey(Set))
|
||||
{
|
||||
RelationshipData = MapTileRelationships[Set];
|
||||
}
|
||||
else
|
||||
{
|
||||
RelationshipData = new MapObstacleRelationshipData(Set, this, _obstacleTileType);
|
||||
MapTileRelationships.Add(Set, RelationshipData);
|
||||
}
|
||||
|
||||
IntVector2 HigherBound = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(_newPositionRect.Corners[0]));
|
||||
IntVector2 LowerBound = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(_newPositionRect.Corners[2]));
|
||||
for (int x = LowerBound.x; x <= HigherBound.x; x++)
|
||||
{
|
||||
for (int y = LowerBound.y; y <= HigherBound.y; y++)
|
||||
{
|
||||
if (Set.GetTileType(x, y) != TileTypes.OutOfBounds)
|
||||
{
|
||||
//Debug.Log("Change Tile");
|
||||
IntVector3 TileKey = new IntVector3(x, y, Set.InstanceID);
|
||||
RelationshipData.AddOrValidateTile(TileKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
ChangeMapJob GeneratedMapChangeJob = Data.GenerateMapChangeJob();
|
||||
if (GeneratedMapChangeJob != null)
|
||||
{
|
||||
//Debug.Log("Change Map From Job");
|
||||
Data.Map.ChangeMap(GeneratedMapChangeJob);
|
||||
}
|
||||
Data.SortRelatedTileData();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RevalidateTiles();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What happens the the obstacle mesh position changes
|
||||
/// </summary>
|
||||
/// <param name="NewPosition"></param>
|
||||
/// <returns></returns>
|
||||
protected override bool PositionChanged(Vector3 NewPosition)
|
||||
{
|
||||
return true;
|
||||
foreach (MapSet set in NavigationManager.Instance.MapSets)
|
||||
{
|
||||
// Find out which maps this Obstacle is on. And if the change in position was enough to change the map
|
||||
for (int i = 0; i < _newPositionRect.Corners.Length; i++)
|
||||
{
|
||||
// Did the height change effect the map that it should previously had not
|
||||
IntVector3 NewTileWorldPosition = NavigationManager.Instance.GetTileWorldPosition(_newPositionRect.Corners[i]);
|
||||
IntVector3 PreviousTileWorldPosition = NavigationManager.Instance.GetTileWorldPosition(_previousPositionRect.Corners[i]);
|
||||
if (_newPositionRect.Corners[i].y - set.SetSettings.MapSettings.Offset.y / 100 <= _checkMapHeight && set.PointInMap(NewTileWorldPosition))
|
||||
{
|
||||
if (!set.PointInMap(PreviousTileWorldPosition) || _previousPositionRect.Corners[i].y - set.SetSettings.MapSettings.Offset.y / 100f > _checkMapHeight)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (set.GetMapTileIndex(PreviousTileWorldPosition) != set.GetMapTileIndex(NewTileWorldPosition))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (_previousPositionRect.Corners[i].y - set.SetSettings.MapSettings.Offset.y / 100f <= _checkMapHeight && set.PointInMap(PreviousTileWorldPosition))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Quaternion _previousRotation = Quaternion.identity;
|
||||
/// <summary>
|
||||
/// Rotates the obstacle based on the desired Rotation. Basic NavigationObstacle will only swap the object size x and y values. Inherit to ovverride this behaviour
|
||||
/// </summary>
|
||||
/// <param name="Rotation"></param>
|
||||
public override void Rotate(Quaternion Rotation)
|
||||
{
|
||||
// Can use that later for more complex rotations. This Rotate just rotates 90* every time you ask this
|
||||
//if (Rotation == _previousRotation)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (_obstacleSize.y == _obstacleSize.x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_previousRotation = Rotation;
|
||||
|
||||
_obstacleSize = new Vector2(_obstacleSize.y, _obstacleSize.x);
|
||||
_newPositionRect.UpdateSize(_obstacleSize);
|
||||
UpdatePosition(transform.position, true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad8ef4b58a73e034aa00ac06b2beda9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,159 @@
|
||||
using HPJ.Simulation;
|
||||
using HPJ.Simulation.Enums;
|
||||
using HPJ.Simulation.Map;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HPJ.Presentation.Obstacle
|
||||
{
|
||||
// A Simple Obstacle based on a sphere or circle
|
||||
public class NavigationObstacleSphere : NavigationObstacle
|
||||
{
|
||||
#region Unity
|
||||
|
||||
// Start is called before the first frame update
|
||||
public override void Start()
|
||||
{
|
||||
if (!NavigationManager.Instance.Initialized)
|
||||
{
|
||||
Invoke(nameof(Start), 01f);
|
||||
return;
|
||||
}
|
||||
MapTileRelationships = new Dictionary<MapSet, MapObstacleRelationshipData>();
|
||||
_previousPosition = new Vector3(-1111111, -112321321321312, 233414212);
|
||||
base.Start();
|
||||
}
|
||||
|
||||
public virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(transform.position, _radius);
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawLine(transform.position, transform.position - Vector3.up * _checkMapHeight);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Obstacle
|
||||
|
||||
[SerializeField]
|
||||
protected float _radius = 1f;
|
||||
public float Radius { get { return _radius; } set { _radius = value; } }
|
||||
|
||||
private Vector3 _previousPosition;
|
||||
|
||||
public override void UpdatePosition(Vector3 NewPosition, bool ForceCheck = false)
|
||||
{
|
||||
if (!NavigationManager.Instance.Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to update if no tiles need updating
|
||||
if (PositionChanged(NewPosition))
|
||||
{
|
||||
_previousPosition = NewPosition;
|
||||
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
Data.UnvalidateTiles();
|
||||
}
|
||||
|
||||
foreach (MapSet Set in NavigationManager.Instance.MapSets)
|
||||
{
|
||||
if (transform.position.y - Set.SetSettings.MapSettings.Offset.y / 100f > _checkMapHeight)
|
||||
{
|
||||
//Debug.Log("Too high or Too low");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!NavigationManager.Instance.CircleOnMap(Set, NewPosition, Radius))
|
||||
{
|
||||
//Debug.Log("Not on Map");
|
||||
continue;
|
||||
}
|
||||
|
||||
MapObstacleRelationshipData RelationshipData;
|
||||
if (MapTileRelationships.ContainsKey(Set))
|
||||
{
|
||||
RelationshipData = MapTileRelationships[Set];
|
||||
}
|
||||
else
|
||||
{
|
||||
RelationshipData = new MapObstacleRelationshipData(Set, this, _obstacleTileType);
|
||||
MapTileRelationships.Add(Set, RelationshipData);
|
||||
}
|
||||
|
||||
Vector3 RadiusVector = new Vector3(Radius, 0, Radius);
|
||||
IntVector2 Center = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(NewPosition));
|
||||
IntVector2 HigherBound = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(NewPosition + RadiusVector));
|
||||
IntVector2 LowerBound = Set.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(NewPosition - RadiusVector));
|
||||
float TileRadiusSqr = (HigherBound.y - LowerBound.y) / 2f;
|
||||
TileRadiusSqr *= TileRadiusSqr;
|
||||
|
||||
for (int x = LowerBound.x; x <= HigherBound.x; x++)
|
||||
{
|
||||
for (int y = LowerBound.y; y <= HigherBound.y; y++)
|
||||
{
|
||||
int X_Distance = Center.x - x;
|
||||
int Y_Distance = Center.y - y;
|
||||
if (X_Distance * X_Distance + Y_Distance * Y_Distance > TileRadiusSqr)
|
||||
{
|
||||
//Debug.Log($"({X_Distance}, {Y_Distance}) Not In Bounds");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure its close enough to the ground to count as an obstacle
|
||||
if (Set.GetTileType(x, y) != TileTypes.OutOfBounds)
|
||||
{
|
||||
//Debug.Log("Change Tile");
|
||||
IntVector3 TileKey = new IntVector3(x, y, Set.InstanceID);
|
||||
RelationshipData.AddOrValidateTile(TileKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
ChangeMapJob GeneratedMapChangeJob = Data.GenerateMapChangeJob();
|
||||
if (GeneratedMapChangeJob != null)
|
||||
{
|
||||
//Debug.Log("Change Map From Job");
|
||||
Data.Map.ChangeMap(GeneratedMapChangeJob);
|
||||
}
|
||||
Data.SortRelatedTileData();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RevalidateTiles();
|
||||
}
|
||||
}
|
||||
|
||||
public override void RevalidateTiles()
|
||||
{
|
||||
foreach (MapObstacleRelationshipData Data in MapTileRelationships.Values)
|
||||
{
|
||||
Data.Revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PositionChanged(Vector3 NewPosition)
|
||||
{
|
||||
return _previousPosition != NewPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotates the obstacle based on the desired Rotation. Basic NavigationObstacle will only swap the object size x and y values. Inherit to ovverride this behaviour
|
||||
/// </summary>
|
||||
/// <param name="Rotation"></param>
|
||||
public override void Rotate(Quaternion Rotation)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c129247b250ac5a4d8e6f226334f33a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user