This commit is contained in:
Wojciech 2021-04-21 01:02:54 +02:00
parent 111772e9e9
commit 226974ab23
11 changed files with 982 additions and 758 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ Material:
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Node_Mat
m_Name: Node_mat
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 4

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Logic.Agent;
namespace Assets.Logic.Agent
{
public class FringeNodes
{
public FringeNodes(State state)
{
State = state;
}
public State State;
public FringeNodes Parent;
public AgentAction Action;
}
}

View File

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

View File

@ -1,81 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Logic.Agent;
using Logic.Graph;
using UnityEngine;
namespace Logic.Agent
{
public class PathFinder : MonoBehaviour
{
// Słownik
// Klucz - Node rodzica
// Wartość - Tuple< Node Dziecka, Akcja przejścia z Noda rodzica do Noda dziecka >
private readonly IDictionary<Node, Tuple<Node, Action>> _exploredPaths = new Dictionary<Node, Tuple<Node, Action>>();
public Stack<Tuple<Node, Action>> FindPath(Node startNode, Node endNode)
public Stack<AgentAction> GraphSearch(Queue<FringeNodes> fringe, HashSet<FringeNodes> explored, State iState, State goalState)
{
_exploredPaths.Clear();
Stack<Tuple<Node, Action>> shortestPath = new Stack<Tuple<Node, Action>>();
var goal = Bfs(startNode, endNode);
if (goal.Item1 == startNode) {
print("Path Not found");
return shortestPath;
}
Tuple<Node, Action> curr = goal;
while (curr.Item1 != startNode) {
curr.Item1.MarkAsPath();
shortestPath.Push(new Tuple<Node, Action>(curr.Item1, curr.Item2));
curr = _exploredPaths[curr.Item1];
}
shortestPath.Push(new Tuple<Node, Action>(curr.Item1, curr.Item2));
return shortestPath;
}
private Tuple<Node, Action> Bfs(Node startNode, Node endNode){
Queue<Node> queue = new Queue<Node> ();
HashSet<Node> exploredNodes = new HashSet<Node> ();
queue.Enqueue(startNode);
while (queue.Count != 0) {
Node currentNode = queue.Dequeue();
// Warunek spełnienia celu
if (currentNode == endNode)
{
return new Tuple<Node, Action>(currentNode, null);
}
foreach(Tuple<Node, Action> node in Succ(currentNode)){
if(!exploredNodes.Contains(node.Item1)) {
exploredNodes.Add(node.Item1);
_exploredPaths.Add(node.Item1, new Tuple<Node, Action>(currentNode, node.Item2));
queue.Enqueue(node.Item1);
}
}
}
return new Tuple<Node, Action>(startNode, null);
}
private List<Tuple<Node, Action>> Succ(Node currentNode)
{
var tupleList = new List<Tuple<Node, Action>>();
foreach (Node node in currentNode.neighbors)
Stack<AgentAction> stack = new Stack<AgentAction>();
fringe.Enqueue(new FringeNodes(iState));
while (fringe.Count != 0)
{
var tuple = new Tuple<Node, Action>(node, () => AgentManager.Instance.RunToAnotherNode(node));
tupleList.Add(tuple);
var elem = fringe.Dequeue();
if (goalTest(elem.State, goalState))
{
while (!elem.State.Equals(iState))
{
elem.State.AgentPosition.MarkAsPath();
stack.Push(elem.Action);
elem = elem.Parent;
}
return stack;
}
explored.Add(elem);
foreach (var successor in Succ(elem.State))
{
if (fringe.Any(z =>
z.State.Equals(successor.Item1)) || explored.Any(z => z.State.Equals(successor.Item1)))
continue;
var x = new FringeNodes(successor.Item1) {Parent = elem, Action = successor.Item2};
fringe.Enqueue(x);
}
}
return stack;
}
private List<Tuple<State, AgentAction>> Succ(State currentState)
{
var tupleList = new List<Tuple<State, AgentAction>>();
//akcja obrot w lewo
if (!(currentState.AgentPosition is Table))
{
var stateLeft = new State();
stateLeft.AgentPosition = currentState.AgentPosition;
switch (currentState.AgentRotation)
{
case Rotation.Left:
stateLeft.AgentRotation = Rotation.Bottom;
break;
case Rotation.Right:
stateLeft.AgentRotation = Rotation.Top;
break;
case Rotation.Top:
stateLeft.AgentRotation = Rotation.Left;
break;
case Rotation.Bottom:
stateLeft.AgentRotation = Rotation.Right;
break;
}
tupleList.Add(new Tuple<State, AgentAction>(stateLeft, AgentAction.Left));
}
//akcja obrot w prawo
if (!(currentState.AgentPosition is Table))
{
var stateRight = new State();
stateRight.AgentPosition = currentState.AgentPosition;
switch (currentState.AgentRotation)
{
case Rotation.Left:
stateRight.AgentRotation = Rotation.Top;
break;
case Rotation.Right:
stateRight.AgentRotation = Rotation.Bottom;
break;
case Rotation.Top:
stateRight.AgentRotation = Rotation.Right;
break;
case Rotation.Bottom:
stateRight.AgentRotation = Rotation.Left;
break;
default:
throw new ArgumentOutOfRangeException();
}
tupleList.Add(new Tuple<State, AgentAction>(stateRight, AgentAction.Right));
}
//akcja do przodu
var stateGoForward = new State();
stateGoForward.AgentRotation = currentState.AgentRotation;
var node = currentState.AgentPosition.FindNode(currentState.AgentRotation);
if (node != null)
{
stateGoForward.AgentPosition = node;
tupleList.Add(new Tuple<State, AgentAction>(stateGoForward, AgentAction.GoForward));
}
return tupleList;
}
private bool goalTest(State actualState, State goalState)
{
return actualState.Equals(goalState);
}
}
}

