浏览代码

Merge branch 'state-machine' of https://github.com/DeivSky/open-project-1 into state-machine

/main
DeivSky 4 年前
当前提交
33f1fbae
共有 8 个文件被更改,包括 212 次插入212 次删除
  1. 96
      UOP1_Project/Assets/Scripts/StateMachine/Core/State.cs
  2. 34
      UOP1_Project/Assets/Scripts/StateMachine/Core/StateAction.cs
  3. 58
      UOP1_Project/Assets/Scripts/StateMachine/Core/StateTransition.cs
  4. 72
      UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableState.cs
  5. 36
      UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableStateAction.cs
  6. 30
      UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableStateCondition.cs
  7. 96
      UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableStateTransition.cs
  8. 2
      UOP1_Project/Assets/Scripts/StateMachineTest/ScriptableChaseAction.cs

96
UOP1_Project/Assets/Scripts/StateMachine/Core/State.cs


namespace DeivSky.StateMachine
{
public class State
{
public string Name { get; internal set; }
public class State
{
public string Name { get; internal set; }
internal StateMachine _stateMachine;
internal StateTransition[] _transitions;
internal StateAction[] _actions;
internal StateMachine _stateMachine;
internal StateTransition[] _transitions;
internal StateAction[] _actions;
internal State() { }
internal State() { }
public State(
StateMachine stateMachine,
StateTransition[] transitions,
StateAction[] actions)
{
_stateMachine = stateMachine;
_transitions = transitions;
_actions = actions;
}
public State(
StateMachine stateMachine,
StateTransition[] transitions,
StateAction[] actions)
{
_stateMachine = stateMachine;
_transitions = transitions;
_actions = actions;
}
public void OnStateEnter()
{
public void OnStateEnter()
{
for (int i = 0; i < comps.Length; i++)
comps[i].OnStateEnter();
}
OnStateEnter(_transitions);
OnStateEnter(_actions);
}
for (int i = 0; i < comps.Length; i++)
comps[i].OnStateEnter();
}
OnStateEnter(_transitions);
OnStateEnter(_actions);
}
public void OnUpdate()
{
for (int i = 0; i < _actions.Length; i++)
_actions[i].Perform();
}
public void OnUpdate()
{
for (int i = 0; i < _actions.Length; i++)
_actions[i].Perform();
}
public void OnStateExit()
{
void OnStateExit(IStateComponent[] comps)
{
for (int i = 0; i < comps.Length; i++)
comps[i].OnStateExit();
}
OnStateExit(_transitions);
OnStateExit(_actions);
}
public void OnStateExit()
{
void OnStateExit(IStateComponent[] comps)
{
for (int i = 0; i < comps.Length; i++)
comps[i].OnStateExit();
}
OnStateExit(_transitions);
OnStateExit(_actions);
}
public bool TryGetTransition(out State state)
{
for (int i = 0; i < _transitions.Length; i++)
if (_transitions[i].TryGetTransiton(out state))
return true;
public bool TryGetTransition(out State state)
{
for (int i = 0; i < _transitions.Length; i++)
if (_transitions[i].TryGetTransiton(out state))
return true;
state = null;
return false;
}
}
state = null;
return false;
}
}
}

34
UOP1_Project/Assets/Scripts/StateMachine/Core/StateAction.cs


namespace DeivSky.StateMachine
{
/// <summary>
/// An object representing an action.
/// </summary>
public abstract class StateAction : IStateComponent
{
/// <summary>
/// Perform the action this object represents.
/// </summary>
public abstract void Perform();
/// <summary>
/// An object representing an action.
/// </summary>
public abstract class StateAction : IStateComponent
{
/// <summary>
/// Perform the action this object represents.
/// </summary>
public abstract void Perform();
/// <summary>
/// Awake is called when creating a new instance. Use this method to cache the components needed for the action.
/// </summary>
/// <param name="stateMachine">The state machine this instance belongs to.</param>
public virtual void Awake(StateMachine stateMachine) { }
/// <summary>
/// Awake is called when creating a new instance. Use this method to cache the components needed for the action.
/// </summary>
/// <param name="stateMachine">The state machine this instance belongs to.</param>
public virtual void Awake(StateMachine stateMachine) { }
public virtual void OnStateEnter() { }
public virtual void OnStateExit() { }
}
public virtual void OnStateEnter() { }
public virtual void OnStateExit() { }
}
}

