Initial Commit
This commit is contained in:
commit
ee5c2f922d
2255 changed files with 547750 additions and 0 deletions
140
Assets/Scripts/Systems/Navigation/FindPathJob.cs
Normal file
140
Assets/Scripts/Systems/Navigation/FindPathJob.cs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace.Navigation
|
||||
{
|
||||
public struct FindPathJob : IJob
|
||||
{
|
||||
private readonly Vector2 from;
|
||||
private readonly int to;
|
||||
[ReadOnly] private NativeList<NavigationBuilder.Point> points;
|
||||
[ReadOnly] private NativeMultiHashMap<int, PathNodeConnection> connectionsDictionary;
|
||||
public NativeList<PathNode> Path;
|
||||
|
||||
public FindPathJob(
|
||||
Vector2 from,
|
||||
int to,
|
||||
[ReadOnly] NativeList<NavigationBuilder.Point> points,
|
||||
[ReadOnly] NativeMultiHashMap<int, PathNodeConnection> connectionsDictionary)
|
||||
{
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.points = points;
|
||||
this.connectionsDictionary = connectionsDictionary;
|
||||
Path = new NativeList<PathNode>(Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var from = this.from;
|
||||
|
||||
var toPos = points[to].Pos;
|
||||
var closestStartPoint = points.FindMinIndex(p => (p.Pos - from).sqrMagnitude);
|
||||
var closestEndPoint = points.FindMinIndex(p => (p.Pos - toPos).sqrMagnitude);
|
||||
|
||||
if (closestStartPoint < 0 || closestEndPoint < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var parents = new Dictionary<int, int>();
|
||||
var gScore = new NativeArray<float>(points.Length, Allocator.Temp);
|
||||
var fScore = new NativeArray<float>(points.Length, Allocator.Temp);
|
||||
var cons = new NativeArray<PathNodeConnection>(points.Length, Allocator.Temp);
|
||||
|
||||
try
|
||||
{
|
||||
var closed = new HashSet<int>();
|
||||
var open = new HashSet<int>();
|
||||
gScore.Fill(float.PositiveInfinity);
|
||||
fScore.Fill(float.PositiveInfinity);
|
||||
gScore[closestStartPoint] = 0;
|
||||
fScore[closestStartPoint] = CalculateHeuristic(closestStartPoint, closestEndPoint);
|
||||
open.Add(closestStartPoint);
|
||||
|
||||
while (open.Count > 0)
|
||||
{
|
||||
var fScoreLocal = fScore;
|
||||
var current = open.MinValue(i => fScoreLocal[i]);
|
||||
var qPoint = points[current];
|
||||
open.Remove(current);
|
||||
|
||||
if (current == closestEndPoint)
|
||||
{
|
||||
ConstructPath(parents, current, cons);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var connection in connectionsDictionary.GetEnumerator(qPoint.FaltIndex))
|
||||
{
|
||||
if (closed.Contains(connection.Destination))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var gScoreVal = gScore[current] +
|
||||
(connection.Type == PathNodeConnectionType.Jump
|
||||
? connection.Distance * connection.Distance * connection.Distance
|
||||
: 0);
|
||||
var fScoreValue = gScoreVal + CalculateHeuristic(connection.Destination, closestEndPoint);
|
||||
|
||||
if (!open.Contains(connection.Destination)) // Discover a new node
|
||||
{
|
||||
open.Add(connection.Destination);
|
||||
}
|
||||
else if (gScoreVal >= gScore[connection.Destination])
|
||||
{
|
||||
continue; // This is not a better path.
|
||||
}
|
||||
|
||||
parents[connection.Destination] = current;
|
||||
gScore[connection.Destination] = gScoreVal;
|
||||
fScore[connection.Destination] = fScoreValue;
|
||||
cons[connection.Destination] = connection;
|
||||
|
||||
open.Add(connection.Destination);
|
||||
}
|
||||
|
||||
closed.Add(current);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
gScore.Dispose();
|
||||
fScore.Dispose();
|
||||
cons.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ConstructPath(IDictionary<int, int> parents, int end, NativeArray<PathNodeConnection> cons)
|
||||
{
|
||||
Path.Add(new PathNode { ConnectionType = cons[end].Type, pos = points[end].Pos });
|
||||
|
||||
while (parents.TryGetValue(end, out var parent))
|
||||
{
|
||||
Path.Add(new PathNode { ConnectionType = cons[parent].Type, pos = points[parent].Pos });
|
||||
end = parent;
|
||||
}
|
||||
|
||||
var distanceFromStart = Vector2.Distance(Path[Path.Length - 1].pos, from);
|
||||
if (distanceFromStart > 0.05f)
|
||||
{
|
||||
Path.Add(new PathNode { pos = @from, ConnectionType = PathNodeConnectionType.Start });
|
||||
}
|
||||
|
||||
Path.Reverse();
|
||||
}
|
||||
|
||||
private float CalculateHeuristic(int from, int to)
|
||||
{
|
||||
return (points[from].Index2D - points[to].Index2D).sqrMagnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Systems/Navigation/FindPathJob.cs.meta
Normal file
11
Assets/Scripts/Systems/Navigation/FindPathJob.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b427073c5a8f24f4fb88c203b98d5d37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
180
Assets/Scripts/Systems/Navigation/NavigationAgentDriverSystem.cs
Normal file
180
Assets/Scripts/Systems/Navigation/NavigationAgentDriverSystem.cs
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
using System;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using Zenject;
|
||||
|
||||
namespace DefaultNamespace.Navigation
|
||||
{
|
||||
public class NavigationAgentDriverSystem : InjectableComponentSystem
|
||||
{
|
||||
[Serializable]
|
||||
public class Settings
|
||||
{
|
||||
public LayerMask GroundMask;
|
||||
public float JumpSpeed;
|
||||
public float MinNodeDistnace = 0.1f;
|
||||
public float Speed;
|
||||
}
|
||||
|
||||
[Inject] private readonly NavigationBuilder builder;
|
||||
|
||||
[Inject] private readonly Settings settings;
|
||||
private readonly ContactPoint2D[] contactPoints = new ContactPoint2D[16];
|
||||
|
||||
protected override void OnSystemUpdate()
|
||||
{
|
||||
Entities.WithNone<PathNode>()
|
||||
.ForEach((Entity entity, ref NavigationAgentData agent) => { PostUpdateCommands.AddBuffer<PathNode>(entity); });
|
||||
|
||||
Entities.WithAll<PathNode, Rigidbody2D>()
|
||||
.ForEach(
|
||||
(Entity entity, NavigationCalculationData calculation, ref NavigationAgentData agent) =>
|
||||
{
|
||||
var rigidbody = EntityManager.GetComponentObject<Rigidbody2D>(entity);
|
||||
var path = EntityManager.GetBuffer<PathNode>(entity);
|
||||
|
||||
if (calculation.PathCalculationJobHandle.IsCompleted)
|
||||
{
|
||||
calculation.PathCalculationJobHandle.Complete();
|
||||
path.CopyFrom(calculation.PathCalculationJob.Path);
|
||||
calculation.PathCalculationJob.Path.Dispose();
|
||||
agent.currentTime = 0;
|
||||
agent.currentIndex = 0;
|
||||
agent.startPos = rigidbody.position;
|
||||
PostUpdateCommands.RemoveComponent<NavigationCalculationData>(entity);
|
||||
}
|
||||
});
|
||||
|
||||
Entities.WithAll<PathNode>()
|
||||
.ForEach(
|
||||
(Entity entity, Rigidbody2D rigidbody, ref NavigationAgentData agent) =>
|
||||
{
|
||||
var path = EntityManager.GetBuffer<PathNode>(entity);
|
||||
|
||||
agent.Grounded = false;
|
||||
|
||||
var hasDestination = agent.destination.HasValue;
|
||||
if (hasDestination)
|
||||
{
|
||||
var goalPos = agent.destination.Value;
|
||||
var closestEndPoint = builder.Points.FindMinIndex(p => (p.Pos - goalPos).sqrMagnitude);
|
||||
|
||||
if (closestEndPoint != agent.lastGoalPosIndex)
|
||||
{
|
||||
agent.lastGoalPosIndex = closestEndPoint;
|
||||
if (closestEndPoint >= 0)
|
||||
{
|
||||
var from = rigidbody.position;
|
||||
var job = new FindPathJob(from, closestEndPoint, builder.Points, builder.connectionsDictionary);
|
||||
PostUpdateCommands.AddSharedComponent(
|
||||
entity,
|
||||
new NavigationCalculationData { PathCalculationJob = job, PathCalculationJobHandle = job.Schedule() });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (path.Length > 0)
|
||||
{
|
||||
path.Clear();
|
||||
}
|
||||
|
||||
var agentContacts = rigidbody.GetContacts(
|
||||
new ContactFilter2D { useLayerMask = true, layerMask = settings.GroundMask },
|
||||
contactPoints);
|
||||
//Bounds bounds = agentCollider.bounds;
|
||||
//bool grounded = contactPoints.Take(agentContacts).Any(c => Vector2.Angle(c.normal, Vector2.up) <= 22.5f);
|
||||
|
||||
/*float waypointMinDistance2 = waypointMinDistance * waypointMinDistance;
|
||||
int closestPointIndex = path.FindLastIndex(p => ((Vector2)bounds.ClosestPoint(p.pos) - p.pos).sqrMagnitude <= waypointMinDistance2);
|
||||
if (closestPointIndex > currentIndex)
|
||||
{
|
||||
currentIndex = closestPointIndex;
|
||||
currentTime = 0;
|
||||
}*/
|
||||
|
||||
for (var j = 1; j < path.Length; j++)
|
||||
{
|
||||
Debug.DrawLine(path[j - 1].pos + Vector2.up * 0.5f, path[j].pos + Vector2.up * 0.5f, Color.cyan);
|
||||
}
|
||||
|
||||
var currentIndex = agent.currentIndex;
|
||||
var nextIndex = agent.currentIndex + 1;
|
||||
|
||||
rigidbody.bodyType = nextIndex >= path.Length ? RigidbodyType2D.Dynamic : RigidbodyType2D.Kinematic;
|
||||
if (nextIndex < path.Length)
|
||||
{
|
||||
var firstPosition = currentIndex >= 0 ? path[currentIndex].pos : agent.startPos;
|
||||
var nextPosition = path[nextIndex].pos;
|
||||
var nextConnectionType = path[nextIndex].ConnectionType;
|
||||
var lastConnectionType = path[currentIndex].ConnectionType;
|
||||
var isNextJump = nextConnectionType == PathNodeConnectionType.Jump;
|
||||
var isNextDrop = nextConnectionType == PathNodeConnectionType.Drop;
|
||||
var isStart = lastConnectionType == PathNodeConnectionType.Start;
|
||||
|
||||
var nextMaxTime = currentIndex >= 0
|
||||
? isNextJump || isNextDrop ? settings.JumpSpeed : settings.Speed
|
||||
: Mathf.Max(Mathf.Clamp01(Vector2.Distance(agent.startPos, nextPosition)), settings.Speed);
|
||||
agent.currentTime += Time.DeltaTime;
|
||||
agent.currentTime = Mathf.Min(agent.currentTime, nextMaxTime);
|
||||
|
||||
var heightDelta = Mathf.Abs(firstPosition.y - nextPosition.y);
|
||||
|
||||
var percent = agent.currentTime / Mathf.Max(nextMaxTime, Time.DeltaTime);
|
||||
if (currentIndex >= 0 && !isStart && (isNextJump || isNextDrop || heightDelta > 0.1f))
|
||||
{
|
||||
var height = Mathf.Max(Mathf.Sqrt(heightDelta), 1);
|
||||
rigidbody.MovePosition(builder.SampleParabola(firstPosition, nextPosition, height, percent));
|
||||
|
||||
if (agent.currentTime >= nextMaxTime)
|
||||
{
|
||||
agent.currentIndex++;
|
||||
agent.currentTime -= nextMaxTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dir = nextPosition - rigidbody.position;
|
||||
var dirMag = dir.magnitude;
|
||||
dir.Normalize();
|
||||
rigidbody.MovePosition(rigidbody.position + dir * Mathf.Min(dirMag, settings.Speed * Time.DeltaTime));
|
||||
if (dirMag <= settings.MinNodeDistnace)
|
||||
{
|
||||
agent.currentTime = 0;
|
||||
agent.currentIndex++;
|
||||
}
|
||||
|
||||
agent.Grounded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
agent.lastGoalPosIndex = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public struct NavigationCalculationData : ISystemStateSharedComponentData, IEquatable<NavigationCalculationData>
|
||||
{
|
||||
public FindPathJob PathCalculationJob;
|
||||
public JobHandle PathCalculationJobHandle;
|
||||
|
||||
public bool Equals(NavigationCalculationData other)
|
||||
{
|
||||
return PathCalculationJob.Equals(other.PathCalculationJob) && PathCalculationJobHandle.Equals(other.PathCalculationJobHandle);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is NavigationCalculationData other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (PathCalculationJob.GetHashCode() * 397) ^ PathCalculationJobHandle.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9a8f6a25f16cb4479d04e90f5156ae0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Add table
Add a link
Reference in a new issue