diff options
Diffstat (limited to 'src/libjin/ai')
-rw-r--r-- | src/libjin/ai/je_ai.h | 7 | ||||
-rw-r--r-- | src/libjin/ai/je_behavior_tree.h | 4 | ||||
-rw-r--r-- | src/libjin/ai/je_state_machine.cpp | 407 | ||||
-rw-r--r-- | src/libjin/ai/je_state_machine.h | 128 |
4 files changed, 486 insertions, 60 deletions
diff --git a/src/libjin/ai/je_ai.h b/src/libjin/ai/je_ai.h new file mode 100644 index 0000000..74c4fd1 --- /dev/null +++ b/src/libjin/ai/je_ai.h @@ -0,0 +1,7 @@ +#ifndef __JE_AI_H +#define __JE_AI_H + +#include "je_state_machine.h" +#include "je_behavior_tree.h" + +#endif
\ No newline at end of file diff --git a/src/libjin/ai/je_behavior_tree.h b/src/libjin/ai/je_behavior_tree.h index bfd0c6b..6c7c25f 100644 --- a/src/libjin/ai/je_behavior_tree.h +++ b/src/libjin/ai/je_behavior_tree.h @@ -19,8 +19,8 @@ namespace JinEngine }; - } -} + } // namespace AI +} // namespace JinEngine #endif // jin_ai diff --git a/src/libjin/ai/je_state_machine.cpp b/src/libjin/ai/je_state_machine.cpp index 3a8cd0d..2d82a0a 100644 --- a/src/libjin/ai/je_state_machine.cpp +++ b/src/libjin/ai/je_state_machine.cpp @@ -1,5 +1,7 @@ #include "je_state_machine.h" +#include "../utils/je_log.h" + using namespace std; namespace JinEngine @@ -7,120 +9,471 @@ namespace JinEngine namespace AI { - StateMachine::StateMachine() + StateMachine::StateMachine(Mode mode, void* userdata) + : mCurrentState("Empty") + , mUserData(userdata) + , mMode(mode) { - + addState("Empty"); } StateMachine::~StateMachine() { + } + void StateMachine::invokeCallback(const string& from, const string& to) + { + if (mExitCallback != nullptr) + mExitCallback(from, mUserData); + if (mTraslateCallback != nullptr) + mTraslateCallback(from, to, mUserData); + if (mEnterCallback != nullptr) + mEnterCallback(to, mUserData); + map<string, StateChangeCallback*>::iterator it = mOnExitState.find(from); + if (it != mOnExitState.end()) + it->second(mUserData); + map<pair<string, string>, StateTranslateCallback*>::iterator transItr + = mOnStateTranslate.find(pair<string, string>(from, to)); + if (transItr != mOnStateTranslate.end()) + transItr->second(mUserData); + it = mOnEnterState.find(to); + if (it != mOnEnterState.end()) + it->second(mUserData); } - void StateMachine::onUpdate() + void StateMachine::stepwiseProcess() { + map<string, State>::iterator it = mStates.find(mCurrentState); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", mCurrentState); + return; + } + State& state = it->second; + for (int i = 0; i < state.transitions.size(); ++i) + { + if (processCondition(state.transitions[i].condition)) + { + // Traslate + mCurrentState = state.transitions[i].state; + invokeCallback(state.name, mCurrentState); + return; + } + } + } + void StateMachine::iterativeProcess() + { + map<string, State>::iterator it = mStates.find(mCurrentState); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", mCurrentState); + return; + } + State& state = it->second; + for (int i = 0; i < state.transitions.size(); ++i) + { + if (processCondition(state.transitions[i].condition)) + { + // Traslate + mCurrentState = state.transitions[i].state; + invokeCallback(state.name, mCurrentState); + return iterativeProcess(); + } + } } - const string& StateMachine::getCurrentState() + void StateMachine::setMode(Mode mode) { + mMode = mode; + } + //ģʽ״̬ + void StateMachine::update() + { + switch (mMode) + { + case Mode::Iterative: iterativeProcess(); break; + case Mode::Stepwise: stepwiseProcess(); break; + } } - void StateMachine::addParameteri(const std::string& name) + bool StateMachine::processCondition(const Condition& condition) { + map<string, Parameter>::iterator it = mParameters.find(condition.parameter); + if (it == mParameters.end()) + { + jin_log_error("The parameter %s is not exist", condition.parameter); + return false; + } + Parameter& p = it->second; + switch (p.type) + { + case ParameterType::Int: return p.value._int == condition.value._int; + case ParameterType::Float: return p.value._float == condition.value._float; + case ParameterType::Bool: return p.value._bool == condition.value._bool; + case ParameterType::Trigger: + { + bool trigger = p.value._int == true; + if (trigger) p.value._int = false; + return trigger; + } + } + return false; + } + const string& StateMachine::getCurrentState() + { + return mCurrentState; } - void StateMachine::addParameterf(const std::string& name) + void StateMachine::addParameteri(const std::string& name) { + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Int; + p.value._int = 0; + mParameters.insert(pair<string, Parameter>(name, p)); + } + void StateMachine::addParameterf(const std::string& name) + { + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Float; + p.value._float = 0.0f; + mParameters.insert(pair<string, Parameter>(name, p)); } void StateMachine::addParameterb(const std::string& name) { - + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Bool; + p.value._bool = false; + mParameters.insert(pair<string, Parameter>(name, p)); } void StateMachine::addParametert(const std::string& name) { - + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Trigger; + p.value._trigger = false; + mParameters.insert(pair<string, Parameter>(name, p)); } void StateMachine::addState(const std::string& name) { + if (mStates.find(name) != mStates.end()) + { + jin_log_error("The state %s is already exist.", name); + return; + } + State state; + state.name = name; + mStates.insert(pair<string, State>(name, state)); + } + const char* StateMachine::parameterTypeString(ParameterType type) + { + switch (type) + { + case ParameterType::Int: return "int"; + case ParameterType::Float: return "float"; + case ParameterType::Bool: return "bool"; + case ParameterType::Trigger: return "trigger"; + } } void StateMachine::addTransitioni(const std::string& stateFrom, const std::string& stateTo, const std::string& name, int value) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Int) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a int value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._int = value; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::addTransitionf(const std::string& stateFrom, const std::string& stateTo, const std::string& name, float value) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Float) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a float value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._float = value; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::addTransitionb(const std::string& stateFrom, const std::string& stateTo, const std::string& name, bool value) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Bool) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a bool value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._bool = value; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::addTransitiont(const std::string& stateFrom, const std::string& stateTo, const std::string& name) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Trigger) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a trigger value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._trigger = true; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::setParameteri(const std::string& name, int value) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Int) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a int value to it", name, parameterTypeString(p.type)); + return; + } + p.value._int = value; } void StateMachine::setParameterf(const std::string& name, float value) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Float) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a float value to it", name, parameterTypeString(p.type)); + return; + } + p.value._float = value; } void StateMachine::setParameterb(const std::string& name, bool value) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Bool) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a bool value to it", name, parameterTypeString(p.type)); + return; + } + p.value._bool = value; } void StateMachine::setParametert(const std::string& name) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Trigger) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a trigger value to it", name, parameterTypeString(p.type)); + return; + } + p.value._trigger = true; } - void StateMachine::trigger(const std::string& name) + void StateMachine::forceToState(const std::string& name) { - + if (mStates.find(name) == mStates.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + mCurrentState = name; } - void StateMachine::forceToState(const std::string& name) + void StateMachine::addEnterListener(const std::string& state, StateChangeCallback* callback) { - + if (mOnEnterState.find(state) != mOnEnterState.end()) + { + jin_log_error("The enter listener of %s is already exist.", state); + return; + } + mOnEnterState.insert(pair<string, StateChangeCallback*>(state, callback)); } - void StateMachine::reset() + void StateMachine::addExitListener(const std::string& state, StateChangeCallback* callback) { - + if (mOnExitState.find(state) != mOnExitState.end()) + { + jin_log_error("The exit listener of %s is already exist.", state); + return; + } + mOnExitState.insert(pair<string, StateChangeCallback*>(state, callback)); } - void StateMachine::addEnterListener(SingleStateCallback callback) + void StateMachine::addTranslateListener(const std::string& from, const std::string& to, StateChangeCallback* callback) { - + if (mOnStateTranslate.find(pair<string, string>(from, to)) != mOnStateTranslate.end()) + { + jin_log_error("The traslate listener of %s to %s is already exist.", from, to); + return; + } + pair<string, string> key(from, to); + mOnStateTranslate.insert(pair<pair<string, string>, StateTranslateCallback*>(key, callback)); } - void StateMachine::addExitListener(SingleStateCallback callback) + void StateMachine::setEnterListener(SingleStateCallback* callback) { - + mEnterCallback = callback; } - void StateMachine::addTranslateListener(DoubleStateCallback callback) + void StateMachine::setExitListener(SingleStateCallback* callback) { + mExitCallback = callback; + } + void StateMachine::setTranslateListener(DoubleStateCallback* callback) + { + mTraslateCallback = callback; } + } // namespace AI } // namespace JinEngine
\ No newline at end of file diff --git a/src/libjin/ai/je_state_machine.h b/src/libjin/ai/je_state_machine.h index 9d7994a..193ab65 100644 --- a/src/libjin/ai/je_state_machine.h +++ b/src/libjin/ai/je_state_machine.h @@ -14,7 +14,6 @@ namespace JinEngine { namespace AI { - // Grab from Unity engine. /// /// A single layer statemachine. @@ -26,17 +25,36 @@ namespace JinEngine /// /// /// - typedef void(*SingleStateCallback)(const std::string& stateName); + enum Mode + { + Iterative, ///< Process until reach condition failed.(May cause endless loop) + Stepwise ///< Process one state each update. + }; /// /// /// - typedef void(*DoubleStateCallback)(const std::string& stateFrom, const std::string& stateTo); + typedef void(StateChangeCallback)(void* userdata); + + /// + /// + /// + typedef void(StateTranslateCallback)(void* userdata); + + /// + /// + /// + typedef void(SingleStateCallback)(const std::string& stateName, void* userdata); + + /// + /// + /// + typedef void(DoubleStateCallback)(const std::string& stateFrom, const std::string& stateTo, void* userdata); /// /// State machine constructor. /// - StateMachine(); + StateMachine(Mode mode = Mode::Stepwise, void* userdata = nullptr); /// /// State machine destructor. @@ -44,9 +62,14 @@ namespace JinEngine ~StateMachine(); /// - /// Update statemachine. /// - void onUpdate(); + /// + void setMode(Mode mode); + + /// + /// Process current state.. + /// + void update(); /// /// Get current state name. @@ -54,7 +77,7 @@ namespace JinEngine const std::string& getCurrentState(); /// - /// + /// Add a integer parameter. /// void addParameteri(const std::string& name); @@ -79,12 +102,12 @@ namespace JinEngine void addState(const std::string& name); /// - /// + /// /// void addTransitioni(const std::string& stateFrom, const std::string& stateTo, const std::string& name, int value); /// - /// + /// /// void addTransitionf(const std::string& stateFrom, const std::string& stateTo, const std::string& name, float value); @@ -119,51 +142,56 @@ namespace JinEngine void setParametert(const std::string& name); /// - /// Equivalent to setParameter(triggername); + /// Force change to state. /// - void trigger(const std::string& name); + void forceToState(const std::string& name); /// - /// Force change to state. + /// /// - void forceToState(const std::string& name); + void addEnterListener(const std::string& state, StateChangeCallback* callback); /// - /// Reset state machine. /// - void reset(); + /// + void addExitListener(const std::string& state, StateChangeCallback* callback); /// - /// /// - void addEnterListener(SingleStateCallback callback); + /// + void addTranslateListener(const std::string& from, const std::string& to, StateChangeCallback* callback); /// /// /// - void addExitListener(SingleStateCallback callback); + void setEnterListener(SingleStateCallback* callback); /// /// /// - void addTranslateListener(DoubleStateCallback callback); + void setExitListener(SingleStateCallback* callback); + + /// + /// + /// + void setTranslateListener(DoubleStateCallback* callback); private: enum ParameterType { Int, ///< A integer value. - FLoat, ///< A float value. + Float, ///< A float value. Bool, ///< A bool value. Trigger ///< A trigger will be reset to false after activated. }; union ParameterValue { - int _int; - float _float; - bool _bool; - byte _trigger; + int _int; ///< 0 by default. + float _float; ///< 0 by default. + bool _bool; ///< false by default. + bool _trigger; ///< false by default. }; struct Parameter @@ -187,7 +215,7 @@ namespace JinEngine struct Transition { Condition condition; ///< Condition to active transition. - std::string state; ///< + std::string state; ///< State to translate to. }; /// @@ -199,12 +227,31 @@ namespace JinEngine std::vector<Transition> transitions; ///< All transitions this state have. }; + const char* parameterTypeString(ParameterType type); + /// /// Check if condition is full filled. /// /// @param condition Condition to check. /// - bool checkCondition(const Condition& condition); + bool processCondition(const Condition& condition); + + typedef void(Processor)(void*); + + /// + /// + /// + void stepwiseProcess(); + + /// + /// + /// + void iterativeProcess(); + + /// + /// + /// + void invokeCallback(const std::string& from, const std::string& to); /// /// All state this state machine keeps. @@ -214,28 +261,47 @@ namespace JinEngine /// /// /// - std::map<std::string, SingleStateCallback> mOnEnterState; + std::map<std::string, StateChangeCallback*> mOnEnterState; /// /// /// - std::map<std::string, SingleStateCallback> mOnExitState; + std::map<std::string, StateChangeCallback*> mOnExitState; /// /// From first to second. /// - std::map<std::pair<std::string, std::string>, DoubleStateCallback> mOnStateTranslate; + std::map<std::pair<std::string, std::string>, StateTranslateCallback*> mOnStateTranslate; + + /// + /// + /// + SingleStateCallback* mEnterCallback; + + /// + /// + /// + SingleStateCallback* mExitCallback; + + /// + /// + /// + DoubleStateCallback* mTraslateCallback; /// /// Current state. /// - const State* mCurrentState; + std::string mCurrentState; /// /// All parameters. /// std::map<std::string, Parameter> mParameters; - + + Mode mMode; + + void* const mUserData; + }; } // namespace Graphics |