58
UOP1_Project/Assets/Scripts/StateMachine/Core/StateTransition.cs


namespace DeivSky.StateMachine
{
public class StateTransition : IStateComponent
{
private readonly State _targetState;
private readonly StateCondition[] _conditions;
private readonly int[] _resultGroups;
private readonly bool[] _results;
public class StateTransition : IStateComponent
{
private readonly State _targetState;
private readonly StateCondition[] _conditions;
private readonly int[] _resultGroups;
private readonly bool[] _results;
_resultGroups = resultGroups != null && resultGroups.Length > 0 ? resultGroups : new int[1];
_results = new bool[_resultGroups.Length];
_resultGroups = resultGroups != null && resultGroups.Length > 0 ? resultGroups : new int[1];
_results = new bool[_resultGroups.Length];
}
/// <summary>

/// <returns>True if the conditions are met.</returns>
public bool TryGetTransiton(out State state)
{
state = ShouldTransition() ? _targetState : null;
return state != null;
}
public void OnStateEnter()
for (int i = 0; i < _conditions.Length; i++)
_conditions[i]._condition.OnStateEnter();
state = ShouldTransition() ? _targetState : null;
return state != null;
public void OnStateExit()
public void OnStateEnter()
for (int i = 0; i < _conditions.Length; i++)
_conditions[i]._condition.OnStateExit();
for (int i = 0; i < _conditions.Length; i++)
_conditions[i]._condition.OnStateEnter();
}
public void OnStateExit()
{
for (int i = 0; i < _conditions.Length; i++)
_conditions[i]._condition.OnStateExit();
private bool ShouldTransition()
{
int count = _resultGroups.Length;
private bool ShouldTransition()
{
int count = _resultGroups.Length;
bool ret = false;
for (int i = 0; i < count && !ret; i++)
ret = ret || _results[i];
return ret;
}
}
bool ret = false;
for (int i = 0; i < count && !ret; i++)
ret = ret || _results[i];
return ret;
}
}
}

72
UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableState.cs


namespace DeivSky.StateMachine.Scriptables
{
[CreateAssetMenu(fileName = "New State", menuName = "State Machines/State")]
public class ScriptableState : ScriptableObject
{
[SerializeField] private ScriptableStateAction[] _actions = null;
[SerializeField] private ScriptableStateTransition[] _transitions = null;
[CreateAssetMenu(fileName = "New State", menuName = "State Machines/State")]
public class ScriptableState : ScriptableObject
{
[SerializeField] private ScriptableStateAction[] _actions = null;
[SerializeField] private ScriptableStateTransition[] _transitions = null;
internal State GetState(StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var obj))
return (State)obj;
internal State GetState(StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var obj))
return (State)obj;
var state = new State();
createdInstances.Add(this, state);
var state = new State();
createdInstances.Add(this, state);
state.Name = name;
state._stateMachine = stateMachine;
state._transitions = GetTransitions(_transitions, stateMachine, createdInstances);
state._actions = GetActions(_actions, stateMachine, createdInstances);
state.Name = name;
state._stateMachine = stateMachine;
state._transitions = GetTransitions(_transitions, stateMachine, createdInstances);
state._actions = GetActions(_actions, stateMachine, createdInstances);
return state;
}
return state;
}
private static StateTransition[] GetTransitions(ScriptableStateTransition[] scriptableTransitions,
StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
int count = scriptableTransitions.Length;
var transitions = new StateTransition[count];
for (int i = 0; i < count; i++)
transitions[i] = scriptableTransitions[i].GetTransition(stateMachine, createdInstances);
private static StateTransition[] GetTransitions(ScriptableStateTransition[] scriptableTransitions,
StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
int count = scriptableTransitions.Length;
var transitions = new StateTransition[count];
for (int i = 0; i < count; i++)
transitions[i] = scriptableTransitions[i].GetTransition(stateMachine, createdInstances);
return transitions;
}
return transitions;
}
private static StateAction[] GetActions(ScriptableStateAction[] scriptableActions,
StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
int count = scriptableActions.Length;
var actions = new StateAction[count];
for (int i = 0; i < count; i++)
actions[i] = scriptableActions[i].GetAction(stateMachine, createdInstances);
private static StateAction[] GetActions(ScriptableStateAction[] scriptableActions,
StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
int count = scriptableActions.Length;
var actions = new StateAction[count];
for (int i = 0; i < count; i++)
actions[i] = scriptableActions[i].GetAction(stateMachine, createdInstances);
return actions;
}
}
return actions;
}
}
}

