no message

This commit is contained in:
PC-20230316NUNE\Administrator
2024-02-20 18:39:12 +08:00
parent 97b3671979
commit 2b467e56ad
1876 changed files with 440340 additions and 35266 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4021006eb4ecb7f4481ed92d22425c97
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3fb381a4e8dbf044fa4fa25dd4a20448
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 582c1f2e2a090ef4cb7323bb27a3fb00
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,71 @@
using System;
using UnityEngine;
namespace HPJ.Presentation.Agents
{
/// <summary>
/// A example ground cast that connects a agent to the ground
/// </summary>
public class AgentGroundCast : MonoBehaviour
{
[SerializeField]
private LayerMask _groundLayers;
[SerializeField]
private Transform _raycastSpot;
[SerializeField]
private float _rayCastDistance;
public float RayCastDistance { get { return _rayCastDistance; } set { _rayCastDistance = value; } }
[SerializeField]
private float _rayCastElevatedDistance;
public float RayCastElevatedDistance { get { return _rayCastElevatedDistance; } set { _rayCastElevatedDistance = value; } }
[SerializeField]
[Range(1, 10)]
private int _rayCastEveryXFrames = 3;
public int RayCastEveryXFrames { get { return _rayCastEveryXFrames; } set { _rayCastEveryXFrames = value; } }
[SerializeField]
private Transform _effectTransform;
[SerializeField]
private float _floatAmount;
public float FloatAmount { get { return _floatAmount; } set { _floatAmount = value; } }
[SerializeField]
private Vector3 _raycastDirection = Vector3.down;
public Vector3 RaycastDirection { get { return _raycastDirection; } set { _raycastDirection = value; } }
[SerializeField]
private bool AttemptTeleportUpOnFail = false;
private RaycastHit _rayHit;
private int _physicsCheckCounter = 0;
// Update is called once per frame
public void PhysicsCheck()
{
_physicsCheckCounter++;
if (_physicsCheckCounter >= _rayCastEveryXFrames)
{
_physicsCheckCounter = 0;
if (Physics.Raycast(_raycastSpot.position - _raycastDirection * _rayCastElevatedDistance, _raycastDirection, out _rayHit, _rayCastDistance + _rayCastElevatedDistance, _groundLayers))
{
//Debug.Log("Move");
_effectTransform.transform.position = _rayHit.point - FloatAmount * _raycastDirection;
}
else if (Physics.Raycast(transform.position - _raycastDirection * _rayCastElevatedDistance, _raycastDirection, out _rayHit, _rayCastDistance + _rayCastElevatedDistance, _groundLayers))
{
//Debug.Log("Move 2");
_effectTransform.transform.position = _rayHit.point - FloatAmount * _raycastDirection;
}
else if (AttemptTeleportUpOnFail)
{
TeleportUp();
}
}
}
public void TeleportUp()
{
if (Physics.Raycast(_raycastSpot.position - _raycastDirection * 30, _raycastDirection, out _rayHit, _rayCastDistance * 60, _groundLayers))
{
//Debug.Log("Teleport");
_effectTransform.transform.position = _rayHit.point - FloatAmount * _raycastDirection;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e31c7a1c22f26de4698459dd6ccada5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
using HPJ.Presentation.Agents;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation
{
/// <summary>
/// Displays a line of the Navigation Agents Remaining Path
/// </summary>
[RequireComponent(typeof(LineRenderer))]
[RequireComponent(typeof(NavigationAgent))]
public class AgentLine : MonoBehaviour
{
/// <summary>
/// How Often the line is updated
/// </summary>
[SerializeField]
private float _updateInterval = 0.1f;
private float _updateTime = 0;
private LineRenderer _line;
private NavigationAgent _agent;
private List<Vector3> _linePoints;
private void Awake()
{
_agent = GetComponent<NavigationAgent>();
_line = GetComponent<LineRenderer>();
_linePoints = new List<Vector3>();
}
// Update is called once per frame
void Update()
{
_updateTime += Time.deltaTime;
if (_updateTime > _updateInterval)
{
_updateTime = 0;
UpdateLine();
}
}
/// <summary>
/// Updates the Line Renderer to the navigation agent remaining path
/// </summary>
public void UpdateLine()
{
_linePoints.Clear();
if (_agent.Path.Count <= 0)
{
_line.positionCount = 0;
return;
}
if (_agent.CurrentPathingIndex + 1 >= _agent.Path.Count)
{
Vector3 EndPoint = _agent.Path[_agent.Path.Count - 1];
_linePoints.Add(EndPoint);
EndPoint.x = transform.position.x;
EndPoint.z = transform.position.z;
_linePoints.Add(EndPoint);
_line.positionCount = 2;
_line.SetPositions(_linePoints.ToArray());
return;
}
Vector3 StartPoint = _agent.Path[_agent.CurrentPathingIndex + 1];
StartPoint.x = transform.position.x;
StartPoint.z = transform.position.z;
_linePoints.Add(StartPoint);
int PathCount = 1;
for(int i = _agent.CurrentPathingIndex + 1; i < _agent.Path.Count; i++)
{
PathCount++;
Vector3 NextPoint = _agent.Path[i];
_linePoints.Add(NextPoint);
}
_line.positionCount = PathCount;
_line.SetPositions(_linePoints.ToArray());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c649545522b2ab4b95a1fb7d7ef8974
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4c2dd48d02935c94a83797754f33fe7c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,415 @@
using HPJ.Simulation;
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation.Agents
{
[System.Serializable]
public class SimAgent
{
/// <summary>
/// The ID for each simulation Agent
/// </summary>
public static ushort SimIDCounter = 1; // SimID of zero means no agent
public ushort SimID { get; protected set; }
/// <summary>
/// The corresponding Navigation Agent for this Simulation Agent
/// </summary>
public SimNavigationAgent NavAgent { get; protected set; }
/// <summary>
/// Position of the simulation agent
/// </summary>
public Vector3 Position { get; protected set; }
/// <summary>
/// Whether agent avoidance is active
/// </summary>
public bool AgentAvoidenceActive { get; internal set; }
/// <summary>
/// Whether the base agent should call the on moving complete call
/// </summary>
public bool CallOnMovingComplete { get; internal set; }
/// <summary>
/// Whether the base agent should call the on recieved path call
/// </summary>
public bool CallOnRecievePath { get; internal set; }
/// <summary>
/// Updates to the Core Agents position
/// </summary>
public bool UpdateToUnity { get; internal set; }
/// <summary>
/// Tile owned by the Agent
/// </summary>
public IntVector2 OwnedTile { get; internal set; }
public static IntVector2 NullTile = -IntVector2.One;
/// <summary>
/// Creates and Initializes the Agent
/// </summary>
/// <param name="Agent"></param>
public SimAgent(SimNavigationAgent Agent, bool UseAgentAvoidence)
{
SimID = SimIDCounter;
SimIDCounter++;
AgentAvoidenceActive = UseAgentAvoidence;
NavAgent = Agent;
UpdatePositionFromAgent();
}
/// <summary>
/// Updates the agent simuliarily the unity version of Navigaiton Agent gets updated
/// </summary>
public void Update()
{
if (UpdateToUnity)
{
UpdateToUnity = false;
UpdatePosition(NavAgent.DesiredPosition);
}
if (NavAgent.State == AgentStates.Moving)
{
NavAgent._lerpPercentage += NavigationManager.Instance.HelperDeltaTime * NavAgent.MovementSpeed / NavAgent._lerpTotal;
UpdatePosition(Vector3.Lerp(NavAgent.Path[NavAgent.CurrentPathingIndex], NavAgent.Path[NavAgent.CurrentPathingIndex + 1], NavAgent._lerpPercentage));
// Make sure the current tile for this agent is Valid
if (NavAgent.ValidateCurrentTile)
{
if (!NavAgent.ValidateStandingTile())
{
// This Path is invalid, so needs to be recalculated
if (NavAgent.CurrentOrder.NavJob.CurrentPath != null)
{
lock (NavAgent.CurrentOrder.NavJob.CurrentPath)
{
NavAgent.CurrentOrder.NavJob.CurrentPath.ValidPath = false;
}
}
// Move to closest Valid Tile and repath
NavAgent.CurrentTileIndex = NavAgent.CurrentOrder.StartingMap.GetClosestValidIndex(NavAgent.CurrentTileIndex, NavAgent.TraversableTiles, SimID);
NavAgent.CurrentTileType = NavigationManager.Instance.GetTileTypeForMap(NavAgent.CurrentTileIndex, NavAgent.CurrentOrder.StartingMap);
UpdatePosition(NavigationManager.Instance.GetTileCenterWorldPosition(NavAgent.CurrentTileIndex, NavAgent.CurrentOrder.StartingMap));
if (NavAgent.Settings.OnFailAttemptToNearestPoint)
{
NavAgent.ReadjustToNearestPoint();
}
else
{
NavAgent.SetDestination(NavAgent.WantedDestination);
}
return;
}
}
if (NavAgent._lerpPercentage >= 1f)
{
// Go to NEXT index
NavAgent.CurrentPathingIndex++;
UpdatePosition(NavAgent.Path[NavAgent.CurrentPathingIndex]);
if (NavAgent.CurrentPathingIndex >= NavAgent.Path.Count - 1)
{
// Completed
if (NavAgent.CurrentOrder.Destination == NavAgent.CurrentOrder.CheckPointDestination)
{
//Debug.Log("At Destination");
CallOnMovingComplete = true;
NavAgent.State = AgentStates.Idle;
}
// Find Destination
else
{
//Debug.Log("At Current Destination");
NavAgent.SetDestination(NavAgent.CurrentOrder.Destination);
}
}
else
{
NavAgent.CurrentDirection = NavAgent.Path[NavAgent.CurrentPathingIndex + 1] - NavAgent.Path[NavAgent.CurrentPathingIndex];
NavAgent.CurrentDirection = new Vector3(NavAgent.CurrentDirection.x, 0, NavAgent.CurrentDirection.z);
NavAgent._lerpPercentage = 0;
NavAgent._lerpTotal = NavAgent.CurrentDirection.magnitude;
}
}
// Local Advoidance
if (NavAgent.AutoValidateCurrentPath)
{
NavAgent._autoValidateTimer += NavigationManager.Instance.HelperDeltaTime;
if (NavAgent._autoValidateTimer > NavAgent.AutoValidateTime)
{
// By this point the pathing may be over
if (NavAgent.State == AgentStates.Moving)
{
if (!NavAgent.CurrentPathIsValid(NavAgent.LocalAvoidanceRange))
{
NavAgent._autoValidateTimer = 0;
if (NavAgent.CurrentOrder != null && NavAgent.CurrentOrder.NavJob != null)
{
if (NavAgent.CurrentOrder.NavJob.CurrentPath != null)
{
lock (NavAgent.CurrentOrder.NavJob.CurrentPath)
{
NavAgent.CurrentOrder.NavJob.CurrentPath.ValidPath = false;
}
}
}
NavAgent.ReadjustToNearestPoint();
}
}
}
}
}
else if (NavAgent.CurrentOrder.PathfindingStep == PathfindingCalculationStep.Complete)
{
CallOnRecievePath = true;
}
else if (NavAgent.State != AgentStates.Paused && NavAgent.State != AgentStates.Stopped)
{
// Keep the agent in a valid position
if (NavAgent.CurrentOrder.StartingMap == null)
{
NavAgent.CurrentOrder.StartingMap = NavigationManager.Instance.GetCurrentMap(Position);
NavAgent.CurrentMap = NavAgent.CurrentOrder.StartingMap;
}
if (NavAgent.CurrentOrder.StartingMap == null)
{
return;
}
if (NavAgent.ValidateCurrentTile)
{
if (!NavAgent.ValidateStandingTile())
{
// Move to closest Valid Tile and repath
NavAgent.CurrentTileIndex = NavAgent.CurrentOrder.StartingMap.GetClosestValidIndex(NavAgent.CurrentTileIndex, NavAgent.TraversableTiles, SimID);
NavAgent.CurrentTileType = NavigationManager.Instance.GetTileTypeForMap(NavAgent.CurrentTileIndex, NavAgent.CurrentOrder.StartingMap);
UpdatePosition(NavigationManager.Instance.GetTileCenterWorldPosition(NavAgent.CurrentTileIndex, NavAgent.CurrentOrder.StartingMap));
}
}
if (NavAgent.FailedLastPath)
{
if (NavAgent.KeepAttemptingOnFail)
{
NavAgent._keepAttemptingTimer += NavigationManager.Instance.HelperDeltaTime;
if (NavAgent._keepAttemptingTimer >= NavAgent.KeepAttemptingTime)
{
NavAgent._keepAttemptingTimer = 0;
if (NavAgent.Settings.OnFailAttemptToNearestPoint)
{
NavAgent.ReadjustToNearestPoint();
}
else
{
NavAgent.SetDestination(NavAgent.WantedDestination);
}
}
}
}
if (AgentAvoidenceActive)
{
if (OwnedTile == NullTile)
{
RecheckOwnership();
}
}
if (NavAgent.Settings.KeepTryingToReadjustToWantedPosition)
{
if (NavAgent.WantedDestination != Position)
{
NavAgent.ReadjustToNearestPoint();
}
}
}
}
/// <summary>
/// Updates the position to the position of the Agent
/// </summary>
internal void UpdatePositionFromAgent()
{
UpdatePosition(NavAgent.transform.position);
}
/// <summary>
/// Internal way to update position and tile ownership for the agent
/// </summary>
protected void UpdatePosition(Vector3 NewPosition)
{
if (AgentAvoidenceActive)
{
if (NavAgent.CurrentMap != null)
{
IntVector2 NewTilePosition = NavigationManager.Instance.GetTileIndexForMap(NewPosition, NavAgent.CurrentMap);
if (NavAgent.CurrentMap.OutOfRange(NewTilePosition))
{
MapSet NewMap = NavigationManager.Instance.GetMapAtWorldPosition(NewPosition);
if (NewMap != null)
{
NewTilePosition = NavigationManager.Instance.GetTileIndexForMap(NewPosition, NewMap);
NavAgent.SetCurrentMap(NewMap);
if (NewTilePosition != OwnedTile || NavAgent.CurrentMap.BaseMap.AgentOwnershipMap.Tiles[OwnedTile.x, OwnedTile.y] != SimID)
{
NavAgent.CurrentMap.DisownClaim(OwnedTile, SimID);
if (NavAgent.CurrentMap.AttemptClaim(NewTilePosition, SimID))
{
OwnedTile = NewTilePosition;
}
else
{
OwnedTile = NullTile;
}
}
}
}
else
{
// Unown previous tile
if (OwnedTile != NullTile)
{
if (NewTilePosition != OwnedTile || NavAgent.CurrentMap.BaseMap.AgentOwnershipMap.Tiles[OwnedTile.x, OwnedTile.y] != SimID)
{
NavAgent.CurrentMap.DisownClaim(OwnedTile, SimID);
if (NavAgent.CurrentMap.AttemptClaim(NewTilePosition, SimID))
{
OwnedTile = NewTilePosition;
}
else
{
OwnedTile = NullTile;
}
}
}
}
}
else
{
MapSet NewMap = NavigationManager.Instance.GetMapAtWorldPosition(NewPosition);
if (NewMap != null)
{
NavAgent.SetCurrentMap(NewMap);
IntVector2 NewTilePosition = NavigationManager.Instance.GetTileIndexForMap(NewPosition, NewMap);
if (NavAgent.CurrentMap.AttemptClaim(NewTilePosition, SimID))
{
OwnedTile = NewTilePosition;
}
else
{
OwnedTile = NullTile;
}
}
else
{
OwnedTile = NullTile;
}
}
}
Position = NewPosition;
}
/// <summary>
/// Rechecks the ownership of the tile
/// </summary>
public void RecheckOwnership()
{
if (AgentAvoidenceActive)
{
if (NavAgent.CurrentMap != null)
{
IntVector2 NewTilePosition = NavigationManager.Instance.GetTileIndexForMap(Position, NavAgent.CurrentMap);
if (NavAgent.CurrentMap.OutOfRange(NewTilePosition))
{
MapSet NewMap = NavigationManager.Instance.GetMapAtWorldPosition(Position);
if (NewMap != null)
{
NewTilePosition = NavigationManager.Instance.GetTileIndexForMap(Position, NewMap);
NavAgent.SetCurrentMap(NewMap);
if (NewTilePosition != OwnedTile || NavAgent.CurrentMap.BaseMap.AgentOwnershipMap.Tiles[OwnedTile.x, OwnedTile.y] == 0)
{
if (OwnedTile != NullTile)
{
NavAgent.CurrentMap.DisownClaim(OwnedTile, SimID);
}
if (NavAgent.CurrentMap.AttemptClaim(NewTilePosition, SimID))
{
OwnedTile = NewTilePosition;
}
else
{
OwnedTile = NullTile;
}
}
}
}
else
{
if (NewTilePosition != OwnedTile || NavAgent.CurrentMap.BaseMap.AgentOwnershipMap.Tiles[OwnedTile.x, OwnedTile.y] == 0)
{
if (OwnedTile != NullTile)
{
NavAgent.CurrentMap.DisownClaim(OwnedTile, SimID);
}
if (NavAgent.CurrentMap.AttemptClaim(NewTilePosition, SimID))
{
OwnedTile = NewTilePosition;
}
else
{
OwnedTile = NullTile;
}
}
}
}
else
{
MapSet NewMap = NavigationManager.Instance.GetMapAtWorldPosition(Position);
if (NewMap != null)
{
NavAgent.SetCurrentMap(NewMap);
IntVector2 NewTilePosition = NavigationManager.Instance.GetTileIndexForMap(Position, NewMap);
if (NavAgent.CurrentMap.AttemptClaim(NewTilePosition, SimID))
{
OwnedTile = NewTilePosition;
}
else
{
OwnedTile = NullTile;
}
}
else
{
OwnedTile = NullTile;
}
}
}
}
/// <summary>
/// Make sure to remove this agent when it's destroyed
/// </summary>
internal void OnDestroy()
{
if (NavAgent.CurrentMap != null)
{
NavAgent.CurrentMap.DisownClaim(OwnedTile, SimID);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fc363d003b9fc02438defff04aa53423
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,482 @@
using HPJ.Simulation;
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation.Agents
{
public class SimNavigationAgent : NavigationAgent
{
/// <summary>
/// Simulation Counterpart of this agent
/// </summary>
public SimAgent SimulationAgent { get; protected set; }
/// <summary>
/// Whether sim agents are using Agent Avoidence
/// </summary>
public bool UsingAgentAvoidence { get; protected set; }
/// <summary>
/// Adds the Agent to the Navigation Manager as a simulation agent
/// </summary>
protected override void AddToManager()
{
if (NavigationManager.Instance == null)
{
Invoke(nameof(AddToManager), 0.1f);
return;
}
if (!NavigationManager.Instance)
{
Invoke(nameof(AddToManager), 0.1f);
return;
}
if (NavigationManager.Instance.MapSets.Count <= 0)
{
return;
}
UsingAgentAvoidence = NavigationManager.Instance.ManagerSettings.SimulationSettings.UseAgentAvoidance;
IntVector3 StartPosition = NavigationManager.Instance.GetTileWorldPosition(transform.position);
CurrentMap = NavigationManager.Instance.GetMapAtTileWorldPosition(StartPosition);
StartingMap = NavigationManager.Instance.GetMapAtTileWorldPosition(StartPosition);
SimulationAgent.AgentAvoidenceActive = NavigationManager.Instance.ManagerSettings.SimulationSettings.UseAgentAvoidance;
NavigationManager.Instance.AddSimAgent(this);
UpdateAgentPosition(transform.position);
}
public override void UpdateAgentState()
{
if (transform.position != SimulationAgent.Position)
{
transform.position = SimulationAgent.Position;
}
if (SimulationAgent.CallOnMovingComplete)
{
SimulationAgent.CallOnMovingComplete = false;
OnMovingComplete?.Invoke(this);
}
if (SimulationAgent.CallOnRecievePath)
{
SimulationAgent.CallOnRecievePath = false;
RecievePathingInfoCallback();
}
}
protected override void OnDrawGizmosSelected()
{
base.OnDrawGizmosSelected();
if (GizmosSettings.ShowClosestValidTileToWantedPosition)
{
if (NavigationManager.Instance != null && CurrentMap != null)
{
Gizmos.color = Color.blue;
Vector3 SquareSize = Vector3.one * CurrentMap.SetSettings.MapSettings.TileSize / 100;
SquareSize.x -= 0.05f;
SquareSize.y = 0.1f;
SquareSize.z -= 0.05f;
IntVector2 WantedIndex = NavigationManager.Instance.GetTileIndexForMap(WantedDestination, CurrentMap);
WantedIndex = CurrentMap.GetClosestValidIndex(WantedIndex, _settings.TraversableTiles, SimulationAgent.SimID);
Vector3 TilePosition = NavigationManager.Instance.GetTileCenterWorldPosition(WantedIndex, CurrentMap);
Gizmos.DrawCube(TilePosition, SquareSize);
}
}
}
/// <summary>
/// The Callback for when the agent recieves its path
/// </summary>
protected override void RecievePathingInfoCallback()
{
if (State == AgentStates.Stopped)
{
return;
}
// Ignore Previous orders if there is a duplication or previous uncompleted order
CurrentOrder.SetPath(Path);
if (CurrentOrder.NavJob.CurrentPath != null && CurrentOrder.NavJob.CurrentPath.ValidPath)
{
State = AgentStates.SucceededPathing;
}
else if (CurrentOrder.DestinationState == DestinationStates.NextMap_FromBridge || CurrentOrder.DestinationState == DestinationStates.NextMap_FromSeam)
{
State = AgentStates.SucceededPathing;
}
else
{
State = AgentStates.FailedPathing;
}
FailedLastPath = false;
CurrentOrder.PathfindingStep = PathfindingCalculationStep.Finalized;
if (State == AgentStates.SucceededPathing)
{
OnPathfindingSucceed?.Invoke(this);
_currentMovementPathIndex = 0;
SetInitialPositionToPath();
if (CurrentOrder.Recenter)
{
UpdateAgentPosition(Path[_currentMovementPathIndex]);
}
if (_settings.GroundCheck)
{
GroundCast?.PhysicsCheck();
}
_currentDirection = Path[_currentMovementPathIndex + 1] - Path[_currentMovementPathIndex];
_currentDirection.y = 0;
_lerpPercentage = 0;
_lerpTotal = _currentDirection.magnitude;
if (PreviousState != AgentStates.Paused)
{
State = AgentStates.Moving;
}
else
{
State = AgentStates.Paused;
}
}
else if (State == AgentStates.FailedPathing)
{
FailedLastPath = true;
State = AgentStates.Idle;
OnPathfindingFailed?.Invoke(this);
}
}
/// <summary>
/// The Position you want to update the agent to
/// </summary>
public Vector3 DesiredPosition { get; protected set; }
/// <summary>
/// Used to adjust the agent position in the simulation. Note make sure that the state is not moving or the agent will teleport back to it's simulated position
/// </summary>
public void UpdateAgentPosition(Vector3 NewPosition, bool AutocancelPathing = false)
{
if (AutocancelPathing)
{
Idle();
}
DesiredPosition = NewPosition;
SimulationAgent.UpdateToUnity = true;
}
/// <summary>
/// Tells you if the current tile the unit is on is valid
/// </summary>
/// <returns></returns>
public override bool ValidateStandingTile()
{
if (CurrentOrder.DestinationState == DestinationStates.NextMap_FromBridge || CurrentOrder.DestinationState == DestinationStates.NextMap_FromSeam)
{
return true;
}
if (CurrentMap != null)
{
CurrentTileIndex = NavigationManager.Instance.GetTileIndexForMap(SimulationAgent.Position, CurrentMap);
CurrentTileType = NavigationManager.Instance.GetTileTypeForMap(CurrentTileIndex, CurrentMap);
if (!TraversableTiles.Contains(CurrentTileType))
{
return false;
}
}
if (SimulationAgent.AgentAvoidenceActive)
{
IntVector2 TilePosition = CurrentMap.GetMapTileIndex(NavigationManager.Instance.GetTileWorldPosition(SimulationAgent.Position));
if (!CurrentMap.BaseMap.AgentOwnershipMap.ValidTileForAgent(SimulationAgent.SimID, TilePosition.x, TilePosition.y))
{
if (SimulationAgent.OwnedTile == TilePosition)
{
SimulationAgent.OwnedTile = -IntVector2.One;
}
return false;
}
}
return true;
}
/// <summary>
/// Checks the tiles in the path to see if they are still valid
/// </summary>
/// <param name="Range"></param>
/// <returns></returns>
public override bool CurrentPathIsValid(int Range = -1)
{
// You are on a bridge, so it will automatically be true
if (CurrentOrder.DestinationState == DestinationStates.NextMap_FromBridge || CurrentOrder.DestinationState == DestinationStates.NextMap_FromSeam)
{
return true;
}
else if (CurrentOrder.DestinationState == DestinationStates.SameMap || CurrentOrder.DestinationState == DestinationStates.Bridge || CurrentOrder.DestinationState == DestinationStates.ClosestPoint)
{
// Reaffirm current Index
if (!ValidateStandingTile())
{
return false;
}
// This is to keep track of the path
int validationPathIndex = _currentMovementPathIndex + 1;
if (Range == -1)
{
Range = int.MaxValue;
}
int RangeCounter = 0;
// Calculate this section
IntVector2 NextDestinationIndexPosition = NavigationManager.Instance.GetTileIndexForMap(Path[validationPathIndex], CurrentOrder.StartingMap);
IntVector2 Direction = new IntVector2();
if (CurrentTileIndex.x < NextDestinationIndexPosition.x)
{
Direction.x = 1;
}
else if (CurrentTileIndex.x > NextDestinationIndexPosition.x)
{
Direction.x = -1;
}
else
{
Direction.x = 0;
}
if (CurrentTileIndex.y < NextDestinationIndexPosition.y)
{
Direction.y = 1;
}
else if (CurrentTileIndex.y > NextDestinationIndexPosition.y)
{
Direction.y = -1;
}
else
{
Direction.y = 0;
}
// Set the tracking tile
IntVector2 TrackingTile = CurrentTileIndex;
while (TrackingTile != NextDestinationIndexPosition)
{
TrackingTile += Direction;
if (!ValidateTileIndex(TrackingTile, CurrentOrder.StartingMap))
{
return false;
}
RangeCounter++;
if (RangeCounter > Range)
{
return true;
}
}
// Check the next sections of the path
validationPathIndex++;
while (validationPathIndex < Path.Count)
{
NextDestinationIndexPosition = NavigationManager.Instance.GetTileIndexForMap(Path[validationPathIndex], CurrentOrder.StartingMap);
if (TrackingTile.x < NextDestinationIndexPosition.x)
{
Direction.x = 1;
}
else if (TrackingTile.x > NextDestinationIndexPosition.x)
{
Direction.x = -1;
}
else
{
Direction.x = 0;
}
if (TrackingTile.y < NextDestinationIndexPosition.y)
{
Direction.y = 1;
}
else if (TrackingTile.y > NextDestinationIndexPosition.y)
{
Direction.y = -1;
}
else
{
Direction.y = 0;
}
// Set the tracking tile
while (TrackingTile != NextDestinationIndexPosition)
{
TrackingTile += Direction;
if (!ValidateTileIndex(TrackingTile, CurrentOrder.StartingMap))
{
return false;
}
RangeCounter++;
if (RangeCounter > Range)
{
return true;
}
}
validationPathIndex++;
}
return true;
}
return false;
}
/// <summary>
/// This tells you if the current tile index is valid for this unit
/// </summary>
/// <param name="TileIndex"></param>
/// <returns></returns>
public override bool ValidateTileIndex(IntVector2 TileIndex, MapSet Map)
{
if (!TraversableTiles.Contains(NavigationManager.Instance.GetTileTypeForMap(TileIndex, Map)))
{
return false;
}
if (UsingAgentAvoidence)
{
if (Map == null)
{
return false;
}
if (!Map.BaseMap.AgentOwnershipMap.ValidTileForAgent(SimulationAgent.SimID, TileIndex.x, TileIndex.y))
{
return false;
}
}
return true;
}
/// <summary>
/// Sets the destination to the nearest valid point near the desired destination
/// </summary>
/// <param name="Destination"></param>
/// <param name="RecenterOnTile"></param>
/// <param name="SetWantedDestination"></param>
public override void SetDestinationToNearestPoint(Vector3 Destination, bool RecenterOnTile = false)
{
if (CurrentOrder.PathfindingStep == PathfindingCalculationStep.Pathfinding)
{
return;
}
State = AgentStates.Pathfinding;
CurrentOrder.SetPrevious();
CurrentOrder.Clear();
IntVector3 WorldTilePosition = NavigationManager.Instance.GetTileWorldPosition(Destination);
MapSet EndingMap = NavigationManager.Instance.GetMapAtTileWorldPosition(NavigationManager.Instance.GetTileWorldPosition(Destination));
if (NavigationManager.Instance.ManagerSettings.SimulationSettings.UseAgentAvoidance)
{
IntVector2 TileIndex = EndingMap.GetMapTileIndex(WorldTilePosition);
if (!_settings.TraversableTiles.Contains(EndingMap.GetTileType(TileIndex)) || !EndingMap.BaseMap.AgentOwnershipMap.ValidTileForAgent(SimulationAgent.SimID, TileIndex.x, TileIndex.y))
{
SetDestination(EndingMap.GetWorldTileIndex(EndingMap.GetClosestValidIndex(TileIndex, _settings.TraversableTiles, SimulationAgent.SimID)), true);
}
else
{
SetDestination(Destination);
}
}
else
{
if (!_settings.TraversableTiles.Contains(EndingMap.GetTileType(WorldTilePosition)))
{
SetDestination(EndingMap.GetWorldTileIndex(EndingMap.GetClosestValidIndex(EndingMap.GetMapTileIndex(WorldTilePosition), _settings.TraversableTiles)), true);
}
else
{
SetDestination(Destination);
}
}
}
/// <summary>
/// Sets the destination to the nearest valid point near the desired destination
/// </summary>
/// <param name="Destination"></param>
/// <param name="RecenterOnTile"></param>
/// <param name="SetWantedDestination"></param>
protected override void SetDestinationToNearestPoint(IntVector3 Destination, bool RecenterOnTile = false)
{
if (CurrentOrder.PathfindingStep == PathfindingCalculationStep.Pathfinding)
{
return;
}
State = AgentStates.Pathfinding;
CurrentOrder.SetPrevious();
CurrentOrder.Clear();
MapSet EndingMap = NavigationManager.Instance.GetMapAtTileWorldPosition(Destination);
if (NavigationManager.Instance.ManagerSettings.SimulationSettings.UseAgentAvoidance)
{
IntVector2 TileIndex = EndingMap.GetMapTileIndex(Destination);
if (!_settings.TraversableTiles.Contains(EndingMap.GetTileType(TileIndex)) || !EndingMap.BaseMap.AgentOwnershipMap.ValidTileForAgent(SimulationAgent.SimID, TileIndex.x, TileIndex.y))
{
SetDestination(EndingMap.GetWorldTileIndex(EndingMap.GetClosestValidIndex(TileIndex, _settings.TraversableTiles, SimulationAgent.SimID)), true);
}
else
{
SetDestination(Destination);
}
}
else
{
if (!_settings.TraversableTiles.Contains(EndingMap.GetTileType(Destination)))
{
SetDestination(EndingMap.GetWorldTileIndex(EndingMap.GetClosestValidIndex(EndingMap.GetMapTileIndex(Destination), _settings.TraversableTiles)), true);
}
else
{
SetDestination(Destination);
}
}
}
/// <summary>
/// Helps get the current position for this agent. Sim agents override this to use the simagent position
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
internal override Vector3 GetCurrentPosition()
{
return SimulationAgent.Position;
}
protected override void Awake()
{
base.Awake();
SimulationAgent = new SimAgent(this, false);
CurrentOrder.NavJob.AgentID = SimulationAgent.SimID;
}
protected override void OnDestroy()
{
if (NavigationManager.Instance != null && NavigationManager.Instance.Running)
{
SimulationAgent?.OnDestroy();
NavigationManager.Instance?.RemoveSimAgent(this);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 53cb4b6f50173b44dbb35bd1007d19d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c4d0b4f704fd2524b9c526c68324c99c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0153f7f8eb3299d41b9260b296d021a1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bc9ffc400bd794459494c21a8e1c02a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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,
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b17b55d52e05634985d0f59c45f969b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad8ef4b58a73e034aa00ac06b2beda9b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c129247b250ac5a4d8e6f226334f33a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f5cb57ca0c3261f43bc33de524b38013
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,773 @@
using HPJ.Simulation;
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif
using UnityEngine;
#if UNITY_EDITOR
namespace HPJ.Presentation.UnityEditor
{
[CustomEditor(typeof(NavigationManager))]
public class NavigationManagerEditor : Editor
{
private int NearestHandle = -1;
private Vector3 _previousMousePosition;
private int _previousTileAmount;
private IntVector3 _previousOffset;
private bool _shifted = false;
private bool _controlDown = false;
private bool _paintButtonDown = false;
private bool _removePaintButtonDown = false;
private void OnEnable()
{
NavigationManager example = (NavigationManager)target;
example.AttemptedBridge = null;
example.LoadMaps();
}
//private void OnDisable()
//{
// NavigationManager example = (NavigationManager)target;
// example.AttemptedBridge = null;
// example.SaveMaps();
//}
protected virtual void OnSceneGUI()
{
#if UNITY_EDITOR
NavigationManager example = (NavigationManager)target;
if (Application.IsPlaying(example))
{
return;
}
// Do not allow edits while baking
if (example.Baking)
{
return;
}
var view = SceneView.currentDrawingSceneView;
if (view == null)
{
return;
}
EditorGUI.BeginChangeCheck();
Event e = Event.current;
// Find out where we clicked
Vector3 mousePos = e.mousePosition;
float ppp = EditorGUIUtility.pixelsPerPoint;
mousePos.y = view.camera.pixelHeight - mousePos.y * ppp;
mousePos.x *= ppp;
//Debug.Log($"Try To Paint");
Ray ray = view.camera.ScreenPointToRay(mousePos);
MapSet ClosestMapSet = null;
float ClosestScore = float.MaxValue;
Vector3 ClosestPosition = new Vector3();
int Index = -1;
foreach (MapSet Set in example.MapSets)
{
Index++;
if (example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(Index))
{
continue;
}
Plane MapPlane = new Plane(Vector3.up, new Vector3(Set.SetSettings.MapSettings.Offset.x / 100f, Set.SetSettings.MapSettings.Offset.y / 100f, Set.SetSettings.MapSettings.Offset.z / 100f));
if (MapPlane.Raycast(ray, out float Enter))
{
Vector3 HitPosition = ray.GetPoint(Enter);
if (example.ValidPoint(HitPosition, Set))
{
//Debug.Log($"Scored a Hit at Position {HitPosition} on map {Set.SetSettings.Name} - Score {Enter}");
if (Enter < ClosestScore)
{
ClosestMapSet = Set;
ClosestScore = Enter;
ClosestPosition = HitPosition;
}
}
}
}
if (example.MapSets.Count <= 0)
{
return;
}
if (example.GizmosSettings.DisplayGizmos)
{
if (example.GizmosSettings.DisplayMapArrows)
{
if (e.type == EventType.Repaint)
{
for (int i = 0; i < example.MapSets.Count; i++)
{
if (example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(i))
{
continue;
}
MapSet mapSet = example.MapSets[i];
// Figure out positions
Vector3 OffsetPosition = new Vector3(mapSet.SetSettings.MapSettings.Offset.x, mapSet.SetSettings.MapSettings.Offset.y, mapSet.SetSettings.MapSettings.Offset.z);
OffsetPosition /= 100f;
Vector3 BottomPosition = OffsetPosition + Vector3.right * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapWidth / 200f;
Vector3 LeftPosition = OffsetPosition + Vector3.forward * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapHeight / 200f;
Vector3 TopPosition = BottomPosition + Vector3.forward * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapHeight / 100f;
Vector3 RightPosition = LeftPosition + Vector3.right * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapWidth / 100f;
// Draw Arrows and Handles
int ClosestIndex = HandleUtility.nearestControl;
Handles.color = ClosestIndex == i * 10 ? Color.white : Color.green;
Handles.ArrowHandleCap(i * 10, LeftPosition, Quaternion.LookRotation(Vector3.left), example.GizmosSettings.DisplayArrowSize, EventType.Repaint);
Handles.color = ClosestIndex == i * 10 + 1 ? Color.white : Handles.xAxisColor;
Handles.ArrowHandleCap(i * 10 + 1, RightPosition, Quaternion.LookRotation(Vector3.right), example.GizmosSettings.DisplayArrowSize, EventType.Repaint);
Handles.color = ClosestIndex == i * 10 + 2 ? Color.white : Color.yellow;
Handles.ArrowHandleCap(i * 10 + 2, BottomPosition, Quaternion.LookRotation(Vector3.back), example.GizmosSettings.DisplayArrowSize, EventType.Repaint);
Handles.color = ClosestIndex == i * 10 + 3 ? Color.white : Handles.zAxisColor;
Handles.ArrowHandleCap(i * 10 + 3, TopPosition, Quaternion.LookRotation(Vector3.forward), example.GizmosSettings.DisplayArrowSize, EventType.Repaint);
}
}
if (e.type == EventType.Layout)
{
//example.LoadMaps();
for (int i = 0; i < example.MapSets.Count; i++)
{
if (example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(i))
{
continue;
}
MapSet mapSet = example.MapSets[i];
// Figure out positions
Vector3 OffsetPosition = new Vector3(mapSet.SetSettings.MapSettings.Offset.x, mapSet.SetSettings.MapSettings.Offset.y, mapSet.SetSettings.MapSettings.Offset.z);
OffsetPosition /= 100f;
Vector3 BottomPosition = OffsetPosition + Vector3.right * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapWidth / 200f;
Vector3 LeftPosition = OffsetPosition + Vector3.forward * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapHeight / 200f;
Vector3 TopPosition = BottomPosition + Vector3.forward * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapHeight / 100f;
Vector3 RightPosition = LeftPosition + Vector3.right * mapSet.SetSettings.MapSettings.TileSize * mapSet.SetSettings.MapSettings.MapWidth / 100f;
// Draw Arrows and Handles
Handles.ArrowHandleCap(i * 10, LeftPosition, Quaternion.LookRotation(Vector3.left), example.GizmosSettings.DisplayArrowSize, EventType.Layout);
Handles.ArrowHandleCap(i * 10 + 1, RightPosition, Quaternion.LookRotation(Vector3.right), example.GizmosSettings.DisplayArrowSize, EventType.Layout);
Handles.ArrowHandleCap(i * 10 + 2, BottomPosition, Quaternion.LookRotation(Vector3.back), example.GizmosSettings.DisplayArrowSize, EventType.Layout);
Handles.ArrowHandleCap(i * 10 + 3, TopPosition, Quaternion.LookRotation(Vector3.forward), example.GizmosSettings.DisplayArrowSize, EventType.Layout);
}
}
}
}
if (e.type == EventType.KeyDown)
{
if (e.keyCode == KeyCode.LeftShift)
{
_shifted = true;
}
if (e.keyCode == KeyCode.LeftControl)
{
_controlDown = true;
}
if (e.keyCode == KeyCode.C)
{
_paintButtonDown = true;
}
if (e.keyCode == KeyCode.V)
{
_removePaintButtonDown = true;
}
}
if (e.type == EventType.KeyUp)
{
if (e.keyCode == KeyCode.LeftShift)
{
_shifted = false;
}
if (e.keyCode == KeyCode.LeftControl)
{
_controlDown = false;
}
if (e.keyCode == KeyCode.C)
{
_paintButtonDown = false;
}
if (e.keyCode == KeyCode.V)
{
_removePaintButtonDown = false;
}
}
if (example.GizmosSettings.DisplayGizmos)
{
if (e.type == EventType.MouseDown)
{
if (Event.current.button == 0)
{
if (_shifted)
{
NearestHandle = HandleUtility.nearestControl;
if (NearestHandle != -1 && example.MapSets.Count > 0)
{
int Direction = NearestHandle % 10;
int MapIndex = (NearestHandle - Direction) / 10;
if (MapIndex >= 0 && MapIndex < example.MapSets.Count)
{
MapSet set = example.MapSets[MapIndex];
_previousMousePosition = e.mousePosition;
_previousOffset = set.SetSettings.MapSettings.Offset;
if (Direction == 0)
{
_previousTileAmount = set.SetSettings.MapSettings.MapWidth;
}
// Left / Right on the Right side of the Map
else if (Direction == 1)
{
_previousTileAmount = set.SetSettings.MapSettings.MapWidth;
}
// Up / Down on the Top side of the Map (This changes the off set as well)
else if (Direction == 3)
{
_previousTileAmount = set.SetSettings.MapSettings.MapHeight;
}
// Up / Down on the Bottom side of the Map (This changes the off set as well)
else if (Direction == 2)
{
_previousTileAmount = set.SetSettings.MapSettings.MapHeight;
}
}
}
}
}
}
if (e.type == EventType.MouseUp && Event.current.button == 0)
{
NearestHandle = -1;
_previousMousePosition = Vector3.zero;
_previousOffset = IntVector3.Zero;
_previousTileAmount = -1;
}
if (e.type == EventType.MouseDrag && Event.current.button == 0)
{
if (_shifted)
{
if (example.GizmosSettings.DisplayMapArrows)
{
//Debug.Log("Try to move Handle");
//Selection.SetActiveObjectWithContext(example, view);
if (NearestHandle != -1 && example.MapSets.Count > 0)
{
//Debug.Log("Should move Handle");
// Figure out which direction and map was selected
int Direction = NearestHandle % 10;
int MapIndex = (NearestHandle - Direction) / 10;
if (MapIndex >= 0 && MapIndex < example.MapSets.Count)
{
GUI.changed = true;
MapSet set = example.MapSets[MapIndex];
Vector3 OffsetPosition = new Vector3(set.SetSettings.MapSettings.Offset.x, set.SetSettings.MapSettings.Offset.y, set.SetSettings.MapSettings.Offset.z) / 100f;
// Left / Right on the Left side of the Map
if (Direction == 0)
{
OffsetPosition += Vector3.forward * set.SetSettings.MapSettings.TileSize * set.SetSettings.MapSettings.MapHeight / 200;
float MoveAmount = HandleUtility.CalcLineTranslation(_previousMousePosition, e.mousePosition, OffsetPosition, Vector3.left);
int Translation = Mathf.FloorToInt(MoveAmount * 100 / set.SetSettings.MapSettings.TileSize);
set.SetSettings.MapSettings.AdjustMap(_previousTileAmount + Translation, MapExpansionSide.Left, _previousOffset.x - Translation * 100, -Translation);
}
// Left / Right on the Right side of the Map
else if (Direction == 1)
{
OffsetPosition += Vector3.forward * set.SetSettings.MapSettings.TileSize * set.SetSettings.MapSettings.MapHeight / 200 + Vector3.right * set.SetSettings.MapSettings.TileSize * set.SetSettings.MapSettings.MapWidth / 100;
float MoveAmount = HandleUtility.CalcLineTranslation(_previousMousePosition, e.mousePosition, OffsetPosition, Vector3.right);
int NewAmount = Mathf.FloorToInt(MoveAmount * 100 / set.SetSettings.MapSettings.TileSize);
set.SetSettings.MapSettings.AdjustMap(_previousTileAmount + NewAmount, MapExpansionSide.Right, _previousOffset.x);
}
// Up / Down on the Top side of the Map (This changes the off set as well)
else if (Direction == 3)
{
OffsetPosition += Vector3.right * set.SetSettings.MapSettings.TileSize * set.SetSettings.MapSettings.MapWidth / 200 + Vector3.forward * set.SetSettings.MapSettings.TileSize * set.SetSettings.MapSettings.MapHeight/ 100;
float MoveAmount = HandleUtility.CalcLineTranslation(_previousMousePosition, e.mousePosition, OffsetPosition, Vector3.forward);
int NewAmount = Mathf.FloorToInt(MoveAmount * 100 / set.SetSettings.MapSettings.TileSize);
set.SetSettings.MapSettings.AdjustMap(_previousTileAmount + NewAmount, MapExpansionSide.Top, _previousOffset.z);
}
// Up / Down on the Bottom side of the Map (This changes the off set as well)
else if (Direction == 2)
{
OffsetPosition += Vector3.right * set.SetSettings.MapSettings.TileSize * set.SetSettings.MapSettings.MapWidth / 200;
float MoveAmount = HandleUtility.CalcLineTranslation(_previousMousePosition, e.mousePosition, OffsetPosition, Vector3.back);
int Translation = Mathf.FloorToInt(MoveAmount * 100 / set.SetSettings.MapSettings.TileSize);
set.SetSettings.MapSettings.AdjustMap(_previousTileAmount + Translation, MapExpansionSide.Bottom, _previousOffset.z - Translation * 100, -Translation);
}
}
}
}
}
}
if (_paintButtonDown && !_removePaintButtonDown)
{
if (example.GizmosSettings.DisplayPaintBrush)
{
if (_shifted)
{
if (ClosestMapSet != null)
{
GUI.changed = true;
//Debug.Log($"Hit Position {ClosestPosition} on map {ClosestMapSet.SetSettings.Name}");
ClosestMapSet.ChangeDefaultTileType(example.GetTileWorldPosition(ClosestPosition), example.Painter.CurrentPainterType, example.Painter.CurrentPainterRadius, example.Painter.PainterType);
}
}
}
}
else if (_removePaintButtonDown)
{
if (_shifted)
{
if (ClosestMapSet != null)
{
GUI.changed = true;
//Debug.Log($"Hit Position {ClosestPosition} on map {ClosestMapSet.SetSettings.Name}");
ClosestMapSet.ChangeDefaultTileType(example.GetTileWorldPosition(ClosestPosition), TileTypes.Standard, example.Painter.CurrentPainterRadius, example.Painter.PainterType);
}
}
}
if (example.GizmosSettings.DisplayMapLabels)
{
for (int i = 0; i < example.MapSets.Count; i++)
{
if (example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(i))
{
continue;
}
MapSet mapSet = example.MapSets[i];
// Figure out positions
Vector3 OffsetPosition = new Vector3(mapSet.SetSettings.MapSettings.Offset.x, mapSet.SetSettings.MapSettings.Offset.y, mapSet.SetSettings.MapSettings.Offset.z) / 100f;
Handles.color = Color.black;
Handles.Label(OffsetPosition + Vector3.left * 10 + Vector3.back * 10, $"({mapSet.SetSettings.Name})");
}
}
if (example.GizmosSettings.DisplayMapHandles)
{
for (int i = 0; i < example.MapSets.Count; i++)
{
if (example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !example.GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(i))
{
continue;
}
MapSet mapSet = example.MapSets[i];
// Figure out positions
Vector3 OffsetPosition = new Vector3(mapSet.SetSettings.MapSettings.Offset.x, mapSet.SetSettings.MapSettings.Offset.y, mapSet.SetSettings.MapSettings.Offset.z) / 100f;
// Draw Map Position
Vector3 newTargetPosition = Handles.PositionHandle(OffsetPosition, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
mapSet.SetSettings.MapSettings.Offset = new IntVector3((int)(newTargetPosition.x * 100f), (int)(newTargetPosition.y * 100f), (int)(newTargetPosition.z * 100f));
}
mapSet.SetSettings.MapSettings.UpdateMapSize();
}
}
//EditorGUI.BeginChangeCheck();
if (example.GizmosSettings.DisplayBridges)
{
for (int i = 0; i < example.Bridges.Count; i++)
{
for (int j = 0; j < example.Bridges[i].MidPoints.Count; j++)
{
Vector3 MidPoint = new Vector3(example.Bridges[i].MidPoints[j].x, example.Bridges[i].MidPoints[j].y, example.Bridges[i].MidPoints[j].z) / 100f;
Vector3 newTargetPosition = Handles.PositionHandle(MidPoint, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
example.Bridges[i].MidPoints[j] = new IntVector3((int)(newTargetPosition.x * 100), (int)(newTargetPosition.y * 100), (int)(newTargetPosition.z * 100));
}
if (j == 0)
{
Handles.Label(newTargetPosition + Vector3.left + Vector3.back, $"(Map A {example.Bridges[i].MapA.SetSettings.Name}- {j} - Bridge {i})");
}
else if (j == example.Bridges[i].MidPoints.Count - 1)
{
Handles.Label(newTargetPosition + Vector3.left + Vector3.back, $"(Map B {example.Bridges[i].MapB.SetSettings.Name}- {j} - Bridge {i})");
}
else
{
Handles.Label(newTargetPosition + Vector3.left + Vector3.back, $"({j})");
}
}
}
if (example.AttemptedBridge != null)
{
for (int j = 0; j < example.AttemptedBridge.MidPoints.Count; j++)
{
Vector3 MidPoint = new Vector3(example.AttemptedBridge.MidPoints[j].x, example.AttemptedBridge.MidPoints[j].y, example.AttemptedBridge.MidPoints[j].z) / 100f;
Vector3 newTargetPosition = Handles.PositionHandle(MidPoint, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
example.AttemptedBridge.MidPoints[j] = new IntVector3((int)(newTargetPosition.x * 100), (int)(newTargetPosition.y * 100), (int)(newTargetPosition.z * 100));
}
Handles.Label(newTargetPosition + Vector3.left + Vector3.back, $"({j})");
}
}
}
}
if (GUI.changed)
{
EditorUtility.SetDirty(example);
EditorSceneManager.MarkSceneDirty(example.gameObject.scene);
}
if (e.type == EventType.KeyDown)
{
if (e.keyCode == KeyCode.S && _controlDown)
{
serializedObject.ApplyModifiedProperties();
example.SaveMaps();
}
}
#endif
}
bool IsMapFoldout = false;
bool IsPainterFoldout = false;
bool IsBridgeFoldout = false;
bool MiscButtonsFoldout = false;
bool ControlsFildOut = false;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
NavigationManager example = (NavigationManager)target;
EditorGUILayout.Space();
ControlsFildOut = EditorGUILayout.Foldout(ControlsFildOut, "Controls");
if (ControlsFildOut)
{
IsMapFoldout = EditorGUILayout.Foldout(IsMapFoldout, "Map Buttons");
if (IsMapFoldout)
{
if (GUILayout.Button("Create New Map"))
{
Undo.RecordObject(this, "Create New Map");
MapSet newMap = new MapSet();
newMap.SetSettings.MapSettings.TileSize = 100;
newMap.SetSettings.MapSettings.MapWidth = 100;
newMap.SetSettings.MapSettings.MapHeight = 100;
newMap.SetSettings.MapSettings.Offset = new IntVector3();
bool NoDuplicateNames = false;
int IterationCount = 0;
string BaseName = newMap.SetSettings.Name;
while (!NoDuplicateNames)
{
IterationCount++;
NoDuplicateNames = true;
foreach (MapSet set in example.MapSets)
{
if (set.SetSettings.Name == newMap.SetSettings.Name)
{
newMap.SetSettings.Name = $"{BaseName} ({IterationCount})";
NoDuplicateNames = false;
}
}
}
// Add Default Data
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Standard, 100));
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Blocked, 0));
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Obstacle, 0));
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Water, 70));
example.MapSets.Add(newMap);
for (int i = 0; i < example.MapSets.Count; i++)
{
example.MapSets[i].InstanceID = i;
}
}
if (GUILayout.Button("Delete All Maps"))
{
Undo.RecordObject(this, "Delete All Maps");
example.MapSets.Clear();
}
if (GUILayout.Button("Create Map Grid"))
{
Undo.RecordObject(this, "Create Map Grid");
MapSet[,] NewMaps = new MapSet[example.ManagerSettings.MapAutoCreationGridSize.x, example.ManagerSettings.MapAutoCreationGridSize.y];
for (int x = 0; x < example.ManagerSettings.MapAutoCreationGridSize.x; x++)
{
for (int y = 0; y < example.ManagerSettings.MapAutoCreationGridSize.y; y++)
{
MapSet newMap = new MapSet();
newMap.SetSettings.MapSettings.TileSize = example.ManagerSettings.MapAutoGridTileSize;
newMap.SetSettings.MapSettings.MapWidth = example.ManagerSettings.MapAutoGridTileWidthAndHeight.x;
newMap.SetSettings.MapSettings.MapHeight = example.ManagerSettings.MapAutoGridTileWidthAndHeight.y;
IntVector3 AdditionOffset = new IntVector3();
AdditionOffset.x = x * example.ManagerSettings.MapAutoGridTileSize * example.ManagerSettings.MapAutoGridTileWidthAndHeight.x;
AdditionOffset.z = y * example.ManagerSettings.MapAutoGridTileSize * example.ManagerSettings.MapAutoGridTileWidthAndHeight.y;
newMap.SetSettings.MapSettings.Offset = AdditionOffset + example.ManagerSettings.MapAutoGridOffset;
bool NoDuplicateNames = false;
int IterationCount = 0;
string BaseName = newMap.SetSettings.Name;
while (!NoDuplicateNames)
{
IterationCount++;
NoDuplicateNames = true;
foreach (MapSet set in example.MapSets)
{
if (set.SetSettings.Name == newMap.SetSettings.Name)
{
newMap.SetSettings.Name = $"{BaseName} ({IterationCount})";
NoDuplicateNames = false;
}
}
}
// Add Default Data
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Standard, 100));
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Blocked, 0));
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Obstacle, 0));
newMap.SetSettings.MapSettings.TileData.Add(new TileData(TileTypes.Water, 70));
example.MapSets.Add(newMap);
NewMaps[x,y] = newMap;
for (int i = 0; i < example.MapSets.Count; i++)
{
example.MapSets[i].InstanceID = i;
}
}
}
if (example.ManagerSettings.MapAutoGridAutoSeam)
{
for (int x = 0; x < example.ManagerSettings.MapAutoCreationGridSize.x; x++)
{
for (int y = 0; y < example.ManagerSettings.MapAutoCreationGridSize.y; y++)
{
bool ConnectRight = x < example.ManagerSettings.MapAutoCreationGridSize.x - 1;
bool ConnectUp = y < example.ManagerSettings.MapAutoCreationGridSize.y - 1;
MapSet IndexMap = NewMaps[x, y];
MapSet NextMap;
if (ConnectRight)
{
NextMap = NewMaps[x + 1, y];
MapSeam NewSeam = new MapSeam(IndexMap, NextMap, SeamConnectionSide.East, SeamConnectionSide.West);
example.Seams.Add(NewSeam);
}
if (ConnectUp)
{
NextMap = NewMaps[x, y + 1];
MapSeam NewSeam = new MapSeam(IndexMap, NextMap, SeamConnectionSide.North, SeamConnectionSide.South);
example.Seams.Add(NewSeam);
}
}
}
}
}
if (GUILayout.Button("Save Maps"))
{
Undo.RecordObject(this, "Save Maps");
example.SaveMaps();
}
if (GUILayout.Button("Load Maps"))
{
Undo.RecordObject(this, "Load Maps");
example.LoadMaps();
}
}
IsPainterFoldout = EditorGUILayout.Foldout(IsPainterFoldout, "Auto-Painter / Painter Buttons");
if (IsPainterFoldout)
{
string MapToAutopaint = "None";
if (example.AutoPainter.AutoPaintMapIndex >= 0 && example.AutoPainter.AutoPaintMapIndex < example.MapSets.Count)
{
MapToAutopaint = example.MapSets[example.AutoPainter.AutoPaintMapIndex].SetSettings.Name;
}
if (GUILayout.Button($"Auto Paint {MapToAutopaint}"))
{
Undo.RecordObject(this, $"Auto Paint {MapToAutopaint}");
example.AutoPaint();
}
string MapToClean = "None";
if (example.Painter.CleanMapIndex >= 0 && example.Painter.CleanMapIndex < example.MapSets.Count)
{
MapToClean = example.MapSets[example.Painter.CleanMapIndex].SetSettings.Name;
}
if (GUILayout.Button($"Clean Map {MapToClean}"))
{
Undo.RecordObject(this, $"Clean Map {MapToClean}");
example.ClearMap();
}
}
IsBridgeFoldout = EditorGUILayout.Foldout(IsBridgeFoldout, "Bridge Buttons");
if (IsBridgeFoldout)
{
if (GUILayout.Button("Attempt Bridge Creation"))
{
Undo.RecordObject(this, "Attempt Bridge Creation");
example.AttemptedBridge = new MapBridge(null, null, new List<IntVector3>() { new IntVector3(), new IntVector3() });
}
if (GUILayout.Button("Complete Bridge Creation"))
{
Undo.RecordObject(this, "Complete New Bridge");
if (example.AttemptedBridge != null)
{
example.AttemptedBridge.MapA = example.GetMapAtTileWorldPosition(example.AttemptedBridge.MidPoints[0]);
example.AttemptedBridge.MapB = example.GetMapAtTileWorldPosition(example.AttemptedBridge.MidPoints[example.AttemptedBridge.MidPoints.Count - 1]);
if (example.AttemptedBridge.MapB != null && example.AttemptedBridge.MapA != null)
{
example.Bridges.Add(example.AttemptedBridge);
EditorUtility.SetDirty(example);
EditorSceneManager.MarkSceneDirty(example.gameObject.scene);
}
example.AttemptedBridge = null;
}
}
if (GUILayout.Button("Add Bridge Point to Attempt"))
{
Undo.RecordObject(this, "Add Bridge Point to Attempt");
if (example.AttemptedBridge != null)
{
IntVector3 MidPointPosition = (example.AttemptedBridge.MidPoints[example.AttemptedBridge.MidPoints.Count - 1] - example.AttemptedBridge.MidPoints[example.AttemptedBridge.MidPoints.Count - 2]) / 2 + example.AttemptedBridge.MidPoints[example.AttemptedBridge.MidPoints.Count - 2];
example.AttemptedBridge.MidPoints.Insert(example.AttemptedBridge.MidPoints.Count - 1, MidPointPosition);
}
}
if (GUILayout.Button("Add Bridge Point to Index"))
{
Undo.RecordObject(this, "Add Bridge Point to Index");
//Debug.Log($"Attempt Point {example.InsertBridgePointIndex} / {example.Bridges.Count}");
if (example.GizmosSettings.InsertBridgePointIndex > -1 && example.GizmosSettings.InsertBridgePointIndex < example.Bridges.Count)
{
MapBridge Bridge = example.Bridges[example.GizmosSettings.InsertBridgePointIndex];
IntVector3 MidPointPosition = (Bridge.MidPoints[Bridge.MidPoints.Count - 1] - Bridge.MidPoints[Bridge.MidPoints.Count - 2]) / 2 + Bridge.MidPoints[Bridge.MidPoints.Count - 2];
Bridge.MidPoints.Insert(Bridge.MidPoints.Count - 1, MidPointPosition);
//Debug.Log("Insert Point");
}
}
if (GUILayout.Button("Remove Bridge Point to Attempt"))
{
Undo.RecordObject(this, "Remove Bridge Point to Attempt");
if (example.AttemptedBridge != null)
{
if (example.AttemptedBridge.MidPoints.Count > 2)
{
example.AttemptedBridge.MidPoints.RemoveAt(example.AttemptedBridge.MidPoints.Count - 2);
}
}
}
if (GUILayout.Button("Remove Bridge Point to Index"))
{
Undo.RecordObject(this, "Remove Bridge Point to Index");
if (example.GizmosSettings.InsertBridgePointIndex != -1 && example.GizmosSettings.InsertBridgePointIndex >= example.Bridges.Count)
{
MapBridge Bridge = example.Bridges[example.GizmosSettings.InsertBridgePointIndex];
if (Bridge.MidPoints.Count > 2)
{
Bridge.MidPoints.RemoveAt(Bridge.MidPoints.Count - 2);
}
}
}
}
MiscButtonsFoldout = EditorGUILayout.Foldout(MiscButtonsFoldout, "Seam Buttons");
if (MiscButtonsFoldout)
{
string ButtonString = "Can't Create Seam";
if (example.MapSets.Count > 0)
{
if (example.MapSeamSettings.MapAInsertSettings.MapIndex != example.MapSeamSettings.MapBInsertSettings.MapIndex)
{
if (example.MapSeamSettings.MapAInsertSettings.MapIndex != -1 && example.MapSets.Count > example.MapSeamSettings.MapAInsertSettings.MapIndex)
{
if (example.MapSeamSettings.MapBInsertSettings.MapIndex != -1 && example.MapSets.Count > example.MapSeamSettings.MapBInsertSettings.MapIndex)
{
ButtonString = $"Create Seam: {example.MapSets[example.MapSeamSettings.MapAInsertSettings.MapIndex].SetSettings.Name}[{example.MapSeamSettings.MapAInsertSettings.ConnectionSide}] to {example.MapSets[example.MapSeamSettings.MapBInsertSettings.MapIndex].SetSettings.Name}[{example.MapSeamSettings.MapBInsertSettings.ConnectionSide}]";
}
}
}
}
if (GUILayout.Button(ButtonString))
{
Undo.RecordObject(this, ButtonString);
if (ButtonString != "Can't Create Seam")
{
example.CreateSeam();
}
}
}
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3c42d38bf6f6a544ea34ba5b5ea5138a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f1e5b1dc4033536408e59166591e3bac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,134 @@
using HPJ.Presentation.Agents;
using HPJ.Simulation;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation
{
[RequireComponent(typeof(NavigationAgent))]
public class AgentAreaDisplay : MonoBehaviour
{
[SerializeField]
private AreaDisplayTile _tilePrefab;
private Transform TileSpawn;
[SerializeField]
private bool _showTilesOutOfReach = true;
[SerializeField]
private int _range = 25;
[SerializeField]
private float _updatePeriod = 1;
private float _updateTime = 0;
private List<AreaDisplayTile> _activeTiles = new List<AreaDisplayTile>();
private List<AreaDisplayTile> _pool = new List<AreaDisplayTile>();
private NavigationAgent _agent;
private void Awake()
{
TileSpawn = new GameObject($"Tile Spawn for {name}").transform;
_agent = GetComponent<NavigationAgent>();
_updateTime = _updatePeriod + 1;
}
// Update is called once per frame
void Update()
{
if (NavigationManager.Instance == null)
{
return;
}
if (!NavigationManager.Instance)
{
return;
}
if (NavigationManager.Instance.MapSets.Count <= 0)
{
return;
}
_updateTime += Time.deltaTime;
if (_updateTime >= _updatePeriod)
{
_updateTime = 0;
UpdateTiles();
}
}
public void UpdateTiles()
{
//Debug.Log("Update Tiles");
ReturnAllTiles();
List<IntVector2> TilesInRangeBySteps = _agent.GetTraversableTilesInRangeBySteps(_range);
if (TilesInRangeBySteps.Count == 0 && _updatePeriod > 1)
{
Invoke(nameof(UpdateTiles), 0.1f);
return;
}
if (_showTilesOutOfReach)
{
List<IntVector2> TilesInRange = _agent.GetTraversableTilesInRange(_range);
foreach (IntVector2 Tile in TilesInRange)
{
AreaDisplayTile NewTile = GetTile();
NewTile.Set(_agent.CurrentMap, Tile, TilesInRangeBySteps.Contains(Tile));
}
}
else
{
foreach (IntVector2 Tile in TilesInRangeBySteps)
{
AreaDisplayTile NewTile = GetTile();
NewTile.Set(_agent.CurrentMap, Tile, true);
}
}
}
protected AreaDisplayTile GetTile()
{
if (_pool.Count > 0)
{
AreaDisplayTile NewTile = _pool[0];
_pool.RemoveAt(0);
NewTile.gameObject.SetActive(true);
_activeTiles.Add(NewTile);
return NewTile;
}
else
{
AreaDisplayTile NewTile = Instantiate(_tilePrefab, TileSpawn);
NewTile.Initialize(_agent.CurrentMap.SetSettings.MapSettings.TileSize);
_activeTiles.Add(NewTile);
return NewTile;
}
}
protected void ReturnTile(AreaDisplayTile Tile)
{
Tile.gameObject.SetActive(false);
_pool.Add(Tile);
_activeTiles.Remove(Tile);
}
protected void ReturnAllTiles()
{
foreach(AreaDisplayTile Tile in _activeTiles)
{
Tile.gameObject.SetActive(false);
_pool.Add(Tile);
}
_activeTiles.Clear();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d7e0c2278be67a94fa98c85390af48ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using HPJ.Simulation;
using HPJ.Simulation.Map;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation
{
public class AreaDisplayTile : MonoBehaviour
{
[SerializeField]
private Material _canReachMaterial;
[SerializeField]
private Material _cannotReachMaterial;
[SerializeField]
private MeshRenderer _meshRenderer;
public IntVector2 CurrentTileIndex { get; protected set; }
public void Initialize(int TileSize)
{
transform.localScale = new Vector3(0.9f * TileSize, 0.5f * TileSize, 0.9f * TileSize) / 100f;
}
public void Set(MapSet Map, IntVector2 TileIndex, bool CanReach)
{
if (CanReach)
{
_meshRenderer.material = _canReachMaterial;
}
else
{
_meshRenderer.material = _cannotReachMaterial;
}
CurrentTileIndex = TileIndex;
transform.position = NavigationManager.Instance.GetTileCenterWorldPosition(TileIndex, Map);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08ba8e78e34cf95459d2de572d20afbf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
using HPJ.Presentation.Agents;
using UnityEngine;
namespace HPJ.Presentation
{
/// <summary>
/// Am Example script to display the local avoidance feature
/// </summary>
public class LocalAvoidanceSceneScript : MonoBehaviour
{
public Transform StartTransform;
public Transform EndTransform;
public NavigationAgent AgentPrefab;
private NavigationAgent _firstAgent;
private bool _direction = false;
private void Start()
{
_firstAgent = Instantiate(AgentPrefab, StartTransform.position, Quaternion.identity);
_firstAgent.OnMovingComplete.AddListener(RepeatDestination);
_firstAgent?.GroundCast?.TeleportUp();
_firstAgent.SetDestination(EndTransform.position);
}
private void RepeatDestination(NavigationAgent Agent)
{
if (_direction)
{
Agent.SetDestination(EndTransform.position);
}
else
{
Agent.SetDestination(StartTransform.position);
}
_direction = !_direction;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10ae043c214aca94bbf2d32548004712
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,149 @@
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation
{
/// <summary>
/// The Map Sprite Renderer is a set of sprite renderers that render the tile state of a desired map.
/// </summary>
[RequireComponent(typeof(SpriteRenderer))]
public class MapSpriteRenderer : MonoBehaviour
{
[SerializeField]
protected float UpdatePeriod = 1; // How often the sprite updates
protected float UpdateTimer = 0;
[SerializeField]
protected int DesiredMapIndex; // The desired map you want
[SerializeField]
protected List<TileColorData> ColorData = new List<TileColorData>(); // Colors you want to display for each tile type
protected Dictionary<TileTypes, TileColorData> SortedData = new Dictionary<TileTypes, TileColorData>();
protected SpriteRenderer SpriteRen; // The Base Sprite renderer for the tile colors
[SerializeField]
protected SpriteRenderer GridSpriteRen; // The grid sprite renderer
private void Awake()
{
FirstUpdate = true;
SpriteRen = GetComponent<SpriteRenderer>();
UpdateTimer = UpdatePeriod;
foreach(TileTypes TileType in System.Enum.GetValues(typeof(TileTypes)))
{
foreach(TileColorData Data in ColorData)
{
if (Data.TileType == TileType)
{
SortedData.Add(TileType, Data);
continue;
}
}
if (SortedData.ContainsKey(TileType))
{
continue;
}
SortedData.Add(TileType, new TileColorData(Color.clear, TileType));
}
}
private void Update()
{
if (NavigationManager.Instance == null)
{
return;
}
if (!NavigationManager.Instance)
{
return;
}
if (DesiredMapIndex < 0 || DesiredMapIndex >= NavigationManager.Instance.MapSets.Count)
{
return;
}
UpdateTimer += Time.deltaTime;
if (UpdateTimer >= UpdatePeriod)
{
UpdateTimer = 0;
UpdateSprite();
}
}
protected bool FirstUpdate = true;
protected Texture2D tex;
protected Color[] colors;
/// <summary>
/// Updates the sprite to match the current state of the desired map
/// </summary>
public void UpdateSprite()
{
MapSet Map = NavigationManager.Instance.MapSets[DesiredMapIndex];
if (FirstUpdate)
{
//Debug.Log("Set Position");
tex = new Texture2D(Map.SetSettings.MapSettings.MapWidth, Map.SetSettings.MapSettings.MapHeight);
colors = new Color[Map.SetSettings.MapSettings.MapWidth * Map.SetSettings.MapSettings.MapHeight];
transform.localScale = new Vector3((Map.SetSettings.MapSettings.MapHeight + 1) * Map.SetSettings.MapSettings.TileSize / 100f, (Map.SetSettings.MapSettings.MapHeight + 1) * Map.SetSettings.MapSettings.TileSize / 100f, 1);
Vector3 Position = new Vector3();
Position.x = Map.SetSettings.MapSettings.MapWidth * Map.SetSettings.MapSettings.TileSize / 200f + Map.SetSettings.MapSettings.Offset.x / 100f;
Position.y = Map.SetSettings.MapSettings.Offset.y / 100f + 0.005f;
Position.z = Map.SetSettings.MapSettings.MapHeight * Map.SetSettings.MapSettings.TileSize / 200f + Map.SetSettings.MapSettings.Offset.z / 100f;
transform.position = Position;
GridSpriteRen.transform.SetParent(null);
GridSpriteRen.transform.localScale = new Vector3(Map.SetSettings.MapSettings.TileSize / 100f, Map.SetSettings.MapSettings.TileSize / 100f, 1);
GridSpriteRen.size = new Vector2(Map.SetSettings.MapSettings.MapWidth * Map.SetSettings.MapSettings.TileSize / 100f, Map.SetSettings.MapSettings.MapHeight * Map.SetSettings.MapSettings.TileSize / 100f) * 100f / Map.SetSettings.MapSettings.TileSize;
GridSpriteRen.transform.position += new Vector3(0, 0.01f, 0);
GridSpriteRen.transform.SetParent(transform);
FirstUpdate = false;
}
for(int x = 0; x < Map.SetSettings.MapSettings.MapWidth; x++)
{
for (int y = 0; y < Map.SetSettings.MapSettings.MapHeight; y++)
{
int index = y * Map.SetSettings.MapSettings.MapWidth + x;
colors[index] = SortedData[Map.GetTileType(x, y)].TileColor;
}
}
tex.SetPixels(colors);
tex.filterMode = FilterMode.Point;
tex.Apply();
Sprite sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
SpriteRen.sprite = sprite;
//Debug.Log("Update SpriteRenderer");
}
}
/// <summary>
/// The Color data for a given tile type
/// </summary>
[System.Serializable]
public struct TileColorData
{
public Color TileColor;
public TileTypes TileType;
public TileColorData(Color color, TileTypes Type)
{
TileColor = color;
TileType = Type;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c4d029a33c7005498d6fa43f0f85d9b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEngine;
namespace HPJ.Presentation
{
public class MoveTowardsPoint : MonoBehaviour
{
public Transform target;
public float speed = 5f;
public float acceleration = 2f;
private void Start()
{
transform.SetParent(null);
}
private void Update()
{
// Get the direction to the target
Vector3 direction = target.position - transform.position;
// Calculate the distance to the target
float distance = direction.magnitude;
// Move towards the target
if (distance > 0.1f)
{
// Calculate the current speed
float currentSpeed = speed + acceleration * distance;
// Normalize the direction vector
direction.Normalize();
transform.position += direction * currentSpeed * Time.deltaTime;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 497eadcd7a52d844fa7c95e8ebf69c6d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,168 @@
using HPJ.Presentation.Agents;
using HPJ.Simulation;
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using HPJ.Simulation.Pathing;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation
{
/// <summary>
/// The example scene to display random pathing
/// </summary>
public class RandomPathsExampleScene : MonoBehaviour
{
[SerializeField]
private float _getRandomPointEvery = 0.5f;
private float _timer = 0;
[SerializeField]
private int _randomTileDistanceVariance = 5;
[SerializeField]
private int _randomRange = 25;
[SerializeField]
private NavigationAgent _testAgent;
[SerializeField]
private LineRenderer _testLine;
private NavigationJob _testJob;
private List<Vector3> _linePoints = new List<Vector3>();
public bool PaththingCompleted { get; set; }
public IntVector3 PreviousRandomDestination { get; protected set; }
public int RandomMode = 0;
private void Awake()
{
_testJob = new NavigationJob(OnCompleteCallback);
Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = true;
}
public void OnCompleteCallback()
{
_testJob.CurrentStep = PathfindingCalculationStep.Finalized;
PaththingCompleted = true;
}
// Update is called once per frame
void Update()
{
if (_testJob.CurrentStep == PathfindingCalculationStep.Pathfinding)
{
return;
}
_timer += Time.deltaTime;
if (_timer >= _getRandomPointEvery)
{
_timer = 0;
// Define the plane in world space
Plane plane = new Plane(Vector3.up, Vector3.zero);
// Cast a ray from the camera to the mouse position
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Calculate the distance from the ray origin to the intersection with the plane
float distance;
if (plane.Raycast(ray, out distance))
{
Vector3 hitPoint = ray.GetPoint(distance);
if (_testAgent.CurrentMap != null)
{
if (NavigationManager.Instance.ValidPoint(hitPoint, _testAgent.CurrentMap))
{
_testJob.Clear();
IntVector3 RandomDestination;
if (RandomMode == 1)
{
RandomDestination = _testAgent.GetRandomDestination(_randomRange);
}
else if (RandomMode == 2)
{
RandomDestination = _testAgent.GetRandomDestinationAwayFromPoint(hitPoint, _randomTileDistanceVariance);
}
else
{
RandomDestination = _testAgent.GetRandomDestinationNearPoint(hitPoint, _randomTileDistanceVariance);
}
_testJob.SetDestinationInfo(NavigationManager.Instance.GetTileWorldPosition(_testAgent.transform.position), RandomDestination, _testAgent.TraversableTiles, _testAgent.PrefferedTiles, _testAgent.NavigationType, _testAgent.CurrentMap, true);
NavigationManager.Instance.SetDestination(_testJob);
PreviousRandomDestination = RandomDestination;
}
else if (NavigationManager.Instance.ValidPoint(hitPoint, out MapSet HitMap))
{
_testJob.Clear();
IntVector3 RandomDestination;
if (RandomMode == 1)
{
RandomDestination = _testAgent.GetRandomDestination(_randomRange);
}
else if (RandomMode == 2)
{
RandomDestination = _testAgent.GetRandomDestinationAwayFromPoint(hitPoint, _randomTileDistanceVariance);
}
else
{
RandomDestination = _testAgent.GetRandomDestinationNearPoint(hitPoint, _randomTileDistanceVariance);
}
_testJob.SetDestinationInfo(NavigationManager.Instance.GetTileWorldPosition(_testAgent.transform.position), RandomDestination, _testAgent.TraversableTiles, _testAgent.PrefferedTiles, _testAgent.NavigationType, _testAgent.CurrentMap, true);
NavigationManager.Instance.SetDestination(_testJob);
PreviousRandomDestination = RandomDestination;
}
}
}
}
else if (PaththingCompleted)
{
PaththingCompleted = false;
UpdateLine();
}
if (Input.GetMouseButtonDown(1))
{
_testAgent.SetDestination(PreviousRandomDestination);
}
if (Input.GetKeyDown(KeyCode.Alpha1))
{
RandomMode = 0;
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
RandomMode = 1;
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
RandomMode = 2;
}
}
private void UpdateLine()
{
//Debug.Log("Update Line");
_linePoints.Clear();
if (_testJob.CurrentPath.Path.Count <= 0)
{
_testLine.positionCount = 0;
return;
}
for (int i = 0; i < _testJob.CurrentPath.Path.Count; i++)
{
Vector3 NextPoint = NavigationManager.Instance.GetTileCenterWorldPosition(_testJob.CurrentPath.Path[i], _testAgent.CurrentMap);
NextPoint.y += 0.01f;
_linePoints.Add(NextPoint);
}
_testLine.positionCount = _testJob.CurrentPath.Path.Count;
_testLine.SetPositions(_linePoints.ToArray());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ac9cbf46f291f16429ede3c990e2d99e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using HPJ.Presentation.Agents;
using HPJ.Simulation;
using HPJ.Simulation.Map;
using System.Collections;
using UnityEngine;
namespace HPJ.Presentation.Sample
{
/// <summary>
/// The all round example scene script
/// </summary>
public class SampleSceneScript : MonoBehaviour
{
[SerializeField]
private int _agentSpawnCount = 100;
[SerializeField]
private NavigationAgent TestAgents;
[SerializeField]
private bool _rollOutSlow = false;
[SerializeField]
private bool _closeRangeRandomPosition = false;
[SerializeField]
private int _closeRangeRadius = 50;
[SerializeField]
private bool _keepAgentsOnSameMap = false;
private void Start()
{
if (_rollOutSlow)
{
StartCoroutine(RollOutSlow());
}
else
{
StartCoroutine(RollOut());
}
}
private IEnumerator RollOutSlow()
{
while (NavigationManager.Instance == null)
{
yield return null;
}
while (!NavigationManager.Instance.Initialized)
{
yield return null;
}
yield return null;
for (int i = 0; i < _agentSpawnCount; i++)
{
Vector3 RandomPosition = NavigationManager.Instance.GetRandomValidPosition(TestAgents.TraversableTiles, true);
NavigationAgent Agent = Instantiate(TestAgents, RandomPosition, Quaternion.identity);
Agent.transform.SetParent(transform);
Agent.OnMovingComplete.AddListener(SetRandomDestination);
Agent?.GroundCast?.TeleportUp();
Vector3 RandomDestination;
if (_closeRangeRandomPosition)
{
IntVector3 RandomPosition_WorldIndex = NavigationManager.Instance.GetTileWorldPosition(RandomPosition);
MapSet map = NavigationManager.Instance.GetCurrentMap(RandomPosition);
RandomDestination = NavigationManager.Instance.GetRandomValidPositionAtPosition(Agent.TraversableTiles, NavigationManager.Instance.GetTileIndexForMap(RandomPosition_WorldIndex, map), _closeRangeRadius, true);
}
else
{
if (_keepAgentsOnSameMap)
{
MapSet map = NavigationManager.Instance.GetCurrentMap(RandomPosition);
Agent.SetCurrentMap(map);
RandomDestination = NavigationManager.Instance.GetRandomValidPosition(Agent.TraversableTiles, map, true);
}
else
{
RandomDestination = NavigationManager.Instance.GetRandomValidPosition(Agent.TraversableTiles, true);
}
}
Agent.SetDestination(RandomDestination);
yield return null;
yield return null;
}
enabled = false;
}
private IEnumerator RollOut()
{
while (NavigationManager.Instance == null)
{
yield return null;
}
while (!NavigationManager.Instance.Initialized)
{
yield return null;
}
yield return null;
for (int i = 0; i < _agentSpawnCount; i++)
{
Vector3 RandomPosition = NavigationManager.Instance.GetRandomValidPosition(TestAgents.TraversableTiles, true);
NavigationAgent Agent = Instantiate(TestAgents, RandomPosition, Quaternion.identity);
Agent.OnMovingComplete.AddListener(SetRandomDestination);
Agent?.GroundCast?.TeleportUp();
Vector3 RandomDestination;
if (_closeRangeRandomPosition)
{
IntVector3 RandomPosition_WorldIndex = NavigationManager.Instance.GetTileWorldPosition(RandomPosition);
MapSet map = NavigationManager.Instance.GetCurrentMap(RandomPosition);
RandomDestination = NavigationManager.Instance.GetRandomValidPositionAtPosition(Agent.TraversableTiles, NavigationManager.Instance.GetTileIndexForMap(RandomPosition_WorldIndex, map), _closeRangeRadius, true);
}
else
{
if (_keepAgentsOnSameMap)
{
MapSet map = NavigationManager.Instance.GetCurrentMap(RandomPosition);
Agent.SetCurrentMap(map);
RandomDestination = NavigationManager.Instance.GetRandomValidPosition(Agent.TraversableTiles, map, true);
}
else
{
RandomDestination = NavigationManager.Instance.GetRandomValidPosition(Agent.TraversableTiles, true);
}
}
Agent.SetDestination(RandomDestination);
}
enabled = false;
}
private void SetRandomDestination(NavigationAgent Agent)
{
Vector3 RandomDestination;
if (_closeRangeRandomPosition)
{
IntVector3 RandomPosition_WorldIndex = NavigationManager.Instance.GetTileWorldPosition(transform.position);
MapSet map = NavigationManager.Instance.GetCurrentMap(transform.position);
RandomDestination = NavigationManager.Instance.GetRandomValidPositionAtPosition(Agent.TraversableTiles, NavigationManager.Instance.GetTileIndexForMap(RandomPosition_WorldIndex, map), _closeRangeRadius, true);
}
else
{
if (_keepAgentsOnSameMap)
{
RandomDestination = NavigationManager.Instance.GetRandomValidPosition(Agent.TraversableTiles, Agent.StartingMap, true);
//Debug.Log($"Random Destination {RandomDestination}");
}
else
{
RandomDestination = NavigationManager.Instance.GetRandomValidPosition(Agent.TraversableTiles, true);
}
}
Agent.SetDestination(RandomDestination);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 726955db545851e45b09d589d5fbe540
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,131 @@
using HPJ.Presentation.Agents;
using HPJ.Simulation;
using HPJ.Simulation.Map;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation
{
/// <summary>
/// This sample script is to spawn and control multiple units to see how swarming runs
/// </summary>
public class SwarmSample : MonoBehaviour
{
[SerializeField]
private int _testSwarmAmount = 50;
[SerializeField]
private SimNavigationAgent _testAgentPrefab;
[SerializeField]
private LayerMask _targetLayer;
public List<SimNavigationAgent> Agents { get; protected set; }
private void Awake()
{
Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = false;
Agents = new List<SimNavigationAgent>();
}
private void Start()
{
StartCoroutine(RollOut());
}
private IEnumerator RollOut()
{
while (NavigationManager.Instance == null)
{
yield return null;
}
while (!NavigationManager.Instance.Initialized)
{
yield return null;
}
yield return null;
for (int i = 0; i < _testSwarmAmount; i++)
{
Vector3 RandomPosition = NavigationManager.Instance.GetRandomValidPosition(_testAgentPrefab.TraversableTiles, true);
SimNavigationAgent Agent = Instantiate(_testAgentPrefab, RandomPosition, Quaternion.identity);
Agent.transform.SetParent(transform);
Agent?.GroundCast?.TeleportUp();
Agents.Add(Agent);
MapSet map = NavigationManager.Instance.GetCurrentMap(RandomPosition);
Agent.SetCurrentMap(map);
yield return null;
}
}
// Update is called once per frame
void Update()
{
// Calculate the distance from the ray origin to the intersection with the plane
if (Input.GetMouseButtonDown(1))
{
RaycastHit hit;
if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, 300f, _targetLayer))
{
Vector3 hitPoint = hit.point;
Debug.Log($"Hit Point {hitPoint}");
for (int i = 0; i < Agents.Count; i++)
{
if (Agents[i].CurrentMap != null)
{
if (NavigationManager.Instance.ValidPoint(hitPoint, Agents[i].CurrentMap))
{
IntVector3 TargetDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
Agents[i].Idle();
Agents[i].SetDestination(TargetDestination, true, true);
}
else if (NavigationManager.Instance.ValidPoint(hitPoint, out MapSet HitMap))
{
Agents[i].SetCurrentMap(HitMap);
IntVector3 TargetDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
Agents[i].Idle();
Agents[i].SetDestination(TargetDestination, true, true);
}
}
else
{
Agents[i].SetCurrentMap(NavigationManager.Instance.GetMapAtWorldPosition(Agents[i].transform.position));
if (NavigationManager.Instance.ValidPoint(hitPoint, Agents[i].CurrentMap))
{
IntVector3 TargetDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
Agents[i].Idle();
Agents[i].SetDestination(TargetDestination, true, true);
}
else if (NavigationManager.Instance.ValidPoint(hitPoint, out MapSet HitMap))
{
Agents[i].SetCurrentMap(HitMap);
IntVector3 TargetDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
Agents[i].Idle();
Agents[i].SetDestination(TargetDestination, true, true);
}
}
}
}
else
{
Debug.Log("Did not hit on Raycast");
}
}
else if (Input.GetKeyDown(KeyCode.Escape))
{
for (int i = 0; i < Agents.Count; i++)
{
Agents[i].Idle();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f64ce63d04a12b344b9487da433e35f3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,143 @@
using HPJ.Presentation.Agents;
using HPJ.Simulation;
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using HPJ.Simulation.Pathing;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation.Sample
{
public class TargetAgentMoveScript : MonoBehaviour
{
[SerializeField]
private NavigationAgent _testAgent;
[SerializeField]
private LayerMask _targetLayer;
private NavigationJob _testJob;
private List<Vector3> _linePoints = new List<Vector3>();
public bool PaththingCompleted { get; set; }
public IntVector3 PreviousDestination { get; protected set; }
private void Awake()
{
_testJob = new NavigationJob(OnCompleteCallback);
Cursor.lockState = CursorLockMode.Confined;
Cursor.visible = true;
}
private void Start()
{
_testAgent.SetCurrentMap(NavigationManager.Instance.GetMapAtWorldPosition(_testAgent.transform.position));
}
public void OnCompleteCallback()
{
_testJob.CurrentStep = PathfindingCalculationStep.Finalized;
PaththingCompleted = true;
}
// Update is called once per frame
void Update()
{
if (_testJob.CurrentStep == PathfindingCalculationStep.Pathfinding)
{
return;
}
if (PaththingCompleted)
{
PaththingCompleted = false;
}
// Calculate the distance from the ray origin to the intersection with the plane
if (Input.GetMouseButtonDown(1))
{
RaycastHit hit;
if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, Mathf.Infinity, _targetLayer))
{
Vector3 hitPoint = hit.point;
if (_testAgent.CurrentMap != null)
{
if (NavigationManager.Instance.ValidPoint(hitPoint, _testAgent.CurrentMap))
{
_testJob.Clear();
IntVector3 RandomDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
_testJob.SetDestinationInfo(NavigationManager.Instance.GetTileWorldPosition(_testAgent.transform.position), RandomDestination, _testAgent.TraversableTiles, _testAgent.PrefferedTiles, _testAgent.NavigationType, _testAgent.CurrentMap, true);
NavigationManager.Instance.SetDestination(_testJob);
PreviousDestination = RandomDestination;
if (PreviousDestination != new IntVector3())
{
_testAgent.Idle();
_testAgent.SetDestination(PreviousDestination);
}
}
else if (NavigationManager.Instance.ValidPoint(hitPoint, out MapSet HitMap))
{
_testJob.Clear();
IntVector3 RandomDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
_testJob.SetDestinationInfo(NavigationManager.Instance.GetTileWorldPosition(_testAgent.transform.position), RandomDestination, _testAgent.TraversableTiles, _testAgent.PrefferedTiles, _testAgent.NavigationType, _testAgent.CurrentMap, true);
NavigationManager.Instance.SetDestination(_testJob);
PreviousDestination = RandomDestination;
if (PreviousDestination != new IntVector3())
{
_testAgent.Idle();
_testAgent.SetDestination(PreviousDestination);
}
}
}
else
{
_testAgent.SetCurrentMap(NavigationManager.Instance.GetMapAtWorldPosition(_testAgent.transform.position));
if (NavigationManager.Instance.ValidPoint(hitPoint, _testAgent.CurrentMap))
{
_testJob.Clear();
IntVector3 RandomDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
_testJob.SetDestinationInfo(NavigationManager.Instance.GetTileWorldPosition(_testAgent.transform.position), RandomDestination, _testAgent.TraversableTiles, _testAgent.PrefferedTiles, _testAgent.NavigationType, _testAgent.CurrentMap, true);
NavigationManager.Instance.SetDestination(_testJob);
PreviousDestination = RandomDestination;
if (PreviousDestination != new IntVector3())
{
_testAgent.Idle();
_testAgent.SetDestination(PreviousDestination);
}
}
else if (NavigationManager.Instance.ValidPoint(hitPoint, out MapSet HitMap))
{
_testJob.Clear();
IntVector3 RandomDestination = NavigationManager.Instance.GetTileWorldPosition(hitPoint);
_testJob.SetDestinationInfo(NavigationManager.Instance.GetTileWorldPosition(_testAgent.transform.position), RandomDestination, _testAgent.TraversableTiles, _testAgent.PrefferedTiles, _testAgent.NavigationType, _testAgent.CurrentMap, true);
NavigationManager.Instance.SetDestination(_testJob);
PreviousDestination = RandomDestination;
if (PreviousDestination != new IntVector3())
{
_testAgent.Idle();
_testAgent.SetDestination(PreviousDestination);
}
}
}
}
else
{
Debug.Log("Did not hit on Raycast");
}
}
else if (Input.GetKeyDown(KeyCode.Escape))
{
_testAgent.Idle();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2417001634632a448e070301ffb1e9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "HPJ.Presentation",
"rootNamespace": "HPJ.Presentation",
"references": [
"GUID:2964754212fd90b4188341fc9783c7d6",
"GUID:478a2357cc57436488a56e564b08d223"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7423525dbbf82fd4dbe9c37aec5245f2
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: