Added first and early version of an item-collecting AI (within
SkiddingAI). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11517 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
fe65f46035
commit
a1c51d61a5
@ -200,6 +200,22 @@
|
||||
post-skid-rotate-factor="1" jump-time="0.4"
|
||||
reduce-turn-min="0.2" reduce-turn-max="0.8"/>
|
||||
|
||||
<!-- Kart-specific settings used by the AI.
|
||||
max-item-angle: Items that would need more than this change in
|
||||
direction are not considered for collection.
|
||||
time-full-steer is the time for the AI to go from neutral steering to
|
||||
extreme left (or right). This can be used to reduce
|
||||
'shaking' of AI karts caused by changing steering direction
|
||||
too often. It also helps with making it easier to push the
|
||||
AI karts (otherwise micro-corrections make this nearly
|
||||
impossible). A value of 1/maxFPS / 2 will guarantee that
|
||||
the wheel can go from -1 to +1 steering in one frame,
|
||||
basically disabling this mechanism.
|
||||
-->
|
||||
<ai max-item-angle="0.7" max-item-angle-high-speed="0.3"
|
||||
time-full-steer="0.1"
|
||||
/>
|
||||
|
||||
<!-- Slipstream: length: How far behind a kart slipstream works
|
||||
collect-time: How many seconds of sstream give maximum benefit
|
||||
use-time: How long the benefit will last.
|
||||
@ -235,17 +251,10 @@
|
||||
than 23 can only be reached with powerups).
|
||||
time-full-steer is the time when a player's input goes from neutral
|
||||
steering to extreme left or right.
|
||||
time-full-steer-ai is the time for the AI to go from neutral steering to
|
||||
extreme left (or right). This can be used to reduce
|
||||
'shaking' of AI karts caused by changing steering direction
|
||||
too often. It also helps with making it easier to push the
|
||||
AI karts (otherwise micro-corrections make this nearly
|
||||
impossible). A value of 1/maxFPS / 2 will guarantee that
|
||||
the wheel can go from -1 to +1 steering in one frame,
|
||||
basically disabling this mechanism. -->
|
||||
-->
|
||||
<turn turn-speed= "0 10 25 45"
|
||||
turn-radius="2.0 7.5 15 25"
|
||||
time-full-steer ="0.2" time-full-steer-ai="0.1" />
|
||||
time-full-steer ="0.2" />
|
||||
|
||||
<!-- Speed and acceleration related values: power and max-speed (in m/s)
|
||||
have 3 values, one for low, medium, and hard.
|
||||
|
@ -907,6 +907,10 @@
|
||||
RelativePath="..\..\karts\controller\ai_base_controller.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\ai_properties.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\controller.cpp"
|
||||
>
|
||||
@ -2105,6 +2109,10 @@
|
||||
RelativePath="..\..\karts\controller\ai_base_controller.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\ai_properties.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\controller.hpp"
|
||||
>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
@ -34,9 +35,10 @@ AIBaseController::AIBaseController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: Controller(kart, player)
|
||||
{
|
||||
m_kart = kart;
|
||||
m_kart_length = m_kart->getKartLength();
|
||||
m_kart_width = m_kart->getKartWidth();
|
||||
m_kart = kart;
|
||||
m_kart_length = m_kart->getKartLength();
|
||||
m_kart_width = m_kart->getKartWidth();
|
||||
m_ai_properties = m_kart->getKartProperties()->getAIProperties();
|
||||
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
@ -415,7 +417,7 @@ void AIBaseController::setSteering(float angle, float dt)
|
||||
}
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_kart->getKartProperties()->getTimeFullSteerAI();
|
||||
float max_steer_change = dt/m_ai_properties->m_time_full_steer;
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
|
71
src/karts/controller/ai_properties.cpp
Normal file
71
src/karts/controller/ai_properties.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2012 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
|
||||
#include "io/xml_node.hpp"
|
||||
|
||||
float AIProperties::UNDEFINED = -99.9f;
|
||||
|
||||
/** Constructor. Sets all properties to the special UNDEFINED value.
|
||||
*/
|
||||
AIProperties::AIProperties()
|
||||
{
|
||||
m_max_item_angle = UNDEFINED;
|
||||
m_max_item_angle_high_speed = UNDEFINED;
|
||||
m_time_full_steer = UNDEFINED;
|
||||
} // AIProperties
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Loads the AI properties from an XML file.
|
||||
* \param ai_node The XML node containing all AI properties.
|
||||
*/
|
||||
void AIProperties::load(const XMLNode *ai_node)
|
||||
{
|
||||
ai_node->get("max-item-angle", &m_max_item_angle );
|
||||
ai_node->get("max-item-angle-high-speed", &m_max_item_angle_high_speed);
|
||||
ai_node->get("time-full-steer", &m_time_full_steer );
|
||||
} // load
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Check if all AI properties are defined, and aborts if some are missing.
|
||||
* \param filename Name of the file from which the properties are read.
|
||||
* Only used for error messages.
|
||||
*/
|
||||
void AIProperties::checkAllSet(const std::string &filename) const
|
||||
{
|
||||
#define CHECK_NEG( a,str_a) if(a<=UNDEFINED) { \
|
||||
fprintf(stderr,"Missing default value for '%s' in '%s'.\n", \
|
||||
str_a,filename.c_str());exit(-1); \
|
||||
}
|
||||
CHECK_NEG(m_max_item_angle, "max-item-angle" );
|
||||
CHECK_NEG(m_max_item_angle_high_speed, "max-item-angle-high-speed");
|
||||
CHECK_NEG(m_time_full_steer, "time-full-steer" );
|
||||
|
||||
} // checkAllSet
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void AIProperties::copyFrom(const AIProperties *destination)
|
||||
{
|
||||
*this = *destination;
|
||||
} // copyFrom
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* EOF */
|
72
src/karts/controller/ai_properties.hpp
Normal file
72
src/karts/controller/ai_properties.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2012 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_AI_PROPERTIES_HPP
|
||||
#define HEADER_AI_PROPERTIES_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
class XMLNode;
|
||||
|
||||
|
||||
/** A simple class that stores all AI related properties. It acts as
|
||||
* interface between kart_properties and AI (to avoid either passing
|
||||
* very many individual variables, or making KartProperties a dependency
|
||||
* of the AI). The AIs are friends of this class and so have access to
|
||||
* its protected members.
|
||||
* \ingroup karts
|
||||
*/
|
||||
|
||||
class AIProperties
|
||||
{
|
||||
public:
|
||||
//LEAK_CHECK();
|
||||
protected:
|
||||
// Give them access to the members
|
||||
friend class AIBaseController;
|
||||
friend class SkiddingAI;
|
||||
|
||||
/** Used to check that all values are defined in the xml file. */
|
||||
static float UNDEFINED;
|
||||
|
||||
/** Maximum direction change when trying to collect an item. Items that
|
||||
* are more than this away, will not even be considered. */
|
||||
float m_max_item_angle;
|
||||
|
||||
/** Maximum direction change when trying to collect an item while being on
|
||||
* high-speed (i.e. skidding bonus, nitro, ...). Items that
|
||||
* are more than this away, will not even be considered. */
|
||||
float m_max_item_angle_high_speed;
|
||||
|
||||
/** Time for AI karts to reach full steer angle (used to reduce shaking
|
||||
* of karts). */
|
||||
float m_time_full_steer;
|
||||
|
||||
public:
|
||||
|
||||
AIProperties();
|
||||
void load(const XMLNode *skid_node);
|
||||
void copyFrom(const AIProperties *destination);
|
||||
void checkAllSet(const std::string &filename) const;
|
||||
}; // AIProperties
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
|
@ -57,12 +57,14 @@
|
||||
#include "graphics/slip_stream.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
@ -82,12 +84,13 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
m_wait_for_players = true;
|
||||
m_make_use_of_slipstream = false;
|
||||
m_max_handicap_speed = 0.9f;
|
||||
m_item_tactic = IT_TEN_SECONDS;
|
||||
m_false_start_probability = 0.08f;
|
||||
m_min_start_delay = 0.3f;
|
||||
m_max_start_delay = 0.5f;
|
||||
m_min_steps = 1;
|
||||
m_item_tactic = IT_TEN_SECONDS;
|
||||
m_nitro_level = NITRO_NONE;
|
||||
m_item_behaviour = ITEM_COLLECT_NONE;
|
||||
m_handle_bomb = false;
|
||||
setSkiddingFraction(4.0f);
|
||||
break;
|
||||
@ -95,12 +98,13 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
m_wait_for_players = true;
|
||||
m_make_use_of_slipstream = false;
|
||||
m_max_handicap_speed = 0.95f;
|
||||
m_item_tactic = IT_CALCULATE;
|
||||
m_false_start_probability = 0.04f;
|
||||
m_min_start_delay = 0.25f;
|
||||
m_max_start_delay = 0.4f;
|
||||
m_min_steps = 1;
|
||||
m_item_tactic = IT_CALCULATE;
|
||||
m_nitro_level = NITRO_SOME;
|
||||
m_item_behaviour = ITEM_COLLECT_NONE;
|
||||
m_handle_bomb = true;
|
||||
setSkiddingFraction(3.0f);
|
||||
break;
|
||||
@ -117,13 +121,15 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
m_max_start_delay = 0.28f;
|
||||
m_min_steps = 2;
|
||||
m_nitro_level = NITRO_ALL;
|
||||
m_item_behaviour = ITEM_COLLECT_PRIORITY;
|
||||
m_handle_bomb = true;
|
||||
setSkiddingFraction(2.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1);
|
||||
m_debug_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1.0f);
|
||||
m_item_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1.0f);
|
||||
#define CURVE_PREDICT1 0
|
||||
#define CURVE_KART 1
|
||||
#define CURVE_LEFT 2
|
||||
@ -152,6 +158,7 @@ SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
irr::video::SColor(128, 0, 128, 0));
|
||||
#endif
|
||||
setControllerName("Skidding");
|
||||
|
||||
} // SkiddingAI
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -162,6 +169,7 @@ SkiddingAI::~SkiddingAI()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
irr_driver->removeNode(m_item_sphere);
|
||||
for(unsigned int i=0; i<NUM_CURVES; i++)
|
||||
{
|
||||
delete m_curve[i];
|
||||
@ -184,6 +192,7 @@ void SkiddingAI::reset()
|
||||
m_current_curve_radius = 0.0f;
|
||||
m_curve_center = Vec3(0,0,0);
|
||||
m_current_track_direction = GraphNode::DIR_STRAIGHT;
|
||||
m_item_to_collect = NULL;
|
||||
|
||||
AIBaseController::reset();
|
||||
m_track_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
@ -398,6 +407,14 @@ void SkiddingAI::handleBraking()
|
||||
} // handleBraking
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Decides in which direction to steer. If the kart is off track, it will
|
||||
* steer towards the center of the track. Otherwise it will call
|
||||
* findNonCrashingPoint to determine a point to aim for. Then it will
|
||||
* evaluate items to see if it should aim for any items or try to avoid
|
||||
* item, and potentially adjust the aim-at point, before computing the
|
||||
* steer direction to arrive at the currently aim-at point.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void SkiddingAI::handleSteering(float dt)
|
||||
{
|
||||
const int next = m_next_node_index[m_track_node];
|
||||
@ -463,23 +480,301 @@ void SkiddingAI::handleSteering(float dt)
|
||||
else
|
||||
{
|
||||
m_start_kart_crash_direction = 0;
|
||||
Vec3 straight_point;
|
||||
Vec3 aim_point;
|
||||
int last_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
#undef NEW_ALGORITHM
|
||||
#ifdef NEW_ALGORITHM
|
||||
findNonCrashingPoint2(&straight_point);
|
||||
findNonCrashingPoint2(&aim_point, &last_node);
|
||||
#else
|
||||
findNonCrashingPoint(&straight_point);
|
||||
findNonCrashingPoint(&aim_point, &last_node);
|
||||
#endif
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(aim_point.toIrrVector());
|
||||
#endif
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(straight_point.toIrrVector());
|
||||
#endif
|
||||
steer_angle = steerToPoint(straight_point);
|
||||
// Potentially adjust the point to aim for in order to either
|
||||
// aim to collect item, or steer to avoid a bad item.
|
||||
if(m_item_behaviour!=ITEM_COLLECT_NONE)
|
||||
handleItemCollectionAndAvoidance(&aim_point, last_node);
|
||||
|
||||
steer_angle = steerToPoint(aim_point);
|
||||
} // if m_current_track_direction!=LEFT/RIGHT
|
||||
|
||||
setSteering(steer_angle, dt);
|
||||
} // handleSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Decides if the currently selected aim at point (as determined by
|
||||
* handleSteering) should be changed in order to collect/avoid an item.
|
||||
* \param aim_point Currently selected point to aim at. If the AI should
|
||||
* try to collect an item, this value will be changed.
|
||||
* \param last_node Index of the graph node on which the aim_point is.
|
||||
*/
|
||||
void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
int last_node)
|
||||
{
|
||||
// Angle of line from kart to aim_point
|
||||
float kart_aim_angle = atan2(aim_point->getX()-m_kart->getXYZ().getX(),
|
||||
aim_point->getZ()-m_kart->getXYZ().getZ());
|
||||
|
||||
// The AI does a much better job of collecting items if after selecting
|
||||
// an item it tries to collect this item even if it doesn't fulfill the
|
||||
// original conditions to be selected in the first place anymore.
|
||||
// Example: An item was selected to be collected because the AI was
|
||||
// hitting it anyway. Then the aim_point changes, and the selected item
|
||||
// is not that close anymore. In many cases it is better to keep on
|
||||
// aiming for the items (otherwise the aiming will not have much benefit
|
||||
// and mostly only results in collecting items that are on long straights)
|
||||
if(m_item_to_collect)
|
||||
{
|
||||
if(handleSelectedItem(kart_aim_angle, aim_point, last_node))
|
||||
{
|
||||
// Still aim at the previsouly selected item.
|
||||
*aim_point = m_item_to_collect->getXYZ();
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_ai_debug)
|
||||
printf("[AI] %s unselects item.\n", m_kart->getIdent().c_str());
|
||||
// Otherwise remove the pre-selected item (and start
|
||||
// looking for a new item).
|
||||
m_item_to_collect = NULL;
|
||||
} // m_item_to_collect
|
||||
|
||||
|
||||
// Make sure we have a valid last_node
|
||||
if(last_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
last_node = m_next_node_index[m_track_node];
|
||||
|
||||
int node = m_track_node;
|
||||
float distance = 0;
|
||||
const Item *item_to_collect = NULL;
|
||||
const Item *item_to_avoid = NULL;
|
||||
|
||||
|
||||
const float max_item_lookahead_distance = 30.f;
|
||||
while(distance < max_item_lookahead_distance)
|
||||
{
|
||||
int q_index= QuadGraph::get()->getNode(node).getQuadIndex();
|
||||
const std::vector<Item *> &items_ahead =
|
||||
ItemManager::get()->getItemsInQuads(q_index);
|
||||
for(unsigned int i=0; i<items_ahead.size(); i++)
|
||||
{
|
||||
evaluateItems(items_ahead[i], kart_aim_angle,
|
||||
&item_to_avoid, &item_to_collect);
|
||||
} // for i<items_ahead;
|
||||
distance += QuadGraph::get()->getDistanceToNext(node,
|
||||
m_successor_index[node]);
|
||||
node = m_next_node_index[node];
|
||||
// Stop when we have reached the last quad
|
||||
if(node==last_node) break;
|
||||
} // while (distance < max_item_lookahead_distance)
|
||||
|
||||
core::line2df line_to_target(m_kart->getXYZ().getX(),
|
||||
m_kart->getXYZ().getZ(),
|
||||
aim_point->getX(), aim_point->getZ());
|
||||
|
||||
|
||||
if(item_to_collect)
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(false);
|
||||
#endif
|
||||
core::vector2df collect(item_to_collect->getXYZ().getX(),
|
||||
item_to_collect->getXYZ().getZ());
|
||||
core::vector2df cp = line_to_target.getClosestPoint(collect);
|
||||
Vec3 xyz(cp.X, item_to_collect->getXYZ().getY(), cp.Y);
|
||||
if(item_to_collect->hitKart(NULL, xyz))
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(true);
|
||||
m_item_sphere->setPosition(item_to_collect->getXYZ().toIrrVector());
|
||||
#endif
|
||||
if(m_ai_debug)
|
||||
printf("[AI] %s selects item type '%d'.\n",
|
||||
m_kart->getIdent().c_str(),
|
||||
item_to_collect->getType());
|
||||
m_item_to_collect = item_to_collect;
|
||||
}
|
||||
else // kart will not hit item
|
||||
{
|
||||
Vec3 xyz = item_to_collect->getXYZ();
|
||||
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
|
||||
xyz.getZ() - m_kart->getXYZ().getZ() );
|
||||
float angle = normalizeAngle(kart_aim_angle - item_angle);
|
||||
float d = (m_kart->getXYZ()-item_to_collect->getXYZ()).length();
|
||||
|
||||
if(fabsf(angle) < 0.3)
|
||||
{
|
||||
*aim_point = item_to_collect->getXYZ();
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(true);
|
||||
m_item_sphere->setPosition(item_to_collect->getXYZ().toIrrVector());
|
||||
#endif
|
||||
if(m_ai_debug)
|
||||
printf("[AI] %s adjusts to hit type %d angle %f.\n",
|
||||
m_kart->getIdent().c_str(),
|
||||
item_to_collect->getType(), angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_ai_debug)
|
||||
printf("[AI] %s won't hit '%d', angle %f.\n",
|
||||
m_kart->getIdent().c_str(),
|
||||
item_to_collect->getType(), angle);
|
||||
}
|
||||
} // kart will not hit item
|
||||
|
||||
} // if item to consider was found
|
||||
|
||||
} // handleItemCollectionAndAvoidance
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function is called when the AI is trying to hit an item that was
|
||||
* previously selected to be collected. The AI only evaluates f it's still
|
||||
* feasible/useful to try to collect this item, or abandon it (and then
|
||||
* look for a new item).
|
||||
* \pre m_item_to_collect is defined
|
||||
* \return True if th AI should still aim for the pre-selected item.
|
||||
*/
|
||||
bool SkiddingAI::handleSelectedItem(float kart_aim_angle,
|
||||
Vec3 *aim_point, int last_node)
|
||||
{
|
||||
// If the item is unavailable or has been switched into a bad item
|
||||
// stop aiming for it.
|
||||
if(m_item_to_collect->getDisableTime()>0 ||
|
||||
m_item_to_collect->getType() == Item::ITEM_BANANA ||
|
||||
m_item_to_collect->getType() == Item::ITEM_BANANA )
|
||||
return false;
|
||||
|
||||
const Vec3 &xyz = m_item_to_collect->getXYZ();
|
||||
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
|
||||
xyz.getZ() - m_kart->getXYZ().getZ());
|
||||
|
||||
float angle = normalizeAngle(kart_aim_angle - item_angle);
|
||||
if(fabsf(angle)>1.5)
|
||||
{
|
||||
// We (likely) have passed the item we were aiming for
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: use ?? float d = (m_kart->getXYZ() - m_item_to_collect->getXYZ()).length();
|
||||
// printf("angle %f distance %f a/d %f\n",
|
||||
// angle, d, angle/d);
|
||||
// angle/d < 0.5 or so?
|
||||
// Keep on aiming for last selected item
|
||||
#ifdef AI_DEBUG
|
||||
m_item_sphere->setVisible(true);
|
||||
m_item_sphere->setPosition(m_item_to_collect->getXYZ().toIrrVector());
|
||||
#endif
|
||||
*aim_point = m_item_to_collect->getXYZ();
|
||||
}
|
||||
return true;
|
||||
} // handleSelectedItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This subroutine decides if the specified item should be collected,
|
||||
* avoided, or ignored (i.e. not interesting). It can use the state of the
|
||||
* kart, e.g. depending on what item is available atm, how much nitro it has,
|
||||
* etc. Though atm it picks the first good item, and tries to avoid.
|
||||
* \param item The item which is considered for picking/avoidance.
|
||||
* \param kart_aim_angle The angle of the line from the kart to the aim point.
|
||||
* If aim_angle==kart_heading then the kart is driving towards the
|
||||
* item.
|
||||
* \param item_to_avoid A pointer to a previously selected item to avoid
|
||||
* (NULL if no item was avoided so far).
|
||||
* \param item_to_collect A pointer to a previously selected item to collect.
|
||||
*/
|
||||
void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
|
||||
const Item **item_to_avoid,
|
||||
const Item **item_to_collect)
|
||||
{
|
||||
// Ignore items that are currently disabled
|
||||
if(item->getDisableTime()>0) return;
|
||||
|
||||
// If the item type is not handled here, ignore it
|
||||
Item::ItemType type = item->getType();
|
||||
if( type!=Item::ITEM_BANANA && type!=Item::ITEM_BONUS_BOX &&
|
||||
type!=Item::ITEM_NITRO_BIG && type!=Item::ITEM_NITRO_SMALL )
|
||||
return;
|
||||
|
||||
bool avoid = false;
|
||||
switch(type)
|
||||
{
|
||||
// Negative items: avoid them
|
||||
case Item::ITEM_BUBBLEGUM: // fallthrough
|
||||
case Item::ITEM_BANANA: avoid = true; break;
|
||||
|
||||
// Positive items: try to collect
|
||||
case Item::ITEM_NITRO_BIG:
|
||||
// Only collect nitro, if it can actually be stored.
|
||||
if(m_kart->getEnergy() +
|
||||
m_kart->getKartProperties()->getNitroBigContainer()
|
||||
> m_kart->getKartProperties()->getNitroMax())
|
||||
return;
|
||||
// fall through: if we have enough space to store a big
|
||||
// container, we can also store a small container, and
|
||||
// finally fall through to the bonus box code.
|
||||
case Item::ITEM_NITRO_SMALL: avoid = false; break;
|
||||
// Only collect nitro, if it can actually be stored.
|
||||
if (m_kart->getEnergy() +
|
||||
m_kart->getKartProperties()->getNitroSmallContainer()
|
||||
> m_kart->getKartProperties()->getNitroMax())
|
||||
return;
|
||||
case Item::ITEM_BONUS_BOX:
|
||||
break;
|
||||
case Item::ITEM_TRIGGER: return; break;
|
||||
|
||||
} // switch
|
||||
|
||||
|
||||
// item_angle The angle of the item (relative to the forward axis,
|
||||
// so 0 means straight ahead in world coordinates!).
|
||||
const Vec3 &xyz = item->getXYZ();
|
||||
float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(),
|
||||
xyz.getZ() - m_kart->getXYZ().getZ());
|
||||
|
||||
float diff = normalizeAngle(kart_aim_angle-item_angle);
|
||||
|
||||
// The kart is driving at high speed, when the current max speed
|
||||
// is higher than the max speed of the kart (which is caused by
|
||||
// any powerups etc)
|
||||
// Otherwise check for skidding. If the kart is still collecting
|
||||
// skid bonus, currentMaxSpeed is not affected yet, but it might
|
||||
// be if the kart would need to turn sharper, therefore stops
|
||||
// skidding, and will get the bonus speed.
|
||||
bool high_speed = (m_kart->getCurrentMaxSpeed() >
|
||||
m_kart->getKartProperties()->getMaxSpeed() ) ||
|
||||
m_kart->getSkidding()->getSkidBonusReady();
|
||||
float max_angle = high_speed
|
||||
? m_ai_properties->m_max_item_angle_high_speed
|
||||
: m_ai_properties->m_max_item_angle;
|
||||
|
||||
if(fabsf(diff) > max_angle)
|
||||
return;
|
||||
|
||||
float steer_direction = normalizeAngle(m_kart->getHeading()
|
||||
- kart_aim_angle );
|
||||
float item_direction = normalizeAngle(m_kart->getHeading()
|
||||
- item_angle );
|
||||
// If we have to steer to the left, and the item is to the right
|
||||
// or vice versa, ignore the item.
|
||||
if(steer_direction * item_direction < 0)
|
||||
return;
|
||||
|
||||
if(avoid)
|
||||
{
|
||||
if(!(*item_to_avoid))
|
||||
*item_to_avoid = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(*item_to_collect))
|
||||
*item_to_collect = item;
|
||||
}
|
||||
} // evaluateItems
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Handle all items depending on the chosen strategy: Either (low level AI)
|
||||
* just use an item after 10 seconds, or do a much better job on higher level
|
||||
@ -996,14 +1291,16 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
|
||||
* a left turn, the kart will aim to the left point (and vice versa for
|
||||
* right turn) - slightly offset by the width of the kart to avoid that
|
||||
* the kart is getting off track.
|
||||
* \return result The new point the kart should aim at when steering.
|
||||
* \param aim_position The point to aim for, i.e. the point that can be
|
||||
* driven to in a straight line.
|
||||
* \param last_node The graph node index in which the aim_position is.
|
||||
*/
|
||||
void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
void SkiddingAI::findNonCrashingPoint2(Vec3 *result, int *last_node)
|
||||
{
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
*last_node = m_next_node_index[m_track_node];
|
||||
const core::vector2df xz = m_kart->getXYZ().toIrrVector2d();
|
||||
|
||||
const Quad &q = QuadGraph::get()->getQuadOfNode(sector);
|
||||
const Quad &q = QuadGraph::get()->getQuadOfNode(*last_node);
|
||||
|
||||
// Index of the left and right end of a quad.
|
||||
const unsigned int LEFT_END_POINT = 0;
|
||||
@ -1031,7 +1328,7 @@ void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
#endif
|
||||
while(1)
|
||||
{
|
||||
unsigned int next_sector = m_next_node_index[sector];
|
||||
unsigned int next_sector = m_next_node_index[*last_node];
|
||||
const Quad &q_next = QuadGraph::get()->getQuadOfNode(next_sector);
|
||||
// Test if the next left point is to the right of the left
|
||||
// line. If so, a new left line is defined.
|
||||
@ -1067,20 +1364,20 @@ void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
#endif
|
||||
right.end = p;
|
||||
}
|
||||
sector = next_sector;
|
||||
*last_node = next_sector;
|
||||
} // while
|
||||
|
||||
// Now look for the next curve to find out to which side of the
|
||||
// track the AI should aim at
|
||||
|
||||
sector = m_track_node;
|
||||
*last_node = m_track_node;
|
||||
int count = 0;
|
||||
while(1)
|
||||
{
|
||||
GraphNode::DirectionType dir;
|
||||
unsigned int last;
|
||||
unsigned int succ = m_successor_index[sector];
|
||||
const GraphNode &gn = QuadGraph::get()->getNode(sector);
|
||||
unsigned int succ = m_successor_index[*last_node];
|
||||
const GraphNode &gn = QuadGraph::get()->getNode(*last_node);
|
||||
gn.getDirectionData(succ, &dir, &last);
|
||||
if(dir==GraphNode::DIR_LEFT)
|
||||
{
|
||||
@ -1106,7 +1403,7 @@ void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
// We are going straight. Determine point to aim for based on the
|
||||
// direction of the track after the straight section
|
||||
|
||||
sector = m_next_node_index[last];
|
||||
*last_node = m_next_node_index[last];
|
||||
count++;
|
||||
if(count>1)
|
||||
printf("That shouldn't happen %d!!!\n", count);
|
||||
@ -1115,7 +1412,7 @@ void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
Vec3 ppp(0.5f*(left.end.X+right.end.X),
|
||||
m_kart->getXYZ().getY(),
|
||||
0.5f*(left.end.Y+right.end.Y));
|
||||
*result = QuadGraph::get()->getQuadOfNode(sector).getCenter();
|
||||
*result = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
|
||||
*result = ppp;
|
||||
} // findNonCrashingPoint2
|
||||
|
||||
@ -1124,8 +1421,11 @@ void SkiddingAI::findNonCrashingPoint2(Vec3 *result)
|
||||
* driven to without crashing with the track, then find towards which of
|
||||
* the two edges of the track is closest to the next curve after wards,
|
||||
* and return the position of that edge.
|
||||
* \param aim_position The point to aim for, i.e. the point that can be
|
||||
* driven to in a straight line.
|
||||
* \param last_node The graph node index in which the aim_position is.
|
||||
*/
|
||||
void SkiddingAI::findNonCrashingPoint(Vec3 *result)
|
||||
void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node)
|
||||
{
|
||||
#ifdef AI_DEBUG_KART_HEADING
|
||||
const Vec3 eps(0,0.5f,0);
|
||||
@ -1134,7 +1434,7 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *result)
|
||||
Vec3 forw(0, 0, 50);
|
||||
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps);
|
||||
#endif
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
*last_node = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
@ -1145,9 +1445,9 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *result)
|
||||
// of iterations in the while loop is less than 7.
|
||||
for(unsigned int i=0; i<100; i++)
|
||||
{
|
||||
//target_sector is the sector at the longest distance that we can drive
|
||||
//to without crashing with the track.
|
||||
target_sector = m_next_node_index[sector];
|
||||
// target_sector is the sector at the longest distance that we can
|
||||
// drive to without crashing with the track.
|
||||
target_sector = m_next_node_index[*last_node];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter()
|
||||
@ -1174,21 +1474,22 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *result)
|
||||
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
|
||||
|
||||
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord,
|
||||
sector );
|
||||
*last_node );
|
||||
|
||||
float distance = fabsf(step_track_coord[0]);
|
||||
|
||||
//If we are outside, the previous sector is what we are looking for
|
||||
//If we are outside, the previous node is what we are looking for
|
||||
if ( distance + m_kart_width * 0.5f
|
||||
> QuadGraph::get()->getNode(sector).getPathWidth() )
|
||||
> QuadGraph::get()->getNode(*last_node).getPathWidth() )
|
||||
{
|
||||
*result = QuadGraph::get()->getQuadOfNode(sector).getCenter();
|
||||
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node)
|
||||
.getCenter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
sector = target_sector;
|
||||
*last_node = target_sector;
|
||||
} // for i<100
|
||||
*result = QuadGraph::get()->getQuadOfNode(sector).getCenter();
|
||||
*aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter();
|
||||
} // findNonCrashingPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1438,7 +1739,6 @@ bool SkiddingAI::doSkid(float steer_fraction)
|
||||
void SkiddingAI::setSteering(float angle, float dt)
|
||||
{
|
||||
float steer_fraction = angle / m_kart->getMaxSteerAngle();
|
||||
|
||||
m_controls->m_skid = doSkid(steer_fraction);
|
||||
|
||||
// Adjust steer fraction in case to be in [-1,1]
|
||||
@ -1493,7 +1793,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
float old_steer = m_controls->m_steer;
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_kart->getKartProperties()->getTimeFullSteerAI();
|
||||
float max_steer_change = dt/m_ai_properties->m_time_full_steer;
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
|
@ -45,6 +45,12 @@ class SkiddingAI : public AIBaseController
|
||||
private:
|
||||
/** How the AI uses nitro. */
|
||||
enum {NITRO_NONE, NITRO_SOME, NITRO_ALL} m_nitro_level;
|
||||
|
||||
/** Determines if the AI should prefer collecting items over avoiding
|
||||
* items, or avoiding over collecting. */
|
||||
enum {ITEM_COLLECT_NONE, ITEM_COLLECT_PRIORITY, ITEM_AVOID_PRIORITY}
|
||||
m_item_behaviour;
|
||||
|
||||
enum ItemTactic
|
||||
{
|
||||
IT_TEN_SECONDS, //Fire after 10 seconds have passed, since the item
|
||||
@ -135,11 +141,20 @@ private:
|
||||
#ifdef DEBUG
|
||||
/** For skidding debugging: shows the estimated turn shape. */
|
||||
ShowCurve **m_curve;
|
||||
#endif
|
||||
|
||||
/** If set an item that the AI should aim for. */
|
||||
const Item *m_item_to_collect;
|
||||
|
||||
/** For debugging purpose: a sphere indicating where the AI
|
||||
* is targeting at. */
|
||||
irr::scene::ISceneNode *m_debug_sphere;
|
||||
|
||||
/** For item debugging: set to the item that is selected to
|
||||
* be collected. */
|
||||
irr::scene::ISceneNode *m_item_sphere;
|
||||
#endif
|
||||
|
||||
|
||||
/*Functions called directly from update(). They all represent an action
|
||||
*that can be done, and end up setting their respective m_controls
|
||||
*variable, except handle_race_start() that isn't associated with any
|
||||
@ -153,10 +168,17 @@ private:
|
||||
void handleBraking();
|
||||
void handleNitroAndZipper();
|
||||
void computeNearestKarts();
|
||||
void handleItemCollectionAndAvoidance(Vec3 *aim_point,
|
||||
int last_node);
|
||||
bool handleSelectedItem(float kart_aim_angle, Vec3 *aim_point,
|
||||
int last_node);
|
||||
void evaluateItems(const Item *item, float kart_aim_angle,
|
||||
const Item **item_to_avoid,
|
||||
const Item **item_to_collect);
|
||||
|
||||
void checkCrashes(const Vec3& pos);
|
||||
void findNonCrashingPoint(Vec3 *result);
|
||||
void findNonCrashingPoint2(Vec3 *result);
|
||||
void findNonCrashingPoint(Vec3 *result, int *last_node);
|
||||
void findNonCrashingPoint2(Vec3 *result, int *last_node);
|
||||
|
||||
void determineTrackDirection();
|
||||
void determineTurnRadius(const Vec3 &start,
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "modes/world.hpp"
|
||||
@ -108,11 +109,13 @@ KartProperties::KartProperties(const std::string &filename)
|
||||
if (filename != "")
|
||||
{
|
||||
m_skidding_properties = NULL;
|
||||
m_ai_properties = NULL;
|
||||
load(filename, "kart");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_skidding_properties = new SkiddingProperties();
|
||||
m_ai_properties = new AIProperties();
|
||||
}
|
||||
} // KartProperties
|
||||
|
||||
@ -123,6 +126,8 @@ KartProperties::~KartProperties()
|
||||
delete m_kart_model;
|
||||
if(m_skidding_properties)
|
||||
delete m_skidding_properties;
|
||||
if(m_ai_properties)
|
||||
delete m_ai_properties;
|
||||
} // ~KartProperties
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -140,7 +145,10 @@ void KartProperties::copyFrom(const KartProperties *source)
|
||||
// So all pointer variables need to be separately allocated and assigned.
|
||||
m_skidding_properties = new SkiddingProperties();
|
||||
assert(m_skidding_properties);
|
||||
m_ai_properties = new AIProperties();
|
||||
assert(m_ai_properties);
|
||||
*m_skidding_properties = *source->m_skidding_properties;
|
||||
*m_ai_properties = *source->m_ai_properties;
|
||||
} // copyFrom
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -318,6 +326,11 @@ void KartProperties::getAllData(const XMLNode * root)
|
||||
m_skidding_properties->load(skid_node);
|
||||
}
|
||||
|
||||
if(const XMLNode *ai_node = root->getNode("ai"))
|
||||
{
|
||||
m_ai_properties->load(ai_node);
|
||||
}
|
||||
|
||||
if(const XMLNode *slipstream_node = root->getNode("slipstream"))
|
||||
{
|
||||
slipstream_node->get("length", &m_slipstream_length );
|
||||
@ -334,7 +347,6 @@ void KartProperties::getAllData(const XMLNode * root)
|
||||
if(const XMLNode *turn_node = root->getNode("turn"))
|
||||
{
|
||||
turn_node->get("time-full-steer", &m_time_full_steer );
|
||||
turn_node->get("time-full-steer-ai", &m_time_full_steer_ai );
|
||||
turn_node->get("turn-speed", &m_turn_speed );
|
||||
turn_node->get("turn-radius", &m_turn_radius_at_speed);
|
||||
// For now store the turn radius in turn angle, the correct
|
||||
@ -593,7 +605,6 @@ void KartProperties::checkAllSet(const std::string &filename)
|
||||
|
||||
CHECK_NEG(m_mass, "mass" );
|
||||
CHECK_NEG(m_time_full_steer, "turn time-full-steer" );
|
||||
CHECK_NEG(m_time_full_steer_ai, "turn time-full-steer-ai" );
|
||||
CHECK_NEG(m_wheel_damping_relaxation, "wheels damping-relaxation" );
|
||||
CHECK_NEG(m_wheel_damping_compression, "wheels damping-compression" );
|
||||
CHECK_NEG(m_wheel_radius, "wheels radius" );
|
||||
@ -671,6 +682,7 @@ void KartProperties::checkAllSet(const std::string &filename)
|
||||
CHECK_NEG(m_explosion_radius, "explosion radius" );
|
||||
|
||||
m_skidding_properties->checkAllSet(filename);
|
||||
m_ai_properties->checkAllSet(filename);
|
||||
} // checkAllSet
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -36,6 +36,7 @@ using namespace irr;
|
||||
#include "race/race_manager.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class Material;
|
||||
class SkiddingProperties;
|
||||
class XMLNode;
|
||||
@ -61,6 +62,11 @@ private:
|
||||
* any skidding property. */
|
||||
SkiddingProperties *m_skidding_properties;
|
||||
|
||||
/** AI Properties for this kart, as a separate object in order to
|
||||
* reduce dependencies (and therefore compile time) when changing
|
||||
* any AI property. */
|
||||
AIProperties *m_ai_properties;
|
||||
|
||||
/** The absolute path of the icon texture to use. */
|
||||
Material *m_icon_material;
|
||||
|
||||
@ -118,9 +124,6 @@ private:
|
||||
* braking force. */
|
||||
float m_time_full_steer; /**< Time for player karts to reach full
|
||||
* steer angle. */
|
||||
float m_time_full_steer_ai; /**< Time for AI karts to reach full
|
||||
* steer angle (used to reduce shaking
|
||||
* of karts). */
|
||||
/** Stores the speeds at which the turn angle changes. */
|
||||
std::vector<float> m_turn_speed;
|
||||
|
||||
@ -397,11 +400,6 @@ public:
|
||||
* steering straight. */
|
||||
float getTimeFullSteer () const {return m_time_full_steer; }
|
||||
|
||||
/** Returns how long the AI should need to steer in a direction. This
|
||||
* avoids that the AI has an advantage by being able to change steering
|
||||
* to quickly (e.g. counteracting pushes). */
|
||||
float getTimeFullSteerAI () const {return m_time_full_steer_ai; }
|
||||
|
||||
/** Get braking information. */
|
||||
float getBrakeFactor () const {return m_brake_factor; }
|
||||
|
||||
@ -620,6 +618,9 @@ public:
|
||||
const SkiddingProperties *getSkiddingProperties() const
|
||||
{ return m_skidding_properties; }
|
||||
|
||||
/** Returns a pointer to the AI properties. */
|
||||
const AIProperties *getAIProperties() const { return m_ai_properties; }
|
||||
|
||||
/** Returns ratio of current speed to max speed at which the gear will
|
||||
* change (for our simualated gears = simple change of engine power). */
|
||||
const std::vector<float>&
|
||||
|
@ -62,11 +62,12 @@ Skidding::~Skidding()
|
||||
*/
|
||||
void Skidding::reset()
|
||||
{
|
||||
m_skid_time = 0.0f;
|
||||
m_skid_state = m_skid_visual_time<=0 ? SKID_OLD : SKID_NONE;
|
||||
m_skid_factor = 1.0f;
|
||||
m_real_steering = 0.0f;
|
||||
m_visual_rotation = 0.0f;
|
||||
m_skid_time = 0.0f;
|
||||
m_skid_state = m_skid_visual_time<=0 ? SKID_OLD : SKID_NONE;
|
||||
m_skid_factor = 1.0f;
|
||||
m_real_steering = 0.0f;
|
||||
m_visual_rotation = 0.0f;
|
||||
m_skid_bonus_ready = false;
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -166,6 +167,7 @@ float Skidding::getSteeringWhenSkidding(float steering) const
|
||||
void Skidding::update(float dt, bool is_on_ground,
|
||||
float steering, bool skidding)
|
||||
{
|
||||
m_skid_bonus_ready = false;
|
||||
if (is_on_ground)
|
||||
{
|
||||
if((fabs(steering) > 0.001f) && skidding)
|
||||
@ -306,7 +308,11 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
unsigned int level = getSkidBonus(&bonus_time, &bonus_speed,
|
||||
&bonus_force);
|
||||
// If at least level 1 bonus is reached, show appropriate gfx
|
||||
if(level>0) m_kart->getKartGFX()->setSkidLevel(level);
|
||||
if(level>0)
|
||||
{
|
||||
m_skid_bonus_ready = true;
|
||||
m_kart->getKartGFX()->setSkidLevel(level);
|
||||
}
|
||||
// If player stops skidding, trigger bonus, and change state to
|
||||
// SKID_SHOW_GFX_*
|
||||
if(!skidding)
|
||||
|
@ -57,6 +57,10 @@ private:
|
||||
* trigger the skidding bonus. */
|
||||
float m_skid_time;
|
||||
|
||||
/** True if the kart has skidded long enough to get a skid bonus if it
|
||||
* stopped skidding now. */
|
||||
bool m_skid_bonus_ready;
|
||||
|
||||
public:
|
||||
/** SKID_OLD: old skidding, will be removed. */
|
||||
/** SKID_NONE: Kart is currently not skidding.
|
||||
@ -114,6 +118,12 @@ protected:
|
||||
SkidState getSkidState() const { return m_skid_state; }
|
||||
// ------------------------------------------------------------------------
|
||||
float getSteeringWhenSkidding(float steering) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the kart has skidded long enough to get a skid bonus if it
|
||||
* stopped skidding now. This function returns false if the kart is
|
||||
* actually using the skid bonus. */
|
||||
bool getSkidBonusReady() const { return m_skid_bonus_ready; }
|
||||
|
||||
}; // Skidding
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user