aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/ai
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/ai')
-rw-r--r--src/libjin/ai/je_ai.h7
-rw-r--r--src/libjin/ai/je_behavior_tree.h4
-rw-r--r--src/libjin/ai/je_state_machine.cpp407
-rw-r--r--src/libjin/ai/je_state_machine.h128
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