36
UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableStateAction.cs


namespace DeivSky.StateMachine.Scriptables
{
public abstract class ScriptableStateAction : ScriptableObject
{
internal StateAction GetAction(StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var obj))
return (StateAction)obj;
public abstract class ScriptableStateAction : ScriptableObject
{
internal StateAction GetAction(StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var obj))
return (StateAction)obj;
var action = CreateAction();
createdInstances.Add(this, action);
action.Awake(stateMachine);
return action;
}
protected abstract StateAction CreateAction();
}
var action = CreateAction();
createdInstances.Add(this, action);
action.Awake(stateMachine);
return action;
}
protected abstract StateAction CreateAction();
}
public abstract class ScriptableStateAction<T> : ScriptableStateAction where T : StateAction, new()
public abstract class ScriptableStateAction<T> : ScriptableStateAction where T : StateAction, new()
protected override StateAction CreateAction() => new T();
protected override StateAction CreateAction() => new T();
public abstract class SerializableStateAction<T> : ScriptableStateAction where T : StateAction, new()
public abstract class SerializableStateAction<T> : ScriptableStateAction where T : StateAction, new()
[SerializeField] private T _action = new T();
protected override StateAction CreateAction() => _action;
[SerializeField] private T _action = new T();
protected override StateAction CreateAction() => _action;
}
}

30
UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableStateCondition.cs


namespace DeivSky.StateMachine.Scriptables
{
public abstract class ScriptableStateCondition : ScriptableObject
{
internal StateCondition GetCondition(StateMachine stateMachine, bool expectedResult, Dictionary<ScriptableObject, object> createdInstances)
{
public abstract class ScriptableStateCondition : ScriptableObject
{
internal StateCondition GetCondition(StateMachine stateMachine, bool expectedResult, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var cond))
return new StateCondition((Condition)cond, expectedResult);

return condition;
}
protected abstract Condition CreateCondition();
}
protected abstract Condition CreateCondition();
}
public abstract class ScriptableStateCondition<T> : ScriptableStateCondition where T : Condition, new()
{
protected override Condition CreateCondition() => new T();
}
public abstract class ScriptableStateCondition<T> : ScriptableStateCondition where T : Condition, new()
{
protected override Condition CreateCondition() => new T();
}
public abstract class SerializableStateCondition<T> : ScriptableStateCondition where T : Condition, new()
{
[SerializeField] private T _condition = new T();
protected override Condition CreateCondition() => _condition;
}
public abstract class SerializableStateCondition<T> : ScriptableStateCondition where T : Condition, new()
{
[SerializeField] private T _condition = new T();
protected override Condition CreateCondition() => _condition;
}
}

96
UOP1_Project/Assets/Scripts/StateMachine/Scriptables/ScriptableStateTransition.cs


