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