Skip to content

Commit

Permalink
ExecuteOnce and prevent same state #10. InterestingObject logic #7. S…
Browse files Browse the repository at this point in the history
…tarted FromAnyStateTransitions #8.
  • Loading branch information
p3v1Xamk committed Mar 25, 2023
1 parent 6cf7f72 commit 3ea612e
Show file tree
Hide file tree
Showing 20 changed files with 150 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ff1f1411973882f409efcfb8e33a7e67, type: 3}
m_Name: FSM Action Interesting Object
m_EditorClassIdentifier:
ExecuteOnce: 1
14 changes: 0 additions & 14 deletions Assets/FSMScriptables/Decisions/FSM Decision Is Interested.asset

This file was deleted.

This file was deleted.

4 changes: 3 additions & 1 deletion Assets/FSMScriptables/States/InterestingObjectState.asset
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ MonoBehaviour:
m_EditorClassIdentifier:
Action:
- {fileID: 11400000, guid: 8dede98f7ce393342bb5c874e8d33212, type: 2}
Transitions: []
Transitions:
- {fileID: 11400000, guid: b48b5e2b88cdd9d44801f80e19b8ce0c, type: 2}
RemainState: 0
2 changes: 1 addition & 1 deletion Assets/FSMScriptables/States/RemainState.asset
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ MonoBehaviour:
m_EditorClassIdentifier:
Action: []
Transitions: []
RemainState: 0
RemainState: 1

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ MonoBehaviour:
m_EditorClassIdentifier:
Decision: {fileID: 11400000, guid: 31c7efa78f0cf5d459398d6dad270aeb, type: 2}
TrueState: {fileID: 11400000, guid: f9fe190c701ee44479165a252765aaf3, type: 2}
FalseState: {fileID: 11400000, guid: f0bf743df33397041be856c48cd2e3af, type: 2}
FalseState: {fileID: 11400000, guid: 9a04c27bff05d3e4dbcfb9f9063d5a3c, type: 2}
44 changes: 39 additions & 5 deletions Assets/Scenes/SampleScene.unity
Original file line number Diff line number Diff line change
Expand Up @@ -484,14 +484,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 963194225}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalRotation: {x: 0.5, y: 0, z: 0, w: 0.8660254}
m_LocalPosition: {x: 0, y: 22.07, z: -15.31}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 60, y: 0, z: 0}
--- !u!1 &1726376089
GameObject:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -536,6 +536,7 @@ GameObject:
- component: {fileID: 1892191295}
- component: {fileID: 1892191294}
- component: {fileID: 1892191293}
- component: {fileID: 1892191298}
m_Layer: 6
m_Name: Sphere
m_TagString: Untagged
Expand Down Expand Up @@ -630,13 +631,27 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1892191292}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -2.39, y: 1.25, z: -5.54}
m_LocalPosition: {x: -3.99, y: 1.25, z: 6.5}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1892191298
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1892191292}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0914c67ba62d96e45933bf2c1c82dc51, type: 3}
m_Name:
m_EditorClassIdentifier:
IsInterestingForSeconds: 4
InterestReturnCooldown: 10
--- !u!1 &2039071646
GameObject:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -1080,6 +1095,7 @@ GameObject:
- component: {fileID: 5353696484321215362}
- component: {fileID: 5353696484321215361}
- component: {fileID: 5353696484321215363}
- component: {fileID: 5353696484321215364}
m_Layer: 0
m_Name: MixamoMannequin
m_TagString: Untagged
Expand Down Expand Up @@ -2068,8 +2084,26 @@ MonoBehaviour:
- {fileID: 2076500601}
- {fileID: 1726376090}
- {fileID: 274155953}
_initialState: {fileID: 11400000, guid: 9a04c27bff05d3e4dbcfb9f9063d5a3c, type: 2}
initialState: {fileID: 11400000, guid: 9a04c27bff05d3e4dbcfb9f9063d5a3c, type: 2}
FromAnyStateTransitions: []
CurrentState: {fileID: 0}
CurrentEmotionalState: 0
--- !u!54 &5353696484321215364
Rigidbody:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1722586099319358396}
serializedVersion: 2
m_Mass: 1
m_Drag: 0
m_AngularDrag: 0.05
m_UseGravity: 0
m_IsKinematic: 1
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!4 &5432016104463062099
Transform:
m_ObjectHideFlags: 0
Expand Down
20 changes: 14 additions & 6 deletions Assets/Scripts/CharacterAndAI/Characters/FSMCharacter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,41 @@

