mirror of
https://github.com/GTA-ASM/SanAndreasUnity
synced 2024-11-26 05:50:18 +00:00
start refactoring into object-oriented state machine - walk around done
This commit is contained in:
parent
5e08419ac8
commit
9c68ea7a54
8 changed files with 212 additions and 80 deletions
68
Assets/Scripts/Behaviours/PedAI/BaseState.cs
Normal file
68
Assets/Scripts/Behaviours/PedAI/BaseState.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SanAndreasUnity.Behaviours.Vehicles;
|
||||
using SanAndreasUnity.Utilities;
|
||||
|
||||
namespace SanAndreasUnity.Behaviours.Peds.AI
|
||||
{
|
||||
public abstract class BaseState : IState
|
||||
{
|
||||
protected PedAI _pedAI { get; private set; }
|
||||
|
||||
protected Ped _ped => _pedAI.MyPed;
|
||||
protected Ped MyPed => _pedAI.MyPed;
|
||||
protected List<Ped> _enemyPeds => _pedAI.EnemyPeds;
|
||||
|
||||
|
||||
protected internal virtual void OnAwake(PedAI pedAI)
|
||||
{
|
||||
_pedAI = pedAI;
|
||||
}
|
||||
|
||||
public virtual void OnBecameActive()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnBecameInactive()
|
||||
{
|
||||
}
|
||||
|
||||
public bool RepresentsState(Type type)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool RepresentsState<T>() where T : IState
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public virtual void UpdateState()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void LateUpdateState()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void FixedUpdateState()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal virtual void OnMyPedDamaged(DamageInfo dmgInfo, Ped.DamageResult dmgResult)
|
||||
{
|
||||
}
|
||||
|
||||
protected internal virtual void OnOtherPedDamaged(Ped damagedPed, DamageInfo dmgInfo, Ped.DamageResult dmgResult)
|
||||
{
|
||||
}
|
||||
|
||||
protected internal virtual void OnVehicleDamaged(Vehicle vehicle, DamageInfo damageInfo)
|
||||
{
|
||||
}
|
||||
|
||||
protected internal virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/Behaviours/PedAI/BaseState.cs.meta
Normal file
11
Assets/Scripts/Behaviours/PedAI/BaseState.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 220a8feb8843f004bb6cfc4d791cdd4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
10
Assets/Scripts/Behaviours/PedAI/IdleState.cs
Normal file
10
Assets/Scripts/Behaviours/PedAI/IdleState.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace SanAndreasUnity.Behaviours.Peds.AI
|
||||
{
|
||||
public class IdleState : BaseState
|
||||
{
|
||||
public override void UpdateState()
|
||||
{
|
||||
_pedAI.StartWalkingAround();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/Behaviours/PedAI/IdleState.cs.meta
Normal file
11
Assets/Scripts/Behaviours/PedAI/IdleState.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 73cba38be80b3254b873f8c96878a824
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -51,9 +51,9 @@ namespace SanAndreasUnity.Behaviours.Peds.AI
|
|||
public PedestrianType PedestrianType => this.MyPed.PedDef.DefaultType;
|
||||
|
||||
private List<Ped> _enemyPeds = new List<Ped>();
|
||||
private Ped _currentlyEngagedPed;
|
||||
public List<Ped> EnemyPeds => _enemyPeds;
|
||||
|
||||
private bool _isFindingPathNodeDelayed = false;
|
||||
private Ped _currentlyEngagedPed;
|
||||
|
||||
|
||||
private void Awake()
|
||||
|
@ -250,65 +250,44 @@ namespace SanAndreasUnity.Behaviours.Peds.AI
|
|||
|
||||
bool ArrivedAtDestinationNode()
|
||||
{
|
||||
if (!this.HasTargetNode)
|
||||
return ArrivedAtDestinationNode(this.HasTargetNode ? this.TargetNode : (PathNode?)null, this.transform);
|
||||
}
|
||||
|
||||
public static bool ArrivedAtDestinationNode(PathMovementData pathMovementData, Transform tr)
|
||||
{
|
||||
if (!pathMovementData.destinationNode.HasValue)
|
||||
return false;
|
||||
if (Vector2.Distance(this.transform.position.ToVec2WithXAndZ(), this.TargetNode.Position.ToVec2WithXAndZ())
|
||||
< this.TargetNode.PathWidth / 2f)
|
||||
if (Vector2.Distance(tr.position.ToVec2WithXAndZ(), pathMovementData.destinationNode.Value.Position.ToVec2WithXAndZ())
|
||||
< pathMovementData.destinationNode.Value.PathWidth / 2f)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnArrivedToDestinationNode()
|
||||
private void OnArrivedToDestinationNode()
|
||||
{
|
||||
PathNode previousNode = CurrentNode;
|
||||
CurrentNode = TargetNode;
|
||||
TargetNode = GetNextPathNode(previousNode, CurrentNode);
|
||||
this.AssignMoveDestinationBasedOnTargetNode();
|
||||
var c = CurrentNode;
|
||||
var d = TargetNode;
|
||||
OnArrivedToDestinationNode(ref c, ref d, out Vector3 m);
|
||||
CurrentNode = c;
|
||||
TargetNode = d;
|
||||
_moveDestination = m;
|
||||
}
|
||||
|
||||
void AssignMoveDestinationBasedOnTargetNode()
|
||||
public static void OnArrivedToDestinationNode(PathMovementData pathMovementData)
|
||||
{
|
||||
Vector2 offset = Random.insideUnitCircle * TargetNode.PathWidth / 2f * 0.9f;
|
||||
_moveDestination = TargetNode.Position + offset.ToVector3XZ();
|
||||
}
|
||||
|
||||
void UpdateIdle()
|
||||
{
|
||||
this.StartWalkingAround();
|
||||
}
|
||||
|
||||
void UpdateWalkingAround()
|
||||
{
|
||||
if (this.MyPed.IsInVehicleSeat)
|
||||
{
|
||||
// exit vehicle
|
||||
this.MyPed.OnSubmitPressed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.MyPed.IsInVehicle) // wait until we exit vehicle
|
||||
if (!pathMovementData.destinationNode.HasValue)
|
||||
return;
|
||||
|
||||
// check if we gained some enemies
|
||||
_enemyPeds.RemoveDeadObjectsIfNotEmpty();
|
||||
if (_enemyPeds.Count > 0)
|
||||
{
|
||||
this.Action = PedAIAction.Chasing;
|
||||
return;
|
||||
PathNode previousNode = pathMovementData.currentNode.GetValueOrDefault();
|
||||
pathMovementData.currentNode = pathMovementData.destinationNode;
|
||||
pathMovementData.destinationNode = GetNextPathNode(previousNode, pathMovementData.currentNode.Value);
|
||||
pathMovementData.moveDestination = GetMoveDestinationBasedOnTargetNode(pathMovementData.destinationNode.Value);
|
||||
}
|
||||
|
||||
if (this.ArrivedAtDestinationNode())
|
||||
this.OnArrivedToDestinationNode();
|
||||
|
||||
if (!this.HasTargetNode)
|
||||
public static Vector3 GetMoveDestinationBasedOnTargetNode(PathNode targetNode)
|
||||
{
|
||||
this.FindNextNodeDelayed();
|
||||
return;
|
||||
}
|
||||
|
||||
this.MyPed.IsWalkOn = true;
|
||||
this.MyPed.Movement = (_moveDestination - this.MyPed.transform.position).normalized;
|
||||
this.MyPed.Heading = this.MyPed.Movement;
|
||||
Vector2 offset = Random.insideUnitCircle * targetNode.PathWidth / 2f * 0.9f;
|
||||
return targetNode.Position + offset.ToVector3XZ();
|
||||
}
|
||||
|
||||
void UpdateChasing()
|
||||
|
@ -532,6 +511,11 @@ namespace SanAndreasUnity.Behaviours.Peds.AI
|
|||
_enemyPeds.AddIfNotPresent(ped);
|
||||
}
|
||||
|
||||
public void StartChasing()
|
||||
{
|
||||
this.Action = PedAIAction.Chasing;
|
||||
}
|
||||
|
||||
public void Recruit(Ped recruiterPed)
|
||||
{
|
||||
if (this.Action == PedAIAction.Following)
|
||||
|
@ -574,9 +558,8 @@ namespace SanAndreasUnity.Behaviours.Peds.AI
|
|||
}
|
||||
}
|
||||
|
||||
PathNode? GetClosestPathNodeToWalk()
|
||||
public static PathNode? GetClosestPathNodeToWalk(Vector3 pos)
|
||||
{
|
||||
Vector3 pos = this.MyPed.transform.position;
|
||||
float radius = 200f;
|
||||
|
||||
var pathNodeInfo = NodeReader.GetAreasInRadius(pos, radius)
|
||||
|
@ -592,33 +575,6 @@ namespace SanAndreasUnity.Behaviours.Peds.AI
|
|||
return pathNodeInfo.node;
|
||||
}
|
||||
|
||||
private void FindNextNodeDelayed()
|
||||
{
|
||||
if (_isFindingPathNodeDelayed)
|
||||
return;
|
||||
|
||||
_isFindingPathNodeDelayed = true;
|
||||
|
||||
this.CancelInvoke(nameof(this.FindNextNodeDelayedCallback));
|
||||
this.Invoke(nameof(this.FindNextNodeDelayedCallback), 2f);
|
||||
}
|
||||
|
||||
private void FindNextNodeDelayedCallback()
|
||||
{
|
||||
_isFindingPathNodeDelayed = false;
|
||||
|
||||
if (this.HasTargetNode) // already assigned ?
|
||||
return;
|
||||
|
||||
var closestPathNodeToWalk = this.GetClosestPathNodeToWalk();
|
||||
if (null == closestPathNodeToWalk)
|
||||
return;
|
||||
|
||||
this.TargetNode = closestPathNodeToWalk.Value;
|
||||
this.HasTargetNode = true;
|
||||
this.AssignMoveDestinationBasedOnTargetNode();
|
||||
}
|
||||
|
||||
private Ped GetNextPedToAttack()
|
||||
{
|
||||
_enemyPeds.RemoveDeadObjectsIfNotEmpty();
|
||||
|
|
65
Assets/Scripts/Behaviours/PedAI/WalkAroundState.cs
Normal file
65
Assets/Scripts/Behaviours/PedAI/WalkAroundState.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using SanAndreasUnity.Importing.Paths;
|
||||
using SanAndreasUnity.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SanAndreasUnity.Behaviours.Peds.AI
|
||||
{
|
||||
public class PathMovementData // don't change to struct, it would be large
|
||||
{
|
||||
public PathNode? currentNode;
|
||||
public PathNode? destinationNode;
|
||||
public Vector3 moveDestination;
|
||||
}
|
||||
|
||||
public class WalkAroundState : BaseState
|
||||
{
|
||||
private readonly PathMovementData _pathMovementData = new PathMovementData();
|
||||
private float _timeWhenAttemptedToFindClosestNode = 0f;
|
||||
|
||||
|
||||
public override void UpdateState()
|
||||
{
|
||||
if (this.MyPed.IsInVehicleSeat)
|
||||
{
|
||||
// exit vehicle
|
||||
this.MyPed.OnSubmitPressed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.MyPed.IsInVehicle) // wait until we exit vehicle
|
||||
return;
|
||||
|
||||
// check if we gained some enemies
|
||||
_enemyPeds.RemoveDeadObjectsIfNotEmpty();
|
||||
if (_enemyPeds.Count > 0)
|
||||
{
|
||||
_pedAI.StartChasing();
|
||||
return;
|
||||
}
|
||||
|
||||
if (PedAI.ArrivedAtDestinationNode(_pathMovementData, _ped.transform))
|
||||
PedAI.OnArrivedToDestinationNode(_pathMovementData);
|
||||
|
||||
if (!_pathMovementData.destinationNode.HasValue)
|
||||
{
|
||||
if (Time.time - _timeWhenAttemptedToFindClosestNode > 2f) // don't attempt to find it every frame
|
||||
{
|
||||
_timeWhenAttemptedToFindClosestNode = Time.time;
|
||||
|
||||
var closestPathNodeToWalk = PedAI.GetClosestPathNodeToWalk(_ped.transform.position);
|
||||
if (null == closestPathNodeToWalk)
|
||||
return;
|
||||
|
||||
_pathMovementData.destinationNode = closestPathNodeToWalk;
|
||||
_pathMovementData.moveDestination = PedAI.GetMoveDestinationBasedOnTargetNode(closestPathNodeToWalk.Value);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.MyPed.IsWalkOn = true;
|
||||
this.MyPed.Movement = (_pathMovementData.moveDestination - this.MyPed.transform.position).normalized;
|
||||
this.MyPed.Heading = this.MyPed.Movement;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/Behaviours/PedAI/WalkAroundState.cs.meta
Normal file
11
Assets/Scripts/Behaviours/PedAI/WalkAroundState.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 222511457f310964cb16bb4f68d52ac5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -7,8 +7,8 @@ namespace SanAndreasUnity.Utilities
|
|||
|
||||
void OnBecameActive();
|
||||
void OnBecameInactive();
|
||||
bool RepresentsState(System.Type type);
|
||||
bool RepresentsState<T>() where T : IState;
|
||||
bool RepresentsState(System.Type type); // TODO: should be removed
|
||||
bool RepresentsState<T>() where T : IState; // TODO: should be removed
|
||||
void UpdateState();
|
||||
void LateUpdateState();
|
||||
void FixedUpdateState();
|
||||
|
|
Loading…
Reference in a new issue