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: a66cfd8039335d040aa244d27a6e4ea7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

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:

View File

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

View File

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

View File

@@ -0,0 +1,81 @@
using System;
namespace HPJ.Simulation.Map
{
public class AgentMap
{
/// <summary>
/// Base map related to this map
/// </summary>
public Map Base { get; protected set; }
/// <summary>
/// Tile that descripe the agent ownership
/// </summary>
public ushort[,] Tiles { get; protected set; }
/// <summary>
/// Initializes the agent map based on the base map
/// </summary>
/// <param name="baseMap"></param>
public AgentMap(Map baseMap)
{
Base = baseMap;
Tiles = new ushort[baseMap.Settings.MapWidth, baseMap.Settings.MapHeight];
}
/// <summary>
/// Disowns this tile so other agents can claim it or to know its availible
/// </summary>
/// <param name="ownedTile"></param>
public void DisownTile(IntVector2 ownedTile, ushort ID)
{
if (ownedTile.x < 0 || ownedTile.y < 0 || ownedTile.x >= Base.Settings.MapWidth || ownedTile.y >= Base.Settings.MapHeight)
{
return;
}
if (Tiles[ownedTile.x, ownedTile.y] == ID)
{
Tiles[ownedTile.x, ownedTile.y] = 0;
}
}
/// <summary>
/// Attempts to claim a tile for a specified ID
/// </summary>
/// <param name="newTilePosition"></param>
/// <param name="ID"></param>
/// <returns></returns>
public bool ClaimTile(IntVector2 newTilePosition, ushort ID)
{
if (newTilePosition.x < 0 || newTilePosition.y < 0 || newTilePosition.x >= Base.Settings.MapWidth || newTilePosition.y >= Base.Settings.MapHeight)
{
return false;
}
if (Tiles[newTilePosition.x, newTilePosition.y] == 0)
{
Tiles[newTilePosition.x, newTilePosition.y] = ID;
return true;
}
return false;
}
internal bool IsBlocked(int x, int y, ushort CompareID)
{
return Tiles[x, y] != 0 && Tiles[x, y] != CompareID;
}
public bool ValidTileForAgent(ushort simNavigationAgentID, int x, int y)
{
if (Tiles[x, y] == 0 || Tiles[x, y] == simNavigationAgentID)
{
return true;
}
return false;
}
}
}

View File

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

View File

@@ -0,0 +1,129 @@
using HPJ.Simulation.Enums;
using HPJ.Simulation.Utilities;
using System.Linq;
namespace HPJ.Simulation.Map
{
/// <summary>
/// A Flattenned version of a map that changes every tile type into a 1 or 0. Is it traverable or is it not
/// </summary>
[System.Serializable]
public class BytePointMap
{
private byte[,] _tiles;
/// <summary>
/// The Tiles for the Byte Map
/// </summary>
public byte[,] Tiles { get { return _tiles; } }
private int _width;
/// <summary>
/// The Width of the Byte Map
/// </summary>
public int Width { get { return _width; } }
private int _length;
/// <summary>
/// The Length of the Byte Map
/// </summary>
public int Length { get { return _length; } }
private bool _cornerCutting;
/// <summary>
/// Whether corner cuttins is enabled on this map
/// </summary>
public bool CornerCutting { get { return _cornerCutting; } set { _cornerCutting = value; } }
private string _traversableKey;
/// <summary>
/// The Key used to flatten the map
/// </summary>
public string TraversableKey { get { return _traversableKey; } }
private TileTypes[] _traversable;
/// <summary>
/// The Tiles that are traversable on this map
/// </summary>
public TileTypes[] Traversable { get { return _traversable; } }
public BytePointMap(byte[,] TileTypeMap, TileTypes[] TraversableTiles, int TileMapWidth, int TileMapLength, bool CornerCuttingEnabled)
{
_traversable = TraversableTiles;
_traversableKey = TraversableTiles.TilesToString();
_cornerCutting = CornerCuttingEnabled;
_tiles = new byte[TileMapWidth, TileMapLength];
_width = TileMapWidth;
_length = TileMapLength;
for (int x = 0; x < TileMapWidth; x++)
{
for (int y = 0; y < TileMapLength; y++)
{
if (_traversable.Contains((TileTypes)TileTypeMap[x, y]))
{
_tiles[x, y] = 100;
}
else
{
_tiles[x, y] = 0;
}
}
}
}
/// <summary>
/// Changes the tile of the byte map
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="newType"></param>
public void ChangeTile(int x, int y, TileTypes newType)
{
if (_traversable.Contains(newType))
{
_tiles[x, y] = 100;
}
else
{
_tiles[x, y] = 0;
}
}
/// <summary>
/// Changes the tile of the byte map
/// </summary>
/// <param name="TileIndex"></param>
/// <param name="newType"></param>
public void ChangeTile(IntVector2 TileIndex, TileTypes newType)
{
if (_traversable.Contains(newType))
{
_tiles[TileIndex.x, TileIndex.y] = 100;
}
else
{
_tiles[TileIndex.x, TileIndex.y] = 0;
}
}
/// <summary>
/// Gets the speed of the tile
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public byte GetTileSpeed(int x, int y)
{
if (x < 0 || x >= _width)
{
return 0;
}
if (y < 0 || y >= _length)
{
return 0;
}
return _tiles[x, y];
}
}
}