public class FSMCharacter : NavMeshAgentCharacter
{
[SerializeField, Tooltip("State from which the AI starts executing next states depending on decisions.")] private FSMState _initialState;
[ReadOnly, Tooltip("Current state for debugging.")] public FSMState CurrentState;
[SerializeField, Tooltip("State from which the AI starts executing next states depending on decisions.")]
private FSMState initialState;
[Tooltip("Transitions that are allowed from any state.")]
public List<FSMTransition> FromAnyStateTransitions = new List<FSMTransition>();

public enum EmotionalState { Default, Interested, Afraid }
[ReadOnly, Tooltip("Current state for debugging.")]
public FSMState CurrentState;
public enum EmotionalState { Default, Interested, Panic }
public EmotionalState CurrentEmotionalState = EmotionalState.Default;
#region Public

//TODO: Maybe this is obsolete? Test how causing panic from external source works in practice...
/*
public void SetEmotionalState(EmotionalState emotionalState, float? returnToDefaultAfterSeconds)
{
//Set new current state
CurrentEmotionalState = emotionalState;
//Return to default state after timer has run
if (returnToDefaultAfterSeconds.HasValue)
Observable.Timer(TimeSpan.FromSeconds(returnToDefaultAfterSeconds.Value)).Take(1).Subscribe(x => CurrentEmotionalState = EmotionalState.Default).AddTo(this);
Observable.Timer(TimeSpan.FromSeconds(returnToDefaultAfterSeconds.Value)).Take(1).Subscribe(x => { CurrentEmotionalState = EmotionalState.Default; Debug.Log("*** Timer ended, changed emotion!"); }).AddTo(this);
}
*/
#endregion

#region Unity
protected virtual void Awake()
{
CurrentState = _initialState;
CurrentState = initialState;
}

protected override void Update()
{
base.Update();
CurrentState.Execute(this);
CurrentState.ExecuteState(this);
}
#endregion
}
19 changes: 14 additions & 5 deletions Assets/Scripts/CharacterAndAI/FSMAction.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
using UnityEngine;