View File

@ -0,0 +1,25 @@
using Logic.Graph;
using System;
namespace Assets.Logic.Agent
{
public enum Rotation
{
Left = 0,
Right = 1,
Top = 2,
Bottom = 3
}
public class State
{
public Rotation AgentRotation;
public Node AgentPosition;
public override bool Equals(object obj)
{
if (obj == null) return false;
var state = (State) obj;
return AgentPosition == state.AgentPosition && AgentRotation == state.AgentRotation;
}
}
}

View File

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

View File

@ -1,28 +1,46 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Assets.Logic.Agent;
using Logic.Graph;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace Logic.Agent
{
public enum AgentAction
{
Left = 0,
Right = 1,
GoForward = 2
}
public class Waitress : MonoBehaviour
{
[SerializeField] private Node currentNode;
//[SerializeField] private Node currentNode;
public Node StartNode;
[SerializeField] private bool isFollowingPath;
[SerializeField] private bool canMove = true;
private Node _previousNode;
//private Node _previousNode;
private State _currentState;
private State _previousState;
private PathFinder _pathFinder;
void Awake()
{
_pathFinder = GetComponent<PathFinder>();
_currentState = new State();
_currentState.AgentPosition = StartNode;
_currentState.AgentRotation = Rotation.Top;
_previousState = new State();
_previousState.AgentPosition = StartNode;
_previousState.AgentRotation = Rotation.Top;
}
void Update()
{
if (!canMove) return;
if (currentNode is Table table)
if (_currentState.AgentPosition is Table table)
{
if (table is KitchenTable kitchenTable)
{
@ -47,28 +65,65 @@ namespace Logic.Agent
isFollowingPath = true;
if (currentNode is Table && _previousNode != null)
if (_currentState.AgentPosition is Table && _previousState != null)
{
currentNode = _previousNode;
_currentState.AgentPosition = _previousState.AgentPosition;
}
Stack<Tuple<Node, Action>> path = _pathFinder.FindPath(currentNode, table);
if (path.Count > 0)
var goalState = new State();
goalState.AgentPosition = table;
goalState.AgentRotation = Rotation.Right;
Stack<AgentAction> actions = _pathFinder.GraphSearch(new Queue<FringeNodes>(), new HashSet<FringeNodes>(),
_currentState, goalState);
if (actions.Count > 0)
{
StartCoroutine(FollowPath(path));
StartCoroutine(ExecuteActions(actions));
}
}
private IEnumerator FollowPath(Stack<Tuple<Node, Action>> path)
private IEnumerator ExecuteActions(Stack<AgentAction> actions)
{
while (path.Count > 0)
while (actions.Count > 0)
{
if (canMove)
{
currentNode.ClearPathMark();
var node = path.Pop();
node.Item2?.Invoke();
_currentState.AgentPosition.ClearPathMark();
var action = actions.Pop();
switch (action)
{
case AgentAction.Left:
StartCoroutine(RotateLeft());
_previousState.AgentRotation = _currentState.AgentRotation;
_currentState.AgentRotation = _currentState.AgentRotation == Rotation.Left
?
Rotation.Bottom
: _currentState.AgentRotation == Rotation.Bottom
? Rotation.Right
: _currentState.AgentRotation == Rotation.Right
? Rotation.Top
: Rotation.Left;
break;
case AgentAction.Right:
StartCoroutine(RotateRight());
_previousState.AgentRotation = _currentState.AgentRotation;
_currentState.AgentRotation = _currentState.AgentRotation == Rotation.Left
?
Rotation.Top
: _currentState.AgentRotation == Rotation.Top
? Rotation.Right
: _currentState.AgentRotation == Rotation.Right
? Rotation.Bottom
: Rotation.Left;
break;
case AgentAction.GoForward:
StartCoroutine(
RunToAnotherNode(_currentState.AgentPosition.FindNode(_currentState.AgentRotation)));
break;
}
//node.Item2?.Invoke();
}
yield return new WaitForEndOfFrame();
@ -77,39 +132,69 @@ namespace Logic.Agent
isFollowingPath = false;
}
public IEnumerator RunToAnotherNode(Node destination)
private IEnumerator RotateLeft()
{
canMove = false;
transform.Rotate(new Vector3(0, -90, 0), Space.World);
var targetRotation = transform.rotation;
transform.Rotate(new Vector3(0, 90, 0), Space.World);
var startRotation = transform.rotation;
float i = 0;
while (i <= 1)
{
transform.rotation = Quaternion.Slerp(startRotation, targetRotation, i);
yield return new WaitForEndOfFrame();
i += Time.deltaTime*3;
}
transform.rotation = targetRotation;
canMove = true;
}
private IEnumerator RotateRight()
{
canMove = false;
transform.Rotate(new Vector3(0, 90, 0), Space.World);
var targetRotation = transform.rotation;
transform.Rotate(new Vector3(0, -90, 0), Space.World);
var startRotation = transform.rotation;
float i = 0;
while (i <= 1)
{
Debug.Log(i);
transform.rotation = Quaternion.Slerp(startRotation, targetRotation, i);
yield return new WaitForEndOfFrame();
i += Time.deltaTime*3;
}
transform.rotation = targetRotation;
canMove = true;
}
private IEnumerator RunToAnotherNode(Node destination)
{
canMove = false;
if (destination is Table)
{
_previousState.AgentPosition = _currentState.AgentPosition;
_currentState.AgentPosition = destination;
canMove = true;
yield break;
}
var location = destination.GetComponent<Transform>().position;
var targetPoint = new Vector3(location.x, transform.position.y, location.z) - transform.position;
var targetRotation = Quaternion.LookRotation(targetPoint, Vector3.up);
float i = 0;
while (targetRotation.eulerAngles != transform.rotation.eulerAngles && i <= 1)
{
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, i);
yield return new WaitForEndOfFrame();
i += Time.deltaTime;
}
i = 1;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, i);
i = 0;
var y = transform.position.y;
while (i <= 1 && !(destination is Table) && transform.position != new Vector3(location.x, transform.position.y, location.z))
var startPosition = transform.position;
while (i <= 1 && transform.position != new Vector3(location.x, transform.position.y, location.z))
{
transform.position = Vector3.Slerp(transform.position,
transform.position = Vector3.Slerp(startPosition,
new Vector3(location.x, y, location.z), i);
yield return new WaitForEndOfFrame();
i += Time.deltaTime;
i += Time.deltaTime*3;
}
if (!(destination is Table))
{
transform.position = new Vector3(location.x, transform.position.y, location.z);
}
_previousNode = currentNode;
currentNode = destination;
transform.position = new Vector3(location.x, transform.position.y, location.z);
_previousState.AgentPosition = _currentState.AgentPosition;
_currentState.AgentPosition = destination;
canMove = true;
}
}

View File

@ -42,10 +42,5 @@ namespace Logic
inventory.RemoveItem(item);
}
public void RunToAnotherNode(Node destination)
{
StartCoroutine(waitress.RunToAnotherNode(destination));
}
}
}

View File

@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Logic.Agent;
using Logic.Utils;
using UnityEngine;
namespace Logic.Graph
@ -110,6 +114,31 @@ namespace Logic.Graph
neighbors.Add(kitchenTableCollider);
}
}
public Node FindNode(Rotation agentRotation)
{
switch (agentRotation)
{
case Rotation.Left:
return neighbors.FirstOrDefault(x =>
x.transform.position.z.IsEq(transform.position.z) &&
x.transform.position.x.IsEq(transform.position.x - 1));
case Rotation.Right:
return neighbors.FirstOrDefault(x =>
x.transform.position.z.IsEq(transform.position.z) &&
x.transform.position.x.IsEq(transform.position.x + 1));
case Rotation.Top:
return neighbors.FirstOrDefault(x =>
x.transform.position.x.IsEq(transform.position.x) &&
x.transform.position.z.IsEq(transform.position.z + 1.25f));
case Rotation.Bottom:
return neighbors.FirstOrDefault(x =>
x.transform.position.x.IsEq(transform.position.x) &&
x.transform.position.z.IsEq(transform.position.z - 1.25f));
default:
return null;
}
}
}
}

View File

@ -3062,7 +3062,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 705507993}
m_LocalRotation: {x: 0.3917988, y: 0.6035859, z: -0.25043884, w: 0.64765584}
m_LocalPosition: {x: 0.3, y: 11, z: 6.26}
m_LocalPosition: {x: 0, y: 11, z: 6.26}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
@ -5976,7 +5976,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 88c24af30e59b1a4ab8fd947b1361040, type: 3}
m_Name:
m_EditorClassIdentifier:
currentNode: {fileID: 1825702552}
StartNode: {fileID: 1825702552}
isFollowingPath: 0
canMove: 1
--- !u!136 &1413865864