View File

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

View File

@@ -0,0 +1,27 @@
using HPJ.Simulation.Enums;
using System.Collections;
using System.Collections.Generic;
namespace HPJ.Simulation.Map
{
[System.Serializable]
public class ChangeMapJob
{
public List<(IntVector2, TileTypes)> TilesToBeChanged;
public ChangeMapJob(List<(IntVector2, TileTypes)> TilesChanged)
{
TilesToBeChanged = TilesChanged;
}
public ChangeMapJob()
{
TilesToBeChanged = new List<(IntVector2, TileTypes)>();
}
public void AddTileChange(IntVector2 TileIndex, TileTypes TypeChange)
{
TilesToBeChanged.Add((TileIndex, TypeChange));
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,26 @@
namespace HPJ.Simulation
{
public struct TileOwnershipClaim
{
public ushort OwnerID;
public IntVector2 RequestTile;
public TileOwnershipClaim(ushort ID, IntVector2 Tile)
{
OwnerID = ID;
RequestTile = Tile;
}
}
public struct DisownTileOwnership
{
public ushort OwnerID;
public IntVector2 RequestTile;
public DisownTileOwnership(ushort ID, IntVector2 Tile)
{
OwnerID = ID;
RequestTile = Tile;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,294 @@
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using HPJ.Simulation.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace HPJ.Simulation.Pathing
{
public class AStar : PathingCalculation
{
public static AStar Instance = null;
public override void Initialize()
{
NavigationType = Enums.NavigationTypes.AStar;
if (!PathingTypes.ContainsKey(NavigationType))
{
PathingTypes.Add(NavigationType, this);
}
}
public override void CalculatePath(NavigationPath Path, Map.Map OccuringMap, out string Status, out bool Succeeded)
{
try
{
List<IntVector2> OpenList = new List<IntVector2>();
HashSet<IntVector2> ClosedList = new HashSet<IntVector2>();
Dictionary<IntVector2, AStarTileData> SortedList = new Dictionary<IntVector2, AStarTileData>();
IntVector2 StartTile = Path.Info.PointA;
IntVector2 EndTile = Path.Info.PointB;
OpenList.Add(StartTile);
AStarTileData StartingTileData = new AStarTileData(new IntVector2(-1, -1), CalculateDistanceCost(StartTile.x, StartTile.y, EndTile.x, EndTile.y));
StartingTileData.GCost = 0;
StartingTileData.FCost = StartingTileData.GCost + StartingTileData.HCost;
SortedList.Add(StartTile, StartingTileData);
int TentativeGCost = 0;
IntVector2 CurrentTile = StartTile;
int Iterations = 0;
bool MaxIterationsMade = false;
int MaxIterations = 3000;
// Get BitMap
BytePointMap BitMap = Path.HostMap.GetBytePointMap(Path);
TileTypes[] PrefferedTiles = Path.Info.PrefferedTilesKey.StringToTilesArray();
while (OpenList.Count > 0)
{
// Give a safty range of 2 times the range in terms of iterations, if it cannot find a path by then, it's failed. can probably cannot be reached
if (Iterations > MaxIterations)
{
MaxIterationsMade = true;
break;
}
Iterations++;
int CurrentNodeIndex = GetLowestFCostTileIndex(OpenList, Path.HostMap, StartTile, EndTile, CurrentTile, PrefferedTiles);
CurrentTile = OpenList[CurrentNodeIndex];
if (EndTile == CurrentTile)
{
// Reached the end
//Debug.Log("Found the End - Should be Path Complete");
break;
}
// Remove current
OpenList.RemoveAt(CurrentNodeIndex);
ClosedList.Add(CurrentTile);
AStarTileData CurrentData = SortedList[CurrentTile];
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0)
{
continue;
}
IntVector2 neighbourPosition = new IntVector2(CurrentTile.x + x, CurrentTile.y + y);
if (BitMap.GetTileSpeed(neighbourPosition.x, neighbourPosition.y) == 0)
{
continue;
}
if (ClosedList.Contains(neighbourPosition))
{
continue;
}
// Get Corner Types, if its a wall, continue (DO NOT WALK THROUGH WALLS)
if (!BitMap.CornerCutting)
{
if (x != 0 && y != 0)
{
IntVector2 cornerAdjacentPosition = new IntVector2(CurrentTile.x + x, CurrentTile.y);
if (BitMap.Tiles[cornerAdjacentPosition.x, cornerAdjacentPosition.y] == 0)
{
continue;
}
cornerAdjacentPosition.x = CurrentTile.x;
cornerAdjacentPosition.y = CurrentTile.y + y;
if (BitMap.Tiles[cornerAdjacentPosition.x, cornerAdjacentPosition.y] == 0)
{
continue;
}
}
}
AStarTileData NeighbourData;
if (!SortedList.TryGetValue(neighbourPosition, out NeighbourData))
{
NeighbourData = new AStarTileData(new IntVector2(-1, -1), CalculateDistanceCost(neighbourPosition.x, neighbourPosition.y, EndTile.x, EndTile.y));
SortedList.Add(neighbourPosition, NeighbourData);
}
TentativeGCost = CurrentData.GCost + CalculateDistanceCost(CurrentTile.x, CurrentTile.y, neighbourPosition.x, neighbourPosition.y);
if (TentativeGCost < NeighbourData.GCost)
{
//Debug.Log("Lower G Cost");
NeighbourData.RouteFromTileIndex = CurrentTile;
NeighbourData.GCost = TentativeGCost;
NeighbourData.FCost = NeighbourData.GCost + NeighbourData.HCost;
SortedList[neighbourPosition] = NeighbourData;
if (!OpenList.Contains(neighbourPosition))
{
//Debug.Log("LEnter To OpenList");
OpenList.Add(neighbourPosition);
}
}
}
}
}
AStarTileData EndTileData;
if (MaxIterationsMade)
{
Succeeded = false;
Status = $"Path is too far away, or cannot be reached --> Iteration Max Reached {MaxIterations}";
}
else if (!SortedList.TryGetValue(EndTile, out EndTileData) || EndTileData.RouteFromTileIndex.x == -1)
{
// No Valid Path Found
Succeeded = false;
Status = "Open list emptied - But did NOT reach the End, Likely Trapped";
}
else
{
Succeeded = true;
// Path should be valid
SortPath(Path, SortedList, EndTile);
Status = $"Found a Valid Path 'Iterations ({Iterations} / {MaxIterations})' -> 'List Counts (Open:{OpenList.Count} / Closed:{ClosedList.Count})'";
}
}
catch (Exception ex)
{
Status = "Faled";
OccuringMap.LogError($"{ex.Message}: {ex.Source}: {ex.StackTrace}");
Succeeded = false;
}
}
protected int GetLowestFCostTileIndex(List<IntVector2> OpenList, Map.Map OccuringMap, IntVector2 Start, IntVector2 End, IntVector2 CurrentTileIndex, TileTypes[] PrefferedTiles)
{
int LowestCostIndex = 0;
if (PrefferedTiles.Contains(OccuringMap.GetTileType(CurrentTileIndex)))
{
// Try to stick to the group tile unless the tile is farther from the start AND closer to the end
int CurrentStartScore = CalculateDistanceCost(CurrentTileIndex.x, CurrentTileIndex.y, Start.x, Start.y);
int CurrentEndScore = CalculateDistanceCost(CurrentTileIndex.x, CurrentTileIndex.y, End.x, End.y);
int LowestSameCostIndex = -1;
TileTypes ZeroTileType = OccuringMap.GetTileType(OpenList[0].x, OpenList[0].y);
byte TileSpeed = OccuringMap.GetTileSpeedData(ZeroTileType);
int ZeroStartScore = CalculateDistanceCost(OpenList[0].x, OpenList[0].y, Start.x, Start.y);
int ZeroEndScore = CalculateDistanceCost(OpenList[0].x, OpenList[0].y, End.x, End.y);
int CurrentLowestCost = ZeroEndScore / TileSpeed;
int CurrentSameLowestCost = int.MaxValue;
if (PrefferedTiles.Contains(ZeroTileType) || (ZeroStartScore > CurrentStartScore && ZeroEndScore < CurrentEndScore))
{
LowestSameCostIndex = 0;
CurrentSameLowestCost = CurrentLowestCost;
}
for (int i = 1; i < OpenList.Count; i++)
{
TileTypes iTileType = OccuringMap.GetTileType(OpenList[i].x, OpenList[i].y);
TileSpeed = OccuringMap.GetTileSpeedData(iTileType);
int iStartScore = CalculateDistanceCost(OpenList[i].x, OpenList[i].y, Start.x, Start.y);
int iEndScore = CalculateDistanceCost(OpenList[i].x, OpenList[i].y, End.x, End.y);
int testCost = iEndScore / TileSpeed;
if (testCost < CurrentLowestCost)
{
CurrentLowestCost = testCost;
LowestCostIndex = i;
}
if (PrefferedTiles.Contains(iTileType) || (iStartScore > CurrentStartScore && iEndScore < CurrentEndScore))
{
if (testCost < CurrentSameLowestCost)
{
LowestSameCostIndex = i;
CurrentSameLowestCost = testCost;
}
}
}
if (LowestSameCostIndex != -1)
{
return LowestSameCostIndex;
}
}
else
{
// Typical AStar pathfinding
int TileSpeed = OccuringMap.GetTileSpeedData(OccuringMap.GetTileType(OpenList[0].x, OpenList[0].y));
int CurrentLowestCost = CalculateDistanceCost(OpenList[0].x, OpenList[0].y, End.x, End.y) / TileSpeed;
for (int i = 1; i < OpenList.Count; i++)
{
TileSpeed = OccuringMap.GetTileSpeedData(OccuringMap.GetTileType(OpenList[i].x, OpenList[i].y));
int testCost = CalculateDistanceCost(OpenList[i].x, OpenList[i].y, End.x, End.y) / TileSpeed;
if (testCost < CurrentLowestCost)
{
CurrentLowestCost = testCost;
LowestCostIndex = i;
}
}
}
return LowestCostIndex;
}
protected int CalculateDistanceCost(int x1, int y1, int x2, int y2)
{
int X_Distance = x1 - x2;
X_Distance = X_Distance < 0 ? -X_Distance : X_Distance;
int Y_Distance = y1 - y2;
Y_Distance = Y_Distance < 0 ? -Y_Distance : Y_Distance;
int remaining = X_Distance - Y_Distance;
remaining = remaining < 0 ? -remaining : remaining;
if (Y_Distance < X_Distance)
{
return 14 * Y_Distance + 10 * remaining;
}
else
{
return 14 * X_Distance + 10 * remaining;
}
}
protected void SortPath(NavigationPath Path, Dictionary<IntVector2, AStarTileData> SortedData, IntVector2 EndTileIndex)
{
AStarTileData CurrentTile = SortedData[EndTileIndex];
int InsertIndex = Path.Path.Count;
Path.Path.Insert(InsertIndex, EndTileIndex);
// The Route From Index of the starting tile should be the only one with a (-1, -1) index
while (CurrentTile.RouteFromTileIndex.x != -1)
{
Path.Path.Insert(InsertIndex, CurrentTile.RouteFromTileIndex);
CurrentTile = SortedData[CurrentTile.RouteFromTileIndex];
}
}
public struct AStarTileData
{
public IntVector2 RouteFromTileIndex;
public int FCost;
public int GCost;
public int HCost;
public AStarTileData(IntVector2 RouteFromTile, int EndCost)
{
RouteFromTileIndex = RouteFromTile;
FCost = int.MaxValue;
GCost = int.MaxValue;
HCost = EndCost;
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,340 @@
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using HPJ.Simulation.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
namespace HPJ.Simulation.Pathing
{
/// <summary>
/// The Base class for any pathfinding algorithms
/// </summary>
public abstract class PathingCalculation
{
/// <summary>
/// The Navigation Type this pathing is. Will need to add yours to the enum
/// </summary>
public NavigationTypes NavigationType { get; protected set; }
/// <summary>
/// The Dictionary of all the pathing algorithms
/// </summary>
public static Dictionary<NavigationTypes, PathingCalculation> PathingTypes = new Dictionary<NavigationTypes, PathingCalculation>();
public PathingCalculation()
{
Initialize();
}
/// <summary>
/// Initializes the Algorithm, You will need to call this or add this for your algorithm
/// </summary>
public virtual void Initialize()
{
NavigationType = NavigationTypes.None;
if (!PathingTypes.ContainsKey(NavigationType))
{
PathingTypes.Add(NavigationType, this);
}
}
/// <summary>
/// Calculates the Path for a Navigation Job Request on a specific Map
/// </summary>
/// <param name="Path"></param>
/// <param name="OccuringMap"></param>
/// <param name="Status"></param>
/// <param name="Succeeded"></param>
public abstract void CalculatePath(NavigationPath Path, Map.Map OccuringMap, out string Status, out bool Succeeded);
}
/// <summary>
/// A Navigation Job Request
/// </summary>
[Serializable]
public class NavigationJob
{
#region Navigation Info
/// <summary>
/// Infomation on this Job
/// </summary>
public PathingInfo Info;
/// <summary>
/// Current Step on the Pathfinding Calculation
/// </summary>
public PathfindingCalculationStep CurrentStep;
/// <summary>
/// The Number of tiles away from the start to the end
/// </summary>
public int TilesAway;
/// <summary>
/// Point A of the Path
/// </summary>
public IntVector3 WorldPointA;
/// <summary>
/// Point B of the Path
/// </summary>
public IntVector3 WorldPointB;
/// <summary>
/// If this Job was compatable or not
/// </summary>
public bool Compatable;
/// <summary>
/// Next time this path is pathed, repath it
/// </summary>
public bool RepathSavedPath;
/// <summary>
/// List of Traversable Tiles
/// </summary>
public List<TileTypes> TraverableTileTypes;
/// <summary>
/// List of Prefferred Tiles
/// </summary>
public List<TileTypes> PrefferedTileTypes;
#endregion
#region Navigation Results
/// <summary>
/// The Resulting Path for this Job Request
/// </summary>
public NavigationPath CurrentPath { get; protected set; }
public ushort AgentID { get; set; }
/// <summary>
/// The Callback to the presentation side
/// </summary>
public Action OnCompleteCallback;
#endregion
public NavigationJob(Action onCompleteCallback)
{
Info = new PathingInfo();
CurrentPath = null;
CurrentStep = PathfindingCalculationStep.Incomplete;
OnCompleteCallback = onCompleteCallback;
AgentID = 0;
}
/// <summary>
/// Clears the Job and reverts it back to default
/// </summary>
public void Clear()
{
Info = new PathingInfo();
CurrentPath = null;
CurrentStep = PathfindingCalculationStep.Incomplete;
}
/// <summary>
/// Initializes the Job with the neccessary pathing information
/// </summary>
/// <param name="Start"></param>
/// <param name="End"></param>
/// <param name="TraverableKey"></param>
/// <param name="PrefferedTilesKey"></param>
/// <param name="Navigation"></param>
/// <param name="ForMap"></param>
/// <param name="RepathAnyway"></param>
public void SetDestinationInfo(IntVector3 Start, IntVector3 End, List<TileTypes> TraverableTiles, List<TileTypes> PrefferedTiles, NavigationTypes Navigation, MapSet ForMap, bool RepathAnyway = false)
{
if (Start.x < End.x)
{
WorldPointA = Start;
WorldPointB = End;
}
else if (Start.x > End.x)
{
WorldPointA = End;
WorldPointB = Start;
}
else
{
if (Start.z < End.z)
{
WorldPointA = Start;
WorldPointB = End;
}
else if (Start.z > End.z)
{
WorldPointA = End;
WorldPointB = Start;
}
else
{
WorldPointA = Start;
WorldPointB = End;
}
}
TraverableTileTypes = TraverableTiles;
PrefferedTileTypes = PrefferedTiles;
RepathSavedPath = RepathAnyway;
Info = new PathingInfo(ForMap.GetMapTileIndex(WorldPointA), ForMap.GetMapTileIndex(WorldPointB), Navigation, TraverableTiles.TilesToString(), PrefferedTiles.TilesToString());
TilesAway = JumpPointSearch.Instance.CalculateDistanceCost(Start.x, Start.z, End.x, End.z);
Compatable = ForMap.JobCompatible(this);
}
/// <summary>
/// Sets the resulting path to the request
/// </summary>
/// <param name="path"></param>
internal void SetNewCurrentPath(NavigationPath path)
{
CurrentPath = path;
}
/// <summary>
/// The callback from the simulation when the job request is finished
/// </summary>
internal void PathfindingComplete()
{
CurrentStep = PathfindingCalculationStep.Complete;
OnCompleteCallback?.Invoke();
}
}
/// <summary>
/// The Calculated Path on a specific Map
/// </summary>
[System.Serializable]
public class NavigationPath
{
/// <summary>
/// The map the path was calculated on
/// </summary>
public Map.Map HostMap;
/// <summary>
/// The Information on this Path
/// </summary>
public PathingInfo Info;
/// <summary>
/// The Resulting Path
/// </summary>
public List<IntVector2> Path;
/// <summary>
/// If this Path resulting in a valid path
/// </summary>
public bool ValidPath;
/// <summary>
/// Previous status on the path
/// </summary>
public string PreviousStatus { get; set; }
/// <summary>
/// Asking For Path from specific agent
/// </summary>
public ushort AgentID;
public NavigationPath()
{
Info = new PathingInfo();
Path = new List<IntVector2>();
ValidPath = false;
PreviousStatus = "";
AgentID = 0;
}
public NavigationPath(PathingInfo PathInfo, Map.Map hostMap, ushort ID = 0)
{
Info = PathInfo;
Path = new List<IntVector2>();
ValidPath = false;
HostMap = hostMap;
PreviousStatus = "";
AgentID = 0;
}
/// <summary>
/// Checks to see if your starting point is the first index of the path or the last
/// </summary>
/// <param name="startPoint"></param>
/// <returns></returns>
public bool NeedToReverse(IntVector3 startPoint)
{
if (!ValidPath)
{
return false;
}
if (Path.Count <= 0)
{
return false;
}
return Path[0] != HostMap.GetTileIndexPosition(startPoint);
}
}
/// <summary>
/// The information on a given path
/// </summary>
[System.Serializable]
public struct PathingInfo
{
/// <summary>
/// Point A of a Path
/// </summary>
public IntVector2 PointA;
/// <summary>
/// Point B of a Path
/// </summary>
public IntVector2 PointB;
/// <summary>
/// Navigation type used for this Path
/// </summary>
public NavigationTypes NavigationType;
/// <summary>
/// Traversable Tiles Key
/// </summary>
public string TraversableTilesKey;
/// <summary>
/// Preffered Tile Kep
/// </summary>
public string PrefferedTilesKey;
public PathingInfo(IntVector2 A, IntVector2 B, NavigationTypes Type, string Traverable, string Preffered)
{
// Sort tiles by bottom left so there is no repeats in the saved path Dictionary
if (A.x < B.x)
{
PointA = A;
PointB = B;
}
else if (A.x > B.x)
{
PointA = B;
PointB = A;
}
else
{
if (A.y < B.y)
{
PointA = A;
PointB = B;
}
else if (A.y > B.y)
{
PointA = B;
PointB = A;
}
else
{
PointA = A;
PointB = B;
}
}
NavigationType = Type;
TraversableTilesKey = Traverable;
PrefferedTilesKey = Preffered;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,140 @@
namespace HPJ.Simulation.Enums
{
/// <summary>
/// The Navigation Types a agent can use for pathfinding
/// </summary>
public enum NavigationTypes
{
None = 0, // No Navigation Possible
Free = 1,
JumpPointSearch = 2,
AStar = 3,
Unknown = 4,
}
/// <summary>
/// The Navigation Tile Types that are availble on a Map, add more as needed
/// </summary>
public enum TileTypes : byte
{
Standard = 0,
Blocked = 1,
Free = 2,
Void = 3,
Obstacle = 4,
Water = 5,
OutOfBounds = 6,
}
/// <summary>
/// Bridge Direction Types
/// </summary>
public enum BridgeDirections : byte
{
Both = 0,
A_To_B = 1,
B_To_A = 2,
}
/// <summary>
/// Who has right of way based on your moving direction
/// </summary>
public enum RightOfWay : byte
{
NorthWest = 0,
SouthEast = 1,
}
/// <summary>
/// How agents try to avoid each other
/// </summary>
public enum AvoidenceType : byte
{
StopAndGo = 0,
TryToPathAround = 1,
}
/// <summary>
/// The seam connection side
/// </summary>
public enum SeamConnectionSide : byte
{
North = 0,
West = 1,
South = 2,
East = 3,
}
public enum DistanceCheck
{
Manhatten = 0,
Distance = 1,
SqrDistance,
}
public enum MovementType
{
FourDirection = 0,
EightDirection = 1,
}
public enum PathfindingCalculationStep
{
Incomplete = 0,
Pathfinding = 1,
Complete = 2,
Finalized = 3,
}
public enum SimulationDebugLog
{
Log = 0,
Warning = 1,
Error = 2,
}
public enum MapExpansionSide
{
Top = 0,
Bottom = 1,
Left = 2,
Right = 3,
}
public enum PainterTypes
{
Square = 0,
Circle = 1,
}
public enum ObstacleValidationStates : byte
{
Validated = 0,
Invalidated = 1,
Added = 2,
}
public enum AgentStates : byte
{
Stopped = 0,
Paused = 1,
Pathfinding = 2,
Moving = 3,
FailedPathing = 4,
SucceededPathing = 5,
Idle = 6,
}
public enum DestinationStates : byte
{
None = 0,
SameMap = 1,
Bridge = 2,
NextMap_FromBridge = 3,
ClosestPoint = 4,
Null = 5,
SamePosition = 6,
Seam = 7,
NextMap_FromSeam = 8,
}
}

View File

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

View File

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

View File

@@ -0,0 +1,79 @@
using HPJ.Simulation.Enums;
using System.Collections;
using System.Collections.Generic;
namespace HPJ.Simulation.Utilities
{
public static class Extensions
{
public static float Distance(this IntVector2 vector)
{
return (float)System.Math.Sqrt(vector.x * vector.x + vector.y * vector.y);
}
public static int SqrDistance(this IntVector2 vector)
{
return vector.x * vector.x + vector.y * vector.y;
}
public static string TilesToString(this TileTypes[] Tiles)
{
if (Tiles.Length == 0)
{
return "";
}
string ReturnString = "";
for(int i = 0; i < Tiles.Length - 1; i++)
{
ReturnString += $"{Tiles[i]}.";
}
ReturnString += $"{Tiles[Tiles.Length - 1]}.";
return ReturnString;
}
public static string TilesToString(this List<TileTypes> Tiles)
{
if (Tiles.Count == 0)
{
return "";
}
string ReturnString = "";
for (int i = 0; i < Tiles.Count - 1; i++)
{
ReturnString += $"{Tiles[i]}.";
}
ReturnString += $"{Tiles[Tiles.Count - 1]}.";
return ReturnString;
}
public static TileTypes[] StringToTilesArray(this string TilesStringArray)
{
string[] Split = TilesStringArray.Split('.');
if (Split.Length == 0)
{
return new TileTypes[1] { TileTypes.Free };
}
TileTypes[] ReturnArr = new TileTypes[Split.Length];
string[] EnumNames = System.Enum.GetNames(typeof(TileTypes));
for (int splitIndex = 0; splitIndex < Split.Length; splitIndex++)
{
for(int enumIndex = 0; enumIndex < EnumNames.Length; enumIndex++)
{
if (EnumNames[enumIndex] == Split[splitIndex])
{
ReturnArr[splitIndex] = (TileTypes)enumIndex;
}
}
}
return ReturnArr;
}
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
namespace HPJ.Simulation.Utilities
{
[System.Serializable]
public class Pool<T>
{
public List<T> Active;
public List<T> Inactive;
public Pool()
{
Active = new List<T>();
Inactive = new List<T>();
}
public T GetItem()
{
if (Inactive.Count > 0)
{
T Item = Inactive[0];
Inactive.RemoveAt(0);
return Item;
}
return default(T);
}
public void ReturnItem(T Item)
{
if (Active.Contains(Item))
{
Active.Remove(Item);
Inactive.Add(Item);
}
}
public void AddItem(T Item, bool AddToActiveList = true)
{
if (AddToActiveList)
{
Active.Add(Item);
}
else
{
Inactive.Add(Item);
}
}
public void ReturnAll()
{
for (int i = 0; i < Active.Count; i++)
{
Inactive.Add(Active[i]);
}
Active.Clear();
}
}
}

View File

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

View File

@@ -0,0 +1,16 @@
{
"name": "HPJ_Simulation",
"rootNamespace": "HPJ.Simulation",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"Newtonsoft.Json.dll"
],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": true
}

View File

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

View File

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

View File

@@ -0,0 +1,85 @@
using UnityEngine;
namespace HPJ.Examples
{
/// <summary>
/// A Example Camera Controller for the example scenes
/// </summary>
public class CameraController : MonoBehaviour
{
public float lookSpeed = 5f;
public float moveSpeed = 5f;
public float sprintSpeedMultiplier = 2f;
public float elevationSpeed = 3f;
public bool LockCurser = true;
public bool UseLockCommands = true;
private float rotationX = 0f;
private float rotationY = 0f;
private void Awake()
{
Application.targetFrameRate = 300;
}
void Start()
{
if (LockCurser)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
rotationX = transform.rotation.eulerAngles.x;
rotationY = transform.parent.rotation.eulerAngles.y;
}
void Update()
{
float mouseX = Input.GetAxis("Mouse X") * lookSpeed;
float mouseY = -Input.GetAxis("Mouse Y") * lookSpeed;
if (!Input.GetKey(KeyCode.LeftControl))
{
rotationX += mouseY;
rotationY += mouseX;
rotationX = Mathf.Clamp(rotationX, -90f, 90f);
transform.localRotation = Quaternion.Euler(rotationX, 0f, 0f);
transform.parent.localRotation = Quaternion.Euler(0f, rotationY, 0f);
}
Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical"));
if (moveInput.magnitude > 0f)
{
moveInput = Quaternion.Euler(0f, rotationY, 0f) * moveInput;
moveInput.Normalize();
float speedMultiplier = Input.GetKey(KeyCode.LeftShift) ? sprintSpeedMultiplier : 1f;
transform.parent.position += moveInput * moveSpeed * speedMultiplier * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Q))
{
transform.parent.position += Vector3.up * elevationSpeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.E))
{
transform.parent.position -= Vector3.up * elevationSpeed * Time.deltaTime;
}
if (Input.GetKeyDown(KeyCode.Escape) && UseLockCommands)
{
if (Cursor.lockState == CursorLockMode.None)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
else
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,40 @@
using UnityEngine;
namespace HPJ.Examples
{
/// <summary>
/// An Example Script to ping pong an object between 2 points
/// </summary>
public class ObstaclePingPong : MonoBehaviour
{
public Transform startPoint;
public Transform endPoint;
public float speed = 5.0f;
[Range(0, 1)]
public float startingPercent = 0;
public bool ReverseDirection = false;
private float pingPongTime = 0.0f;
private void Start()
{
if (ReverseDirection)
{
startingPercent = 2 - startingPercent;
}
pingPongTime = startingPercent;
}
private void OnValidate()
{
transform.position = Vector3.Lerp(startPoint.position, endPoint.position, startingPercent);
}
void Update()
{
pingPongTime += Time.deltaTime * speed;
float pingPongValue = Mathf.PingPong(pingPongTime, 1.0f);
transform.position = Vector3.Lerp(startPoint.position, endPoint.position, pingPongValue);
}
}
}

View File

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

View File

@@ -0,0 +1,28 @@
using UnityEngine;
namespace HPJ.Examples
{
/// <summary>
/// An example script that rotates a object over time
/// </summary>
public class Rotate : MonoBehaviour
{
public float RotationSpeed = 5;
public Space RotationSpace = Space.World;
public Vector3 Rotation = new Vector3();
private Vector3 RotationVector = new Vector3();
private void Awake()
{
Rotation = Rotation.normalized;
RotationVector = Rotation * RotationSpeed;
}
// Update is called once per frame
void Update()
{
transform.Rotate(RotationVector * Time.deltaTime, RotationSpace);
}
}
}

View File

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

View File

@@ -0,0 +1,48 @@
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;
namespace HPJ.Examples
{
public class SceneLoader : MonoBehaviour
{
private void Update()
{
if (EventSystem.current.currentSelectedGameObject != null)
{
return;
}
if (Input.GetKeyDown(KeyCode.KeypadMinus))
{
LoadPreviousScene();
}
else if (Input.GetKeyDown(KeyCode.KeypadPlus))
{
LoadNextScene();
}
}
public void LoadNextScene()
{
int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
int nextSceneIndex = currentSceneIndex + 1;
if (nextSceneIndex == SceneManager.sceneCountInBuildSettings)
{
nextSceneIndex = 0;
}
SceneManager.LoadScene(nextSceneIndex);
}
public void LoadPreviousScene()
{
int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
int previousSceneIndex = currentSceneIndex - 1;
if (previousSceneIndex < 0)
{
previousSceneIndex = SceneManager.sceneCountInBuildSettings - 1;
}
SceneManager.LoadScene(previousSceneIndex);
}
}
}

View File

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