public abstract class FSMAction : ScriptableObject
public abstract class FSMAction : ScriptableObject, ISerializationCallbackReceiver
{
public bool ExecuteOnce = false;

public bool Executed { get; private set; } = false;

[System.NonSerialized]
public bool IsExecuted = false;

public virtual void Execute(FSMCharacter stateMachine)
{
if (ExecuteOnce)
Executed = true;
IsExecuted = true;
}

public void SetExecuted(bool isExecuted)
{
Executed = isExecuted;
IsExecuted = isExecuted;
}

public void OnAfterDeserialize()
{
IsExecuted = false;
}

public void OnBeforeSerialize() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ public class FSMActionInterestingObject : FSMAction
public override void Execute(FSMCharacter stateMachine)
{
base.Execute(stateMachine);
Debug.Log("Execute sight interesting object");
var navMeshAgent = stateMachine.GetComponent<NavMeshAgent>();

AISensor enemySightSensor = stateMachine.GetComponent<AISensor>();
GameObject firstObject = enemySightSensor.Objects.FirstOrDefault();
navMeshAgent.SetDestination(firstObject.transform.position);
GameObject firstObject = enemySightSensor.Objects.FirstOrDefault();
stateMachine.SetDirectAgentDestination(firstObject.transform.position);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class FSMActionPatrol : FSMAction
public override void Execute(FSMCharacter stateMachine)
{
base.Execute(stateMachine);
Debug.Log("Execute Patrol Action");

if (!stateMachine.Agent.hasPath || stateMachine.Agent.remainingDistance < CloseEnoughDistance)
{
stateMachine.SetNextPatrolPointDestination();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using UnityEngine;
using System.Linq;

[CreateAssetMenu(menuName = "FSM/Decisions/In Line Of Sight")]
public class FSMDecisionInterestingInSight : FSMDecision
[CreateAssetMenu(menuName = "FSM/Decisions/Investigate Interesting Sighted Object")]
public class FSMDecisionInterestingInSight : FSMDecision
{
public override bool Decide(FSMCharacter stateMachine)
{
public override bool Decide(FSMCharacter stateMachine)
{
AISensor enemySightSensor = stateMachine.GetComponent<AISensor>();
return enemySightSensor.Objects.FirstOrDefault() != null ? true : false;
}
AISensor enemySightSensor = stateMachine.GetComponent<AISensor>();

InterestingObject firstInterestingObject = enemySightSensor.Objects.Select(go => go.GetComponent<InterestingObject>()).FirstOrDefault();
return firstInterestingObject?.IsStillInteresting() ?? false;
}
}

This file was deleted.

17 changes: 11 additions & 6 deletions Assets/Scripts/CharacterAndAI/FSMState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ public class FSMState : ScriptableObject
public List<FSMTransition> Transitions = new List<FSMTransition>();
public bool RemainState = false;

public virtual void Execute(FSMCharacter machine)
public virtual void ExecuteState(FSMCharacter machine)
{
foreach (var action in Action)
foreach (FSMAction action in Action)
{
Debug.Log("Execute state action: " + action);
if (action.ExecuteOnce/* && !action.Executed*/)

if (action.ExecuteOnce)
{
if (!action.Executed)
if (!action.IsExecuted)
action.Execute(machine);
}
else
Expand All @@ -24,7 +24,12 @@ public virtual void Execute(FSMCharacter machine)
}
}

foreach (var transition in Transitions)
foreach (FSMTransition transition in Transitions)
transition.Execute(machine);

foreach (FSMTransition transition in machine.FromAnyStateTransitions)
{
transition.Execute(machine);
}
}
}
30 changes: 25 additions & 5 deletions Assets/Scripts/CharacterAndAI/FSMTransition.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
using UnityEngine;

[CreateAssetMenu(menuName = "FSM/Transition")]
public sealed class FSMTransition : ScriptableObject
public sealed class FSMTransition : ScriptableObject, ISerializationCallbackReceiver
{
public FSMDecision Decision;
public FSMState TrueState;
public FSMState FalseState;

[System.NonSerialized]
private FSMState previousState = null;

public void Execute(FSMCharacter stateMachine)
{
if (Decision.Decide(stateMachine) && !TrueState.RemainState)
{
//TrueState and falseState to simply FSMState instead of base state.
//
stateMachine.CurrentState = TrueState;
//Prevent transition to same state
if (TrueState != previousState)
{
//Reset executed actions when state changes
TrueState.Action.ForEach(action => action.SetExecuted(false));
previousState = stateMachine.CurrentState = TrueState;
}
}
else if (!FalseState.RemainState)
{
stateMachine.CurrentState = FalseState;
//Prevent transition to same state
if (FalseState != previousState)
{
//Reset executed actions when state changes
TrueState.Action.ForEach(action => action.SetExecuted(false));
previousState = stateMachine.CurrentState = FalseState;
}
}
}

public void OnAfterDeserialize()
{
previousState = null;
}

public void OnBeforeSerialize() { }
}
5 changes: 1 addition & 4 deletions Assets/Scripts/Helper/ReadOnlyAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
using UnityEngine;
public class ReadOnlyAttribute : PropertyAttribute
{

}
public class ReadOnlyAttribute : PropertyAttribute { }
Loading

0 comments on commit 3ea612e

Please sign in to comment.