namespace DeivSky.StateMachine.Scriptables
{
[CreateAssetMenu(fileName = "New Transition", menuName = "State Machines/Transition")]
public class ScriptableStateTransition : ScriptableObject
{
[SerializeField] private ScriptableState _targetState = null;
[SerializeField] private ConditionUsage[] _conditions = default;
[CreateAssetMenu(fileName = "New Transition", menuName = "State Machines/Transition")]
public class ScriptableStateTransition : ScriptableObject
{
[SerializeField] private ScriptableState _targetState = null;
[SerializeField] private ConditionUsage[] _conditions = default;
internal StateTransition GetTransition(StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var obj))
return (StateTransition)obj;
internal StateTransition GetTransition(StateMachine stateMachine, Dictionary<ScriptableObject, object> createdInstances)
{
if (createdInstances.TryGetValue(this, out var obj))
return (StateTransition)obj;
var state = _targetState.GetState(stateMachine, createdInstances);
ProcessConditionUsages(stateMachine, _conditions, createdInstances, out var conditions, out var resultGroups);
var state = _targetState.GetState(stateMachine, createdInstances);
ProcessConditionUsages(stateMachine, _conditions, createdInstances, out var conditions, out var resultGroups);
var transition = new StateTransition(state, conditions, resultGroups);
createdInstances.Add(this, transition);
return transition;
}
var transition = new StateTransition(state, conditions, resultGroups);
createdInstances.Add(this, transition);
return transition;
}
private static void ProcessConditionUsages(
StateMachine stateMachine,
ConditionUsage[] conditionUsages,
Dictionary<ScriptableObject, object> createdInstances,
out StateCondition[] conditions,
out int[] resultGroups)
private static void ProcessConditionUsages(
StateMachine stateMachine,
ConditionUsage[] conditionUsages,
Dictionary<ScriptableObject, object> createdInstances,
out StateCondition[] conditions,
out int[] resultGroups)
int count = conditionUsages.Length;
conditions = new StateCondition[count];
for (int i = 0; i < count; i++)
conditions[i] = conditionUsages[i].Condition.GetCondition(
stateMachine, conditionUsages[i].ExpectedResult == Result.True,createdInstances);
int count = conditionUsages.Length;
conditions = new StateCondition[count];
for (int i = 0; i < count; i++)
conditions[i] = conditionUsages[i].Condition.GetCondition(
stateMachine, conditionUsages[i].ExpectedResult == Result.True, createdInstances);
List<int> resultGroupsList = new List<int>();
for (int i = 0; i < count; i++)
{
int idx = i;
resultGroupsList.Add(1);
while (i < count - 1 && conditionUsages[i].Operator == Operator.And)
{
i++;
resultGroupsList[idx]++;
}
}
resultGroups = resultGroupsList.ToArray();
}
List<int> resultGroupsList = new List<int>();
for (int i = 0; i < count; i++)
{
int idx = i;
resultGroupsList.Add(1);
while (i < count - 1 && conditionUsages[i].Operator == Operator.And)
{
i++;
resultGroupsList[idx]++;
}
}
[Serializable]
public struct ConditionUsage
{
public Result ExpectedResult;
public ScriptableStateCondition Condition;
public Operator Operator;
}
resultGroups = resultGroupsList.ToArray();
}
[Serializable]
public struct ConditionUsage
{
public Result ExpectedResult;
public ScriptableStateCondition Condition;
public Operator Operator;
}
}
}
}

2
UOP1_Project/Assets/Scripts/StateMachineTest/ScriptableChaseAction.cs


if (_chaseData == null)
throw new ArgumentNullException(nameof(_chaseData));
if(string.IsNullOrEmpty(_chaseData.TargetName))
if (string.IsNullOrEmpty(_chaseData.TargetName))
throw new ArgumentNullException(nameof(_chaseData.TargetName));
_chaseTransform = GameObject.Find(_chaseData.TargetName).transform;

正在加载...
取消
保存