Add doxygen for Arena and Battle AI

Plus some coding-style cleanup
This commit is contained in:
Benau 2016-10-20 16:40:20 +08:00
parent b12f7a1079
commit 021509387d
7 changed files with 159 additions and 53 deletions

View File

@ -75,6 +75,8 @@ protected:
float *radius) const; float *radius) const;
virtual void update (float delta); virtual void update (float delta);
virtual void setSteering (float angle, float dt); virtual void setSteering (float angle, float dt);
// ------------------------------------------------------------------------
/** Return true if AI can skid now. */
virtual bool canSkid(float steer_fraction) = 0; virtual bool canSkid(float steer_fraction) = 0;
public: public:

View File

@ -74,6 +74,7 @@ void ArenaAI::reset()
/** This is the main entry point for the AI. /** This is the main entry point for the AI.
* It is called once per frame for each AI and determines the behaviour of * It is called once per frame for each AI and determines the behaviour of
* the AI, e.g. steering, accelerating/braking, firing. * the AI, e.g. steering, accelerating/braking, firing.
* \param dt Time step size.
*/ */
void ArenaAI::update(float dt) void ArenaAI::update(float dt)
{ {
@ -170,10 +171,7 @@ bool ArenaAI::updateAimingPosition(Vec3* target_point)
m_debug_sphere_next->setVisible(false); m_debug_sphere_next->setVisible(false);
#endif #endif
// Notice: we use the point ahead of kart to determine next node, m_current_forward_point = m_kart->getTrans()(Vec3(0, 0, m_kart_length));
// to compensate the time difference between steering
m_current_forward_point =
m_kart->getTrans()(Vec3(0, 0, m_kart->getKartLength()));
m_turn_radius = 0.0f; m_turn_radius = 0.0f;
std::vector<int>* test_nodes = NULL; std::vector<int>* test_nodes = NULL;
@ -238,7 +236,7 @@ bool ArenaAI::updateAimingPosition(Vec3* target_point)
} // updateAimingPosition } // updateAimingPosition
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** This function config the steering of AI. /** This function config the steering (\ref m_steering_angle) of AI.
*/ */
void ArenaAI::configSteering() void ArenaAI::configSteering()
{ {
@ -294,6 +292,11 @@ void ArenaAI::configSteering()
} // configSteering } // configSteering
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Determine whether AI is stuck, by checking if it stays on the same node for
* a long period of time (see \ref m_on_node), or \ref isStuck() is true.
* \param dt Time step size.
* \return True if AI is stuck
*/
void ArenaAI::checkIfStuck(const float dt) void ArenaAI::checkIfStuck(const float dt)
{ {
if (m_is_stuck) return; if (m_is_stuck) return;
@ -312,8 +315,7 @@ void ArenaAI::checkIfStuck(const float dt)
&& m_on_node.size() < 2 && !m_is_uturn && && m_on_node.size() < 2 && !m_is_uturn &&
fabsf(m_kart->getSpeed()) < 3.0f) || isStuck() == true) fabsf(m_kart->getSpeed()) < 3.0f) || isStuck() == true)
{ {
// Check whether a kart stay on the same node for a period of time // AI is stuck, reset now and try to get unstuck at next frame
// Or crashed 3 times
m_on_node.clear(); m_on_node.clear();
m_time_since_driving = 0.0f; m_time_since_driving = 0.0f;
AIBaseController::reset(); AIBaseController::reset();
@ -355,6 +357,8 @@ void ArenaAI::configSpeed()
} // configSpeed } // configSpeed
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Make AI reverse so that it faces in front of the last target point.
*/
void ArenaAI::doUTurn(const float dt) void ArenaAI::doUTurn(const float dt)
{ {
float turn_angle = atan2f(m_target_point_lc.x(), float turn_angle = atan2f(m_target_point_lc.x(),
@ -377,6 +381,10 @@ void ArenaAI::doUTurn(const float dt)
} // doUTurn } // doUTurn
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Function to let AI get unstuck.
* \param dt Time step size.
* \return True if getting stuck is needed to be done.
*/
bool ArenaAI::gettingUnstuck(const float dt) bool ArenaAI::gettingUnstuck(const float dt)
{ {
if (!m_is_stuck || m_is_uturn) return false; if (!m_is_stuck || m_is_uturn) return false;
@ -398,6 +406,10 @@ bool ArenaAI::gettingUnstuck(const float dt)
} // gettingUnstuck } // gettingUnstuck
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Determine how AI should use its item, different \ref m_cur_difficulty will
* have a corresponding strategy.
* \param dt Time step size.
*/
void ArenaAI::useItems(const float dt) void ArenaAI::useItems(const float dt)
{ {
m_controls->setFire(false); m_controls->setFire(false);
@ -406,7 +418,7 @@ void ArenaAI::useItems(const float dt)
return; return;
// Find a closest kart again, this time we ignore difficulty // Find a closest kart again, this time we ignore difficulty
findClosestKart(false/*use_difficulty*/, false/*find_sta*/); findClosestKart(false/*consider_difficulty*/, false/*find_sta*/);
if (!m_closest_kart) return; if (!m_closest_kart) return;
Vec3 closest_kart_point_lc = Vec3 closest_kart_point_lc =
@ -558,7 +570,12 @@ void ArenaAI::useItems(const float dt)
} // useItems } // useItems
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ArenaAI::collectItemInArena(Vec3* aim_point, int* target_node) const /** Try to collect item in arena, if no suitable item is found, like they are
* swapped, it will follow closest kart instead.
* \param[out] aim_point Location of item.
* \param[out] target_node The node which item lied on.
*/
void ArenaAI::tryCollectItem(Vec3* aim_point, int* target_node) const
{ {
float distance = 999999.9f; float distance = 999999.9f;
Item* selected = (*target_node == Graph::UNKNOWN_SECTOR ? NULL : Item* selected = (*target_node == Graph::UNKNOWN_SECTOR ? NULL :
@ -611,13 +628,15 @@ void ArenaAI::collectItemInArena(Vec3* aim_point, int* target_node) const
*aim_point = m_closest_kart_point; *aim_point = m_closest_kart_point;
*target_node = m_closest_kart_node; *target_node = m_closest_kart_node;
} }
} // collectItemInArena } // tryCollectItem
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Determine if AI should skid: When it's close to target, but not straight
* ahead, in front of it, same steering side and with suitable difficulties
* which are in expert and supertux only.
*/
void ArenaAI::doSkiddingTest() void ArenaAI::doSkiddingTest()
{ {
// Skid when close to target, but not straight ahead, in front of it, same
// steering side and with suitable difficulties.
const float abs_angle = atan2f(fabsf(m_target_point_lc.x()), const float abs_angle = atan2f(fabsf(m_target_point_lc.x()),
fabsf(m_target_point_lc.z())); fabsf(m_target_point_lc.z()));
if ((m_cur_difficulty == RaceManager::DIFFICULTY_HARD || if ((m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
@ -636,7 +655,7 @@ void ArenaAI::doSkiddingTest()
/** Determine if the path to target needs to be changed to avoid bad items, it /** Determine if the path to target needs to be changed to avoid bad items, it
* will also set the turn radius based on the new path if necessary. * will also set the turn radius based on the new path if necessary.
* \param forward Forward node of current AI position. * \param forward Forward node of current AI position.
* \param path Default path to target. * \param[in,out] path Default path to follow, will be changed if needed.
*/ */
void ArenaAI::determinePath(int forward, std::vector<int>* path) void ArenaAI::determinePath(int forward, std::vector<int>* path)
{ {

View File

@ -32,7 +32,6 @@ class ArenaGraph;
namespace irr namespace irr
{ {
namespace scene { class ISceneNode; } namespace scene { class ISceneNode; }
namespace video { class ITexture; }
} }
/** A base class for AI that use navmesh to work. /** A base class for AI that use navmesh to work.
@ -41,12 +40,16 @@ namespace irr
class ArenaAI : public AIBaseController class ArenaAI : public AIBaseController
{ {
protected: protected:
/** Pointer to the \ref ArenaGraph. */
ArenaGraph* m_graph; ArenaGraph* m_graph;
/** Pointer to the closest kart around this kart. */ /** Pointer to the closest kart around this kart. */
AbstractKart *m_closest_kart; AbstractKart *m_closest_kart;
/** The \ref ArenaNode at which the closest kart located on. */
int m_closest_kart_node; int m_closest_kart_node;
/** The closest kart location. */
Vec3 m_closest_kart_point; Vec3 m_closest_kart_point;
/** Holds the current difficulty. */ /** Holds the current difficulty. */
@ -55,25 +58,39 @@ protected:
/** For debugging purpose: a sphere indicating where the AI /** For debugging purpose: a sphere indicating where the AI
* is targeting at. */ * is targeting at. */
irr::scene::ISceneNode *m_debug_sphere; irr::scene::ISceneNode *m_debug_sphere;
/** For debugging purpose: a sphere indicating where the first
* turning corner is located. */
irr::scene::ISceneNode *m_debug_sphere_next; irr::scene::ISceneNode *m_debug_sphere_next;
/** The node(quad) at which the target point lies in. */ /** The \ref ArenaNode at which the target point located on. */
int m_target_node; int m_target_node;
/** The target point. */ /** The coordinates of target point. */
Vec3 m_target_point; Vec3 m_target_point;
/** True if AI can skid, currently only do when close to target, see
* \ref doSkiddingTest(). */
bool m_mini_skid; bool m_mini_skid;
void collectItemInArena(Vec3*, int*) const; // ------------------------------------------------------------------------
virtual void findClosestKart(bool use_difficulty, bool find_sta) = 0; void tryCollectItem(Vec3* aim_point, int* target_node) const;
// ------------------------------------------------------------------------
/** Find the closest kart around this AI, implemented by sub-class.
* \param consider_difficulty If take current difficulty into account.
* \param find_sta If find \ref SpareTireAI only. */
virtual void findClosestKart(bool consider_difficulty, bool find_sta) = 0;
private: private:
/** Local coordinates of current target point. */
Vec3 m_target_point_lc; Vec3 m_target_point_lc;
/** Save the last target point before reversing, so AI will end reversing
* until facing in front of it. */
Vec3 m_reverse_point; Vec3 m_reverse_point;
/** Indicates that the kart is currently stuck, and m_time_since_reversing is /** Indicates that the kart is currently stuck, and m_time_since_reversing
* counting down. */ * is counting down. */
bool m_is_stuck; bool m_is_stuck;
/** Indicates that the kart need a uturn to reach a node behind, and /** Indicates that the kart need a uturn to reach a node behind, and
@ -99,39 +116,79 @@ private:
/** This is a timer that counts when the kart start going off road. */ /** This is a timer that counts when the kart start going off road. */
float m_time_since_off_road; float m_time_since_off_road;
/** Used to determine braking and nitro usage. */
float m_turn_radius; float m_turn_radius;
/** Used to determine if skidding can be done. */
float m_steering_angle; float m_steering_angle;
/** The point in front of the AI which distance is \ref m_kart_length, used
* to compensate the time difference between steering when finding next
* node. */
Vec3 m_current_forward_point; Vec3 m_current_forward_point;
/** The \ref ArenaNode at which the forward point located on. */
int m_current_forward_node; int m_current_forward_node;
void configSpeed(); void configSpeed();
// ------------------------------------------------------------------------
void configSteering(); void configSteering();
// ------------------------------------------------------------------------
void checkIfStuck(const float dt); void checkIfStuck(const float dt);
// ------------------------------------------------------------------------
void determinePath(int forward, std::vector<int>* path); void determinePath(int forward, std::vector<int>* path);
// ------------------------------------------------------------------------
void doSkiddingTest(); void doSkiddingTest();
// ------------------------------------------------------------------------
void doUTurn(const float dt); void doUTurn(const float dt);
// ------------------------------------------------------------------------
bool gettingUnstuck(const float dt); bool gettingUnstuck(const float dt);
// ------------------------------------------------------------------------
bool updateAimingPosition(Vec3* target_point); bool updateAimingPosition(Vec3* target_point);
// ------------------------------------------------------------------------
void useItems(const float dt); void useItems(const float dt);
// ------------------------------------------------------------------------
virtual bool canSkid(float steer_fraction) OVERRIDE virtual bool canSkid(float steer_fraction) OVERRIDE
{ return m_mini_skid; } { return m_mini_skid; }
// ------------------------------------------------------------------------
/** Find a suitable target for this frame, implemented by sub-class. */
virtual void findTarget() = 0; virtual void findTarget() = 0;
virtual bool forceBraking() { return false; } // ------------------------------------------------------------------------
/** If true, AI will always try to brake for this frame. */
virtual bool forceBraking() { return false; }
// ------------------------------------------------------------------------
/** Return the current \ref ArenaNode the AI located on. */
virtual int getCurrentNode() const = 0; virtual int getCurrentNode() const = 0;
// ------------------------------------------------------------------------
/** Return the distance based on graph distance matrix to any kart.
* \param kart \ref AbstractKart to check. */
virtual float getKartDistance(const AbstractKart* kart) const = 0; virtual float getKartDistance(const AbstractKart* kart) const = 0;
virtual bool ignorePathFinding() { return false; } // ------------------------------------------------------------------------
/** If true, AI will drive directly to target without path finding. */
virtual bool ignorePathFinding() { return false; }
// ------------------------------------------------------------------------
/** If true, AI will stop moving. */
virtual bool isWaiting() const = 0; virtual bool isWaiting() const = 0;
// ------------------------------------------------------------------------
/** If true, AI stays on the \ref ArenaNode correctly, otherwise
* \ref RescueAnimation will be done after sometime. */
virtual bool isKartOnRoad() const = 0; virtual bool isKartOnRoad() const = 0;
virtual void resetAfterStop() {}; // ------------------------------------------------------------------------
/** Overridden if any action is needed to be done when AI stopped
* moving or changed driving direction. */
virtual void resetAfterStop() {}
public: public:
ArenaAI(AbstractKart *kart); ArenaAI(AbstractKart *kart);
virtual ~ArenaAI() {}; // ------------------------------------------------------------------------
virtual ~ArenaAI() {}
// ------------------------------------------------------------------------
virtual void update (float delta) OVERRIDE; virtual void update (float delta) OVERRIDE;
// ------------------------------------------------------------------------
virtual void reset () OVERRIDE; virtual void reset () OVERRIDE;
// ------------------------------------------------------------------------
virtual void newLap (int lap) OVERRIDE {} virtual void newLap (int lap) OVERRIDE {}
}; };
#endif #endif

View File

@ -56,7 +56,6 @@ BattleAI::BattleAI(AbstractKart *kart)
} // BattleAI } // BattleAI
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
BattleAI::~BattleAI() BattleAI::~BattleAI()
{ {
#ifdef AI_DEBUG #ifdef AI_DEBUG
@ -66,7 +65,12 @@ BattleAI::~BattleAI()
} // ~BattleAI } // ~BattleAI
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void BattleAI::findClosestKart(bool use_difficulty, bool find_sta) /** Find the closest kart around this AI, if consider_difficulty is true, AI
* will try to follow human players more or less depends on difficulty.
* \param consider_difficulty If take current difficulty into account.
* \param find_sta If find \ref SpareTireAI only.
*/
void BattleAI::findClosestKart(bool consider_difficulty, bool find_sta)
{ {
float distance = 99999.9f; float distance = 99999.9f;
int closest_kart_num = 0; int closest_kart_num = 0;
@ -88,7 +92,8 @@ void BattleAI::findClosestKart(bool use_difficulty, bool find_sta)
// Test whether takes current difficulty into account for closest kart // Test whether takes current difficulty into account for closest kart
// Notice: it don't affect aiming, this function will be called once // Notice: it don't affect aiming, this function will be called once
// more when use items, which ignore difficulty. // more when use items, which ignore difficulty.
if (m_cur_difficulty == RaceManager::DIFFICULTY_EASY && use_difficulty) if (m_cur_difficulty == RaceManager::DIFFICULTY_EASY &&
consider_difficulty)
{ {
// Skip human players for novice mode unless only they are left // Skip human players for novice mode unless only they are left
const AbstractKart* temp = m_world->getKart(start_id); const AbstractKart* temp = m_world->getKart(start_id);
@ -98,7 +103,7 @@ void BattleAI::findClosestKart(bool use_difficulty, bool find_sta)
continue; continue;
} }
else if (m_cur_difficulty == RaceManager::DIFFICULTY_BEST && else if (m_cur_difficulty == RaceManager::DIFFICULTY_BEST &&
use_difficulty) consider_difficulty)
{ {
// Skip AI players for supertux mode // Skip AI players for supertux mode
const AbstractKart* temp = m_world->getKart(start_id); const AbstractKart* temp = m_world->getKart(start_id);
@ -122,33 +127,44 @@ void BattleAI::findClosestKart(bool use_difficulty, bool find_sta)
} // findClosestKart } // findClosestKart
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Find a suitable target to follow, it will find the closest kart first, it's
* used as fallback if no item is found. It takes the current difficulty into
* account, also collect life from \ref SpareTireAI depends on current
* difficulty if actually they are spawned:
* \li Novice and intermediate - collect them only AI has 1 life only.
* \li Expert and supertux - collect them if AI dones't have 3 lives.
*/
void BattleAI::findTarget() void BattleAI::findTarget()
{ {
// Find the closest kart first, it's used as fallback if no item is found. bool find_sta = false;
// It takes the current difficulty into account, also collect life from if (m_world->spareTireKartsSpawned())
// spare tire karts when neccessary {
switch (m_cur_difficulty)
{
case RaceManager::DIFFICULTY_EASY:
case RaceManager::DIFFICULTY_MEDIUM:
{
find_sta = m_world->getKartLife(m_kart->getWorldKartId()) == 1;
break;
}
case RaceManager::DIFFICULTY_HARD:
case RaceManager::DIFFICULTY_BEST:
{
find_sta = m_world->getKartLife(m_kart->getWorldKartId()) != 3;
break;
}
default: assert(false);
}
}
// Collect life depends on current difficulty: bool consider_difficulty = !find_sta;
// Novice and intermediate - collect them only AI has 1 life only findClosestKart(consider_difficulty, find_sta);
// Expert and supertux - collect them if AI dones't have 3 lives
// Also when actually spare tire karts are spawned
bool find_sta = m_world->spareTireKartsSpawned() ?
((m_cur_difficulty == RaceManager::DIFFICULTY_EASY ||
m_cur_difficulty == RaceManager::DIFFICULTY_MEDIUM) &&
m_world->getKartLife(m_kart->getWorldKartId()) == 1 ?
true :
(m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
m_cur_difficulty == RaceManager::DIFFICULTY_BEST) &&
m_world->getKartLife(m_kart->getWorldKartId()) != 3 ?
true : false) : false;
findClosestKart(find_sta ? false : true/*use_difficulty*/, find_sta);
// Find a suitable target to drive to, either powerup or kart // Find a suitable target to drive to, either powerup or kart
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING && if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING &&
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER && m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER &&
!find_sta) !find_sta)
collectItemInArena(&m_target_point , &m_target_node); tryCollectItem(&m_target_point , &m_target_node);
else else
{ {
m_target_point = m_closest_kart_point; m_target_point = m_closest_kart_point;

View File

@ -33,16 +33,28 @@ class BattleAI : public ArenaAI
protected: protected:
/** Keep a pointer to world. */ /** Keep a pointer to world. */
ThreeStrikesBattle *m_world; ThreeStrikesBattle *m_world;
virtual void findClosestKart(bool use_difficulty, bool find_sta) OVERRIDE;
// ------------------------------------------------------------------------
virtual void findClosestKart(bool consider_difficulty,
bool find_sta) OVERRIDE;
// ------------------------------------------------------------------------
virtual int getCurrentNode() const OVERRIDE; virtual int getCurrentNode() const OVERRIDE;
private: private:
// ------------------------------------------------------------------------
virtual void findTarget() OVERRIDE; virtual void findTarget() OVERRIDE;
// ------------------------------------------------------------------------
virtual float getKartDistance(const AbstractKart* kart) const OVERRIDE; virtual float getKartDistance(const AbstractKart* kart) const OVERRIDE;
// ------------------------------------------------------------------------
virtual bool isKartOnRoad() const OVERRIDE; virtual bool isKartOnRoad() const OVERRIDE;
// ------------------------------------------------------------------------
virtual bool isWaiting() const OVERRIDE; virtual bool isWaiting() const OVERRIDE;
public: public:
BattleAI(AbstractKart *kart); BattleAI(AbstractKart *kart);
// ------------------------------------------------------------------------
~BattleAI(); ~BattleAI();
}; };
#endif #endif

View File

@ -129,7 +129,7 @@ void SoccerAI::update(float dt)
} // update } // update
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SoccerAI::findClosestKart(bool use_difficulty, bool find_sta) void SoccerAI::findClosestKart(bool consider_difficulty, bool find_sta)
{ {
float distance = 99999.9f; float distance = 99999.9f;
const unsigned int n = m_world->getNumKarts(); const unsigned int n = m_world->getNumKarts();
@ -165,7 +165,7 @@ void SoccerAI::findClosestKart(bool use_difficulty, bool find_sta)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SoccerAI::findTarget() void SoccerAI::findTarget()
{ {
findClosestKart(true/*use_difficulty*/, false/*find_sta*/); findClosestKart(true/*consider_difficulty*/, false/*find_sta*/);
// Check if this AI kart is the one who will chase the ball // Check if this AI kart is the one who will chase the ball
if (m_world->getBallChaser(m_cur_team) == (signed)m_kart->getWorldKartId()) if (m_world->getBallChaser(m_cur_team) == (signed)m_kart->getWorldKartId())
{ {
@ -181,7 +181,7 @@ void SoccerAI::findTarget()
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING && if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING &&
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER) m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER)
{ {
collectItemInArena(&m_target_point , &m_target_node); tryCollectItem(&m_target_point , &m_target_node);
} }
else if (m_world->getAttacker(m_cur_team) == (signed)m_kart else if (m_world->getAttacker(m_cur_team) == (signed)m_kart
->getWorldKartId()) ->getWorldKartId())

View File

@ -65,7 +65,7 @@ private:
virtual bool canSkid(float steer_fraction) OVERRIDE virtual bool canSkid(float steer_fraction) OVERRIDE
{ return m_mini_skid && !(m_overtake_ball || m_chasing_ball); } { return m_mini_skid && !(m_overtake_ball || m_chasing_ball); }
virtual void findClosestKart(bool use_difficulty, bool find_sta) OVERRIDE; virtual void findClosestKart(bool consider_difficulty, bool find_sta) OVERRIDE;
virtual void findTarget() OVERRIDE; virtual void findTarget() OVERRIDE;
virtual bool forceBraking() OVERRIDE { return m_force_brake; } virtual bool forceBraking() OVERRIDE { return m_force_brake; }
virtual int getCurrentNode() const OVERRIDE; virtual int getCurrentNode() const OVERRIDE;