poprawki
This commit is contained in:
parent
111772e9e9
commit
226974ab23
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
20
Assets/Logic/Agent/FringeNodes.cs
Normal file
20
Assets/Logic/Agent/FringeNodes.cs
Normal 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;
|
||||
}
|
||||
}
|
11
Assets/Logic/Agent/FringeNodes.cs.meta
Normal file
11
Assets/Logic/Agent/FringeNodes.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 131def8de3119224f95c4fd65f00f3c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
25
Assets/Logic/Agent/State.cs
Normal file
25
Assets/Logic/Agent/State.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Logic/Agent/State.cs.meta
Normal file
11
Assets/Logic/Agent/State.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20173ce40dd948143bfc1ac9545f4e0b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,5 @@ namespace Logic
|
||||
inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
public void RunToAnotherNode(Node destination)
|
||||
{
|
||||
StartCoroutine(waitress.RunToAnotherNode(destination));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user