Big code refactoring: instead of having auto_kart, player_kart, the karts
now use a 'controller' object which is responsible for its steering, e.g. a default_ai_controller, player_controller etc. This makes it easier to switch a player kart to use a end-of-race computer controller to drive the kart once the race is finished (though that's not implemented yet). I expect some bugs with restarting race, and perhaps end of race behaviour at this stage. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4714 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -151,6 +151,17 @@ supertuxkart_SOURCES = \
|
||||
items/rubber_band.cpp \
|
||||
items/rubber_band.hpp \
|
||||
karts/auto_kart.hpp \
|
||||
karts/controller/controller.cpp \
|
||||
karts/controller/controller.hpp \
|
||||
karts/controller/default_ai_controller.cpp \
|
||||
karts/controller/default_ai_controller.hpp \
|
||||
karts/controller/end_controller.cpp \
|
||||
karts/controller/end_controller.hpp \
|
||||
karts/controller/kart_control.hpp \
|
||||
karts/controller/new_ai_controller.cpp \
|
||||
karts/controller/new_ai_controller.hpp \
|
||||
karts/controller/player_controller.cpp \
|
||||
karts/controller/player_controller.hpp \
|
||||
karts/kart.cpp \
|
||||
karts/kart.hpp \
|
||||
karts/kart_control.hpp \
|
||||
@@ -248,10 +259,6 @@ supertuxkart_SOURCES = \
|
||||
replay/replay_player.hpp \
|
||||
replay/replay_recorder.cpp \
|
||||
replay/replay_recorder.hpp \
|
||||
robots/default_robot.cpp \
|
||||
robots/default_robot.hpp \
|
||||
robots/new_ai.cpp \
|
||||
robots/new_ai.hpp \
|
||||
states_screens/challenges.cpp \
|
||||
states_screens/challenges.hpp \
|
||||
states_screens/credits.cpp \
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "lisp/lisp.hpp"
|
||||
#include "lisp/parser.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
@@ -269,7 +268,7 @@ bool ChallengeData::raceFinished()
|
||||
if(track_name!=m_track_name ) return false; // wrong track
|
||||
if((int)world->getNumKarts()<m_num_karts ) return false; // not enough AI karts
|
||||
|
||||
PlayerKart* kart = world->getPlayerKart(0);
|
||||
Kart* kart = world->getPlayerKart(0);
|
||||
if(m_energy>0 && kart->getEnergy() <m_energy ) return false; // not enough energy
|
||||
if(m_position>0 && kart->getPosition()>m_position) return false; // too far behind
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
#include "config/player.hpp"
|
||||
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
|
||||
ActivePlayer::ActivePlayer(PlayerProfile* player, InputDevice *device)
|
||||
@@ -47,20 +47,3 @@ void ActivePlayer::setDevice(InputDevice* device)
|
||||
if (device != NULL) device->setPlayer(this);
|
||||
} // setDevice
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
PlayerKart* ActivePlayer::getKart()
|
||||
{
|
||||
World *world = World::getWorld();
|
||||
const int num_karts = world->getNumKarts();
|
||||
for (int p=0; p<num_karts; p++)
|
||||
{
|
||||
Kart *kart = world->getKart(p);
|
||||
if(kart->isPlayerKart() && ((PlayerKart*)kart)->getPlayer() == this)
|
||||
{
|
||||
return (PlayerKart*)kart;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "ActivePlayer::getKart() failed to find player named " << m_player->getName() << std::endl;
|
||||
return NULL;
|
||||
} // getKart
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "input/input_device.hpp"
|
||||
|
||||
class InputDevice;
|
||||
class PlayerKart;
|
||||
class Kart;
|
||||
|
||||
/**
|
||||
* class for managing player profiles (name, control configuration, etc.)
|
||||
@@ -36,13 +36,11 @@ class PlayerProfile
|
||||
{
|
||||
private:
|
||||
|
||||
// for saving to config file
|
||||
/** For saving to config file. */
|
||||
GroupUserConfigParam m_player_group;
|
||||
|
||||
StringUserConfigParam m_name;
|
||||
|
||||
// int m_last_kart_id;
|
||||
|
||||
public:
|
||||
|
||||
PlayerProfile(const char* name) : m_player_group("Player", "Represents one human player"),
|
||||
@@ -66,8 +64,11 @@ public:
|
||||
*/
|
||||
class ActivePlayer
|
||||
{
|
||||
PlayerProfile* m_player;
|
||||
InputDevice* m_device;
|
||||
PlayerProfile *m_player;
|
||||
InputDevice *m_device;
|
||||
|
||||
/** Pointer to the kart of this player, only valid during the game. */
|
||||
Kart *m_kart;
|
||||
public:
|
||||
/** ID of this player within the list of active players */
|
||||
int m_id;
|
||||
@@ -80,8 +81,10 @@ public:
|
||||
|
||||
InputDevice* getDevice() const;
|
||||
void setDevice(InputDevice* device);
|
||||
|
||||
PlayerKart* getKart();
|
||||
/** Sets the kart for this player. */
|
||||
void setKart(Kart *kart) { m_kart = kart; }
|
||||
/** Returns the kart of this player. Only valid while world exists. */
|
||||
Kart* getKart() { return m_kart; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "audio/sound_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#include "items/attachment_manager.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "main_loop.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/dialogs/confirm_resolution_dialog.hpp"
|
||||
@@ -860,7 +859,7 @@ void IrrDriver::update(float dt)
|
||||
Kart *kart=world->getKart(i);
|
||||
if(kart->getCamera())
|
||||
{
|
||||
kart->activateCamera();
|
||||
kart->getCamera()->activate();
|
||||
m_scene_manager->drawAll();
|
||||
} // if kart->Camera
|
||||
} // for i<world->getNumKarts()
|
||||
|
||||
@@ -142,7 +142,7 @@ void SkidMarks::update(float dt)
|
||||
|
||||
// not turning enough, don't draw skidmarks if kart is going straight ahead
|
||||
// this is even stricter for Ai karts, since they tend to use LOTS of skidding
|
||||
const float min_skid_angle = m_kart.isPlayerKart() ? 0.55f : 0.95f;
|
||||
const float min_skid_angle = m_kart.getController()->isPlayerController() ? 0.55f : 0.95f;
|
||||
if( fabsf(m_kart.getSteerPercent()) < min_skid_angle) return;
|
||||
|
||||
// Start new skid marks
|
||||
|
||||
@@ -481,18 +481,6 @@
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="robots"
|
||||
>
|
||||
<File
|
||||
RelativePath="../../../src\robots\default_robot.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\robots\new_ai.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="challenges"
|
||||
>
|
||||
@@ -688,10 +676,30 @@
|
||||
RelativePath="..\..\karts\moveable.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\player_kart.cpp"
|
||||
<Filter
|
||||
Name="controller"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\controller.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\default_ai_controller.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\end_controller.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\new_ai_controller.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\player_controller.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="graphics"
|
||||
@@ -1063,6 +1071,10 @@
|
||||
RelativePath="..\..\states_screens\dialogs\enter_player_name_dialog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\states_screens\dialogs\gp_info_dialog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\states_screens\dialogs\player_info_dialog.cpp"
|
||||
>
|
||||
@@ -1199,18 +1211,6 @@
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="robots"
|
||||
>
|
||||
<File
|
||||
RelativePath="../../../src\robots\default_robot.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\robots\new_ai.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="challenges"
|
||||
>
|
||||
@@ -1522,10 +1522,30 @@
|
||||
RelativePath="..\..\karts\moveable.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\player_kart.hpp"
|
||||
<Filter
|
||||
Name="controller"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\controller.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\default_ai_controller.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\end_controller.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\new_ai_controller.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\karts\controller\player_controller.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="graphics"
|
||||
@@ -1861,6 +1881,10 @@
|
||||
RelativePath="..\..\states_screens\dialogs\enter_player_name_dialog.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\states_screens\dialogs\gp_info_dialog.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\states_screens\dialogs\player_info_dialog.hpp"
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "guiengine/abstract_state_manager.hpp"
|
||||
#include "input/input.hpp"
|
||||
#include "input/input_device.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
@@ -80,6 +80,7 @@ GamePadDevice::GamePadDevice(const int irrIndex, const std::string name, const i
|
||||
for(int n=0; n<SEvent::SJoystickEvent::NUMBER_OF_BUTTONS; n++)
|
||||
m_buttonPressed[n] = false;
|
||||
} // GamePadDevice
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool GamePadDevice::isButtonPressed(const int i)
|
||||
@@ -92,12 +93,14 @@ void GamePadDevice::setButtonPressed(const int i, bool isButtonPressed)
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void GamePadDevice::resetAxisDirection(const int axis, Input::AxisDirection direction, ActivePlayer* player)
|
||||
void GamePadDevice::resetAxisDirection(const int axis,
|
||||
Input::AxisDirection direction,
|
||||
ActivePlayer* player)
|
||||
{
|
||||
KeyBinding bind;
|
||||
if (StateManager::get()->getGameState() != GUIEngine::GAME) return; // ignore this while in menus
|
||||
|
||||
PlayerKart* pk = player->getKart();
|
||||
Kart* pk = player->getKart();
|
||||
if (pk == NULL)
|
||||
{
|
||||
std::cerr << "Error, trying to reset axis for an unknown player\n";
|
||||
@@ -109,7 +112,7 @@ void GamePadDevice::resetAxisDirection(const int axis, Input::AxisDirection dire
|
||||
bind = m_configuration->getBinding(n);
|
||||
if(bind.id == axis && bind.dir == direction)
|
||||
{
|
||||
pk->action((PlayerAction)n, 0);
|
||||
((PlayerController*)(pk->getController()))->action((PlayerAction)n, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
#include "input/input.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@@ -368,7 +368,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int btnID,
|
||||
if (StateManager::get()->getGameState() == GUIEngine::GAME && !GUIEngine::ModalDialog::isADialogActive())
|
||||
{
|
||||
// Find the corresponding PlayerKart from our ActivePlayer instance
|
||||
PlayerKart* pk;
|
||||
Kart* pk;
|
||||
|
||||
if (player == NULL)
|
||||
{
|
||||
@@ -384,7 +384,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int btnID,
|
||||
return;
|
||||
}
|
||||
|
||||
pk->action(action, abs(value));
|
||||
((PlayerController*)pk->getController())->action(action, abs(value));
|
||||
}
|
||||
// ... when in menus
|
||||
else
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "graphics/camera.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/bowling.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
|
||||
float Bowling::m_st_max_distance; // maximum distance for a bowling ball to be attracted
|
||||
float Bowling::m_st_max_distance_squared;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/rubber_band.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "physics/physical_object.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
@@ -178,7 +178,7 @@ void Powerup::use()
|
||||
// or the kart "throwing" the anvil? Ideally it should be both.
|
||||
// Meanwhile, don't play it near AI karts since they obviously
|
||||
// don't hear anything
|
||||
if(kart->isPlayerKart())
|
||||
if(kart->getController()->isPlayerController())
|
||||
m_sound_use->position(kart->getXYZ());
|
||||
else
|
||||
m_sound_use->position(m_owner->getXYZ());
|
||||
@@ -204,7 +204,7 @@ void Powerup::use()
|
||||
{
|
||||
kart->attach(ATTACH_PARACHUTE, stk_config->m_parachute_time_other);
|
||||
|
||||
if(kart->isPlayerKart())
|
||||
if(kart->getController()->isPlayerController())
|
||||
player_kart = kart;
|
||||
}
|
||||
}
|
||||
@@ -213,7 +213,7 @@ void Powerup::use()
|
||||
// or the kart "throwing" the anvil? Ideally it should be both.
|
||||
// Meanwhile, don't play it near AI karts since they obviously
|
||||
// don't hear anything
|
||||
if(m_owner->isPlayerKart())
|
||||
if(m_owner->getController()->isPlayerController())
|
||||
m_sound_use->position(m_owner->getXYZ());
|
||||
else if(player_kart)
|
||||
m_sound_use->position(player_kart->getXYZ());
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
class AutoKart : public Kart
|
||||
{
|
||||
public:
|
||||
AutoKart(const std::string& kart_name, int position,
|
||||
AutoKart(const std::string& ident, int position,
|
||||
const btTransform& init_pos) :
|
||||
Kart(kart_name, position, init_pos) {}
|
||||
Kart(ident, position, init_pos) {}
|
||||
|
||||
bool isPlayerKart() const {return false;}
|
||||
}; // AutoKart
|
||||
|
||||
43
src/karts/controller/controller.cpp
Normal file
43
src/karts/controller/controller.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
|
||||
//The AI debugging works best with just 1 AI kart, so set the number of karts
|
||||
//to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
|
||||
|
||||
#include "karts/controller/controller.hpp"
|
||||
|
||||
#include "karts/kart.hpp"
|
||||
|
||||
/** Constructor, saves the kart pointer and a pointer to the KartControl
|
||||
* of the kart.
|
||||
*/
|
||||
Controller::Controller(Kart *kart)
|
||||
{
|
||||
m_controls = &(kart->getControls());
|
||||
m_kart = kart;
|
||||
} // Controller
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const irr::core::stringw& Controller::getNamePostfix() const
|
||||
{
|
||||
// Static to avoid returning the address of a temporary stringq
|
||||
static irr::core::stringw name("");
|
||||
return name;
|
||||
} // getNamePostfix
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
60
src/karts/controller/controller.hpp
Normal file
60
src/karts/controller/controller.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2010 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_CONTROLLER_HPP
|
||||
#define HEADER_CONTROLLER_HPP
|
||||
|
||||
#include "irrlicht.h"
|
||||
using namespace irr;
|
||||
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
|
||||
class Kart;
|
||||
class Item;
|
||||
|
||||
/** This is the base class for kart controller - that can be a player
|
||||
* or a a robot.
|
||||
*/
|
||||
class Controller
|
||||
{
|
||||
protected:
|
||||
/** Pointer to the kart that is controlled by this controller. */
|
||||
Kart *m_kart;
|
||||
|
||||
/** A pointer to the main controller, from which the kart takes
|
||||
* it commands. */
|
||||
KartControl *m_controls;
|
||||
|
||||
public:
|
||||
Controller (Kart *kart);
|
||||
~Controller () {};
|
||||
virtual void reset () {};
|
||||
virtual void update (float dt) {};
|
||||
virtual void handleZipper () {};
|
||||
virtual void collectedItem (const Item &item, int add_info=-1,
|
||||
float previous_energy=0) {};
|
||||
virtual void crashed () {};
|
||||
virtual void setPosition (int p) {};
|
||||
virtual void finishedRace (float time) {};
|
||||
virtual bool isPlayerController () const {return false;}
|
||||
virtual bool isNetworkController() const {return false;}
|
||||
virtual const irr::core::stringw& getNamePostfix() const;
|
||||
}; // Controller
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -22,7 +22,7 @@
|
||||
//to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
|
||||
#undef AI_DEBUG
|
||||
|
||||
#include "robots/default_robot.hpp"
|
||||
#include "karts/controller/default_ai_controller.hpp"
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
# include "irrlicht.h"
|
||||
@@ -37,7 +37,6 @@
|
||||
#ifdef AI_DEBUG
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#endif
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@@ -45,13 +44,11 @@
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
DefaultRobot::DefaultRobot(const std::string& kart_name,
|
||||
int position, const btTransform& init_pos,
|
||||
const Track *track) :
|
||||
AutoKart( kart_name, position, init_pos )
|
||||
DefaultAIController::DefaultAIController(Kart *kart) : Controller(kart)
|
||||
{
|
||||
m_kart_length = m_kart_properties->getKartModel()->getLength();
|
||||
m_kart_width = m_kart_properties->getKartModel()->getWidth();
|
||||
m_kart = kart;
|
||||
m_kart_length = m_kart->getKartProperties()->getKartModel()->getLength();
|
||||
m_kart_width = m_kart->getKartProperties()->getKartModel()->getWidth();
|
||||
m_world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
m_quad_graph = &m_track->getQuadGraph();
|
||||
@@ -153,33 +150,41 @@ DefaultRobot::DefaultRobot(const std::string& kart_name,
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1);
|
||||
#endif
|
||||
} // DefaultRobot
|
||||
} // DefaultAIController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The destructor deletes the shared TrackInfo objects if no more DefaultRobot
|
||||
/** The destructor deletes the shared TrackInfo objects if no more DefaultAIController
|
||||
* instances are around.
|
||||
*/
|
||||
DefaultRobot::~DefaultRobot()
|
||||
DefaultAIController::~DefaultAIController()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
#endif
|
||||
} // ~DefaultRobot
|
||||
} // ~DefaultAIController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const irr::core::stringw& DefaultAIController::getNamePostfix() const
|
||||
{
|
||||
// Static to avoid returning the address of a temporary stringq
|
||||
static irr::core::stringw name="(default)";
|
||||
return name;
|
||||
} // getNamePostfix
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//TODO: if the AI is crashing constantly, make it move backwards in a straight
|
||||
//line, then move forward while turning.
|
||||
void DefaultRobot::update(float dt)
|
||||
void DefaultAIController::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls.m_look_back = false;
|
||||
m_controls.m_nitro = false;
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
|
||||
// Update the current node:
|
||||
if(m_track_node!=QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
int old_node = m_track_node;
|
||||
m_quad_graph->findRoadSector(getXYZ(), &m_track_node,
|
||||
m_quad_graph->findRoadSector(m_kart->getXYZ(), &m_track_node,
|
||||
&m_all_look_aheads[m_track_node]);
|
||||
// IF the AI is off track (or on a branch of the track it did not
|
||||
// select to be on), keep the old position.
|
||||
@@ -189,19 +194,19 @@ void DefaultRobot::update(float dt)
|
||||
}
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(getXYZ());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
// The client does not do any AI computations.
|
||||
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
|
||||
{
|
||||
AutoKart::update(dt);
|
||||
Controller::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_world->isStartPhase() )
|
||||
{
|
||||
handleRaceStart();
|
||||
AutoKart::update(dt);
|
||||
Controller::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -212,18 +217,18 @@ void DefaultRobot::update(float dt)
|
||||
steps = calcSteps();
|
||||
|
||||
computeNearestKarts();
|
||||
checkCrashes( steps, getXYZ() );
|
||||
checkCrashes( steps, m_kart->getXYZ() );
|
||||
findCurve();
|
||||
|
||||
// Special behaviour if we have a bomb attach: try to hit the kart ahead
|
||||
// of us.
|
||||
bool commands_set = false;
|
||||
if(m_handle_bomb && getAttachment()->getType()==ATTACH_BOMB &&
|
||||
if(m_handle_bomb && m_kart->getAttachment()->getType()==ATTACH_BOMB &&
|
||||
m_kart_ahead )
|
||||
{
|
||||
// Use nitro if the kart is far ahead, or faster than this kart
|
||||
m_controls.m_nitro = m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > getSpeed();
|
||||
m_controls->m_nitro = m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > m_kart->getSpeed();
|
||||
// If we are close enough, try to hit this kart
|
||||
if(m_distance_ahead<=10)
|
||||
{
|
||||
@@ -231,10 +236,10 @@ void DefaultRobot::update(float dt)
|
||||
|
||||
// If we are faster, try to predict the point where we will hit
|
||||
// the other kart
|
||||
if(m_kart_ahead->getSpeed() < getSpeed())
|
||||
if(m_kart_ahead->getSpeed() < m_kart->getSpeed())
|
||||
{
|
||||
float time_till_hit = m_distance_ahead
|
||||
/ (getSpeed()-m_kart_ahead->getSpeed());
|
||||
/ (m_kart->getSpeed()-m_kart_ahead->getSpeed());
|
||||
target += m_kart_ahead->getVelocity()*time_till_hit;
|
||||
}
|
||||
float steer_angle = steerToPoint(m_kart_ahead->getXYZ(),
|
||||
@@ -253,13 +258,13 @@ void DefaultRobot::update(float dt)
|
||||
handleRescue(dt);
|
||||
handleBraking();
|
||||
// If a bomb is attached, nitro might already be set.
|
||||
if(!m_controls.m_nitro)
|
||||
if(!m_controls->m_nitro)
|
||||
handleNitroAndZipper();
|
||||
}
|
||||
// If we are supposed to use nitro, but have a zipper,
|
||||
// use the zipper instead
|
||||
if(m_controls.m_nitro && m_powerup.getType()==POWERUP_ZIPPER &&
|
||||
getSpeed()>1.0f && m_zipper_time_left<=0)
|
||||
if(m_controls->m_nitro && m_kart->getPowerup()->getType()==POWERUP_ZIPPER &&
|
||||
m_kart->getSpeed()>1.0f && m_kart->getZipperTimeLeft()<=0)
|
||||
{
|
||||
// Make sure that not all AI karts use the zipper at the same
|
||||
// time in time trial at start up, so during the first 5 seconds
|
||||
@@ -267,26 +272,26 @@ void DefaultRobot::update(float dt)
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
(m_world->getTime()<3.0f && rand()%50==1) )
|
||||
{
|
||||
m_controls.m_nitro = false;
|
||||
m_controls.m_fire = true;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->m_fire = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*And obviously general kart stuff*/
|
||||
AutoKart::update(dt);
|
||||
Controller::update(dt);
|
||||
m_collided = false;
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handleBraking()
|
||||
void DefaultAIController::handleBraking()
|
||||
{
|
||||
// In follow the leader mode, the kart should brake if they are ahead of
|
||||
// the leader (and not the leader, i.e. don't have initial position 1)
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
getPosition() < m_world->getKart(0)->getPosition() &&
|
||||
getInitialPosition()>1 )
|
||||
m_kart->getPosition() < m_world->getKart(0)->getPosition() &&
|
||||
m_kart->getInitialPosition()>1 )
|
||||
{
|
||||
m_controls.m_brake = true;
|
||||
m_controls->m_brake = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -294,13 +299,13 @@ void DefaultRobot::handleBraking()
|
||||
//We may brake if we are about to get out of the road, but only if the
|
||||
//kart is on top of the road, and if we won't slow down below a certain
|
||||
//limit.
|
||||
if (m_crashes.m_road && getVelocityLC().getY() > MIN_SPEED &&
|
||||
m_world->isOnRoad(getWorldKartId()) )
|
||||
if (m_crashes.m_road && m_kart->getVelocityLC().getY() > MIN_SPEED &&
|
||||
m_world->isOnRoad(m_kart->getWorldKartId()) )
|
||||
{
|
||||
float kart_ang_diff =
|
||||
m_quad_graph->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node])
|
||||
- getHPR().getHeading();
|
||||
- m_kart->getHPR().getHeading();
|
||||
kart_ang_diff = normalizeAngle(kart_ang_diff);
|
||||
kart_ang_diff = fabsf(kart_ang_diff);
|
||||
|
||||
@@ -314,21 +319,21 @@ void DefaultRobot::handleBraking()
|
||||
//if the curve angle is bigger than what the kart can steer, brake
|
||||
//even if we are in the inside, because the kart would be 'thrown'
|
||||
//out of the curve.
|
||||
if(!(m_world->getDistanceToCenterForKart(getWorldKartId())
|
||||
if(!(m_world->getDistanceToCenterForKart(m_kart->getWorldKartId())
|
||||
> m_quad_graph->getNode(m_track_node).getPathWidth() *
|
||||
-CURVE_INSIDE_PERC || m_curve_angle > RAD_TO_DEGREE*getMaxSteerAngle()))
|
||||
-CURVE_INSIDE_PERC || m_curve_angle > RAD_TO_DEGREE*m_kart->getMaxSteerAngle()))
|
||||
{
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_brake = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if( m_curve_angle < -MIN_TRACK_ANGLE ) //Next curve is right
|
||||
{
|
||||
if(!(m_world->getDistanceToCenterForKart( getWorldKartId() )
|
||||
if(!(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )
|
||||
< m_quad_graph->getNode(m_track_node).getPathWidth() *
|
||||
CURVE_INSIDE_PERC || m_curve_angle < -RAD_TO_DEGREE*getMaxSteerAngle()))
|
||||
CURVE_INSIDE_PERC || m_curve_angle < -RAD_TO_DEGREE*m_kart->getMaxSteerAngle()))
|
||||
{
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_brake = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -336,23 +341,23 @@ void DefaultRobot::handleBraking()
|
||||
//Brake if the kart's speed is bigger than the speed we need
|
||||
//to go through the curve at the widest angle, or if the kart
|
||||
//is not going straight in relation to the road.
|
||||
if(getVelocityLC().getY() > m_curve_target_speed ||
|
||||
if(m_kart->getVelocityLC().getY() > m_curve_target_speed ||
|
||||
kart_ang_diff > MIN_TRACK_ANGLE )
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
std::cout << "BRAKING" << std::endl;
|
||||
#endif
|
||||
m_controls.m_brake = true;
|
||||
m_controls->m_brake = true;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_brake = false;
|
||||
} // handleBraking
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handleSteering(float dt)
|
||||
void DefaultAIController::handleSteering(float dt)
|
||||
{
|
||||
const int next = m_next_node_index[m_track_node];
|
||||
|
||||
@@ -362,7 +367,7 @@ void DefaultRobot::handleSteering(float dt)
|
||||
*finite state machine.
|
||||
*/
|
||||
//Reaction to being outside of the road
|
||||
if( fabsf(m_world->getDistanceToCenterForKart( getWorldKartId() )) >
|
||||
if( fabsf(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )) >
|
||||
0.5f* m_quad_graph->getNode(m_track_node).getPathWidth()+0.5f )
|
||||
{
|
||||
steer_angle = steerToPoint(m_quad_graph->getQuad(next).getCenter(),
|
||||
@@ -391,7 +396,7 @@ void DefaultRobot::handleSteering(float dt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_world->getDistanceToCenterForKart( getWorldKartId() ) >
|
||||
if(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() ) >
|
||||
m_world->getDistanceToCenterForKart( m_crashes.m_kart ))
|
||||
{
|
||||
steer_angle = steerToAngle(next, -M_PI*0.5f );
|
||||
@@ -454,10 +459,10 @@ void DefaultRobot::handleSteering(float dt)
|
||||
} // handleSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
void DefaultAIController::handleItems( const float DELTA, const int STEPS )
|
||||
{
|
||||
m_controls.m_fire = false;
|
||||
if(isRescue() || m_powerup.getType() == POWERUP_NOTHING ) return;
|
||||
m_controls->m_fire = false;
|
||||
if(m_kart->isRescue() || m_kart->getPowerup()->getType() == POWERUP_NOTHING ) return;
|
||||
|
||||
m_time_since_last_shot += DELTA;
|
||||
|
||||
@@ -467,7 +472,7 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
{
|
||||
if( m_time_since_last_shot > 10.0f )
|
||||
{
|
||||
m_controls.m_fire = true;
|
||||
m_controls->m_fire = true;
|
||||
m_time_since_last_shot = 0.0f;
|
||||
}
|
||||
return;
|
||||
@@ -475,7 +480,7 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
|
||||
// Tactic 2: calculate
|
||||
// -------------------
|
||||
switch( m_powerup.getType() )
|
||||
switch( m_kart->getPowerup()->getType() )
|
||||
{
|
||||
case POWERUP_ZIPPER:
|
||||
// Do nothing. Further up a zipper is used if nitro should be selected,
|
||||
@@ -490,7 +495,7 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
// kart as well? I.e. only drop if the kart behind is faster? Otoh
|
||||
// this approach helps preventing an overtaken kart to overtake us
|
||||
// again.
|
||||
m_controls.m_fire = (m_distance_behind < 15.0f &&
|
||||
m_controls->m_fire = (m_distance_behind < 15.0f &&
|
||||
m_distance_behind > 3.0f ) ||
|
||||
m_time_since_last_shot>10.0f;
|
||||
if(m_distance_behind < 10.0f && m_distance_behind > 2.0f )
|
||||
@@ -500,7 +505,7 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
// towards m_kart_ahead. And some of them can fire backwards, too - which
|
||||
// isn't yet supported for AI karts.
|
||||
case POWERUP_CAKE:
|
||||
m_controls.m_fire = (m_kart_ahead && m_distance_ahead < 20.0f) ||
|
||||
m_controls->m_fire = (m_kart_ahead && m_distance_ahead < 20.0f) ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
break;
|
||||
case POWERUP_BOWLING:
|
||||
@@ -513,11 +518,11 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
!m_kart_ahead;
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls.m_fire = (fire_backwards && distance < 30.0f) ||
|
||||
m_controls->m_fire = (fire_backwards && distance < 30.0f) ||
|
||||
(!fire_backwards && distance <10.0f) ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls.m_fire)
|
||||
m_controls.m_look_back = fire_backwards;
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
break;
|
||||
}
|
||||
case POWERUP_PLUNGER:
|
||||
@@ -529,26 +534,27 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
!m_kart_ahead;
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls.m_fire = distance < 30.0f ||
|
||||
m_controls->m_fire = distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls.m_fire)
|
||||
m_controls.m_look_back = fire_backwards;
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
break;
|
||||
}
|
||||
case POWERUP_ANVIL:
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
m_controls.m_fire = m_world->getTime()<1.0f && getPosition()>2;
|
||||
m_controls->m_fire = m_world->getTime()<1.0f &&
|
||||
m_kart->getPosition()>2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls.m_fire = m_time_since_last_shot > 3.0f &&
|
||||
getPosition()>1;
|
||||
m_controls->m_fire = m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1;
|
||||
}
|
||||
default:
|
||||
m_controls.m_fire = true;
|
||||
m_controls->m_fire = true;
|
||||
}
|
||||
if(m_controls.m_fire) m_time_since_last_shot = 0.0f;
|
||||
if(m_controls->m_fire) m_time_since_last_shot = 0.0f;
|
||||
return;
|
||||
} // handleItems
|
||||
|
||||
@@ -557,10 +563,10 @@ void DefaultRobot::handleItems( const float DELTA, const int STEPS )
|
||||
* 'closeness' is for now simply based on the position, i.e. if a kart is
|
||||
* more than one lap behind or ahead, it is not considered to be closest.
|
||||
*/
|
||||
void DefaultRobot::computeNearestKarts()
|
||||
void DefaultAIController::computeNearestKarts()
|
||||
{
|
||||
bool need_to_check = false;
|
||||
int my_position = getPosition();
|
||||
int my_position = m_kart->getPosition();
|
||||
// See if the kart ahead has changed:
|
||||
if( ( m_kart_ahead && m_kart_ahead->getPosition()+1!=my_position ) ||
|
||||
(!m_kart_ahead && my_position>1 ) )
|
||||
@@ -573,11 +579,11 @@ void DefaultRobot::computeNearestKarts()
|
||||
|
||||
m_kart_behind = m_kart_ahead = NULL;
|
||||
m_distance_ahead = m_distance_behind = 9999999.9f;
|
||||
float my_dist = m_world->getDistanceDownTrackForKart(getWorldKartId());
|
||||
float my_dist = m_world->getDistanceDownTrackForKart(m_kart->getWorldKartId());
|
||||
for(unsigned int i=0; i<m_world->getNumKarts(); i++)
|
||||
{
|
||||
Kart *k = m_world->getKart(i);
|
||||
if(k->isEliminated() || k==this) continue;
|
||||
if(k->isEliminated() || k==m_kart) continue;
|
||||
if(k->getPosition()==my_position+1)
|
||||
{
|
||||
m_kart_behind = k;
|
||||
@@ -597,28 +603,28 @@ void DefaultRobot::computeNearestKarts()
|
||||
} // computeNearestKarts
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handleAcceleration( const float DELTA )
|
||||
void DefaultAIController::handleAcceleration( const float DELTA )
|
||||
{
|
||||
//Do not accelerate until we have delayed the start enough
|
||||
if( m_time_till_start > 0.0f )
|
||||
{
|
||||
m_time_till_start -= DELTA;
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_controls.m_brake == true )
|
||||
if( m_controls->m_brake == true )
|
||||
{
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(hasViewBlockedByPlunger())
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
{
|
||||
if(!(getSpeed() > getMaxSpeedOnTerrain() / 2))
|
||||
m_controls.m_accel = 0.05f;
|
||||
if(!(m_kart->getSpeed() > m_kart->getMaxSpeedOnTerrain() / 2))
|
||||
m_controls->m_accel = 0.05f;
|
||||
else
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -627,7 +633,7 @@ void DefaultRobot::handleAcceleration( const float DELTA )
|
||||
//Find if any player is ahead of this kart
|
||||
bool player_winning = false;
|
||||
for(unsigned int i = 0; i < race_manager->getNumPlayers(); ++i )
|
||||
if( getPosition() > m_world->getPlayerKart(i)->getPosition() )
|
||||
if( m_kart->getPosition() > m_world->getPlayerKart(i)->getPosition() )
|
||||
{
|
||||
player_winning = true;
|
||||
break;
|
||||
@@ -635,16 +641,16 @@ void DefaultRobot::handleAcceleration( const float DELTA )
|
||||
|
||||
if( player_winning )
|
||||
{
|
||||
m_controls.m_accel = m_max_handicap_accel;
|
||||
m_controls->m_accel = m_max_handicap_accel;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_controls.m_accel = 1.0f;
|
||||
m_controls->m_accel = 1.0f;
|
||||
} // handleAcceleration
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handleRaceStart()
|
||||
void DefaultAIController::handleRaceStart()
|
||||
{
|
||||
//FIXME: make karts able to get a penalty for accelerating too soon
|
||||
//like players, should happen to about 20% of the karts in easy,
|
||||
@@ -660,15 +666,15 @@ void DefaultRobot::handleRaceStart()
|
||||
} // handleRaceStart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::handleRescue(const float DELTA)
|
||||
void DefaultAIController::handleRescue(const float DELTA)
|
||||
{
|
||||
// check if kart is stuck
|
||||
if(getSpeed()<2.0f && !isRescue() && !m_world->isStartPhase())
|
||||
if(m_kart->getSpeed()<2.0f && !m_kart->isRescue() && !m_world->isStartPhase())
|
||||
{
|
||||
m_time_since_stuck += DELTA;
|
||||
if(m_time_since_stuck > 2.0f)
|
||||
{
|
||||
forceRescue();
|
||||
m_kart->forceRescue();
|
||||
m_time_since_stuck=0.0f;
|
||||
} // m_time_since_stuck > 2.0f
|
||||
}
|
||||
@@ -681,36 +687,36 @@ void DefaultRobot::handleRescue(const float DELTA)
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Decides wether to use nitro or not.
|
||||
*/
|
||||
void DefaultRobot::handleNitroAndZipper()
|
||||
void DefaultAIController::handleNitroAndZipper()
|
||||
{
|
||||
m_controls.m_nitro = false;
|
||||
m_controls->m_nitro = false;
|
||||
// If we are already very fast, save nitro.
|
||||
if(getSpeed() > 0.95f*getMaxSpeedOnTerrain())
|
||||
if(m_kart->getSpeed() > 0.95f*m_kart->getMaxSpeedOnTerrain())
|
||||
return;
|
||||
// Don't use nitro when the AI has a plunger in the face!
|
||||
if(hasViewBlockedByPlunger()) return;
|
||||
if(m_kart->hasViewBlockedByPlunger()) return;
|
||||
|
||||
// Don't use nitro if the kart doesn't have any or is not on ground.
|
||||
if(!isOnGround() || hasFinishedRace()) return;
|
||||
if(!m_kart->isOnGround() || m_kart->hasFinishedRace()) return;
|
||||
|
||||
// Don't compute nitro usage if we don't have nitro or are not supposed
|
||||
// to use it, and we don't have a zipper or are not supposed to use
|
||||
// it (calculated).
|
||||
if( (getEnergy()==0 || m_nitro_level==NITRO_NONE) &&
|
||||
(m_powerup.getType()!=POWERUP_ZIPPER || m_item_tactic==IT_TEN_SECONDS) )
|
||||
if( (m_kart->getEnergy()==0 || m_nitro_level==NITRO_NONE) &&
|
||||
(m_kart->getPowerup()->getType()!=POWERUP_ZIPPER || m_item_tactic==IT_TEN_SECONDS) )
|
||||
return;
|
||||
|
||||
// If a parachute or anvil is attached, the nitro doesn't give much
|
||||
// benefit. Better wait till later.
|
||||
const bool has_slowdown_attachment =
|
||||
m_attachment.getType()==ATTACH_PARACHUTE ||
|
||||
m_attachment.getType()==ATTACH_ANVIL;
|
||||
m_kart->getAttachment()->getType()==ATTACH_PARACHUTE ||
|
||||
m_kart->getAttachment()->getType()==ATTACH_ANVIL;
|
||||
if(has_slowdown_attachment) return;
|
||||
|
||||
// If the kart is very slow (e.g. after rescue), use nitro
|
||||
if(getSpeed()<5)
|
||||
if(m_kart->getSpeed()<5)
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -718,9 +724,9 @@ void DefaultRobot::handleNitroAndZipper()
|
||||
// (i.e. more than 2) nitro, use it.
|
||||
// -------------------------------------------------
|
||||
const unsigned int num_karts = m_world->getCurrentNumKarts();
|
||||
if(getPosition()== (int)num_karts && getEnergy()>2.0f)
|
||||
if(m_kart->getPosition()== (int)num_karts && m_kart->getEnergy()>2.0f)
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -728,13 +734,13 @@ void DefaultRobot::handleNitroAndZipper()
|
||||
// anyway. Since the kart is faster with nitro, estimate a 50% time
|
||||
// decrease (additionally some nitro will be saved when top speed
|
||||
// is reached).
|
||||
if(m_world->getLapForKart(getWorldKartId())==race_manager->getNumLaps()-1 &&
|
||||
if(m_world->getLapForKart(m_kart->getWorldKartId())==race_manager->getNumLaps()-1 &&
|
||||
m_nitro_level == NITRO_ALL)
|
||||
{
|
||||
float finish = m_world->getEstimatedFinishTime(getWorldKartId());
|
||||
if( 1.5f*getEnergy() >= finish - m_world->getTime() )
|
||||
float finish = m_world->getEstimatedFinishTime(m_kart->getWorldKartId());
|
||||
if( 1.5f*m_kart->getEnergy() >= finish - m_world->getTime() )
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -746,35 +752,35 @@ void DefaultRobot::handleNitroAndZipper()
|
||||
// Try to overtake a kart that is close ahead, except
|
||||
// when we are already much faster than that kart
|
||||
// --------------------------------------------------
|
||||
if(m_kart_ahead &&
|
||||
m_distance_ahead < overtake_distance &&
|
||||
m_kart_ahead->getSpeed()+5.0f > getSpeed() )
|
||||
if(m_kart_ahead &&
|
||||
m_distance_ahead < overtake_distance &&
|
||||
m_kart_ahead->getSpeed()+5.0f > m_kart->getSpeed() )
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_kart_behind &&
|
||||
m_distance_behind < overtake_distance &&
|
||||
m_kart_behind->getSpeed() > getSpeed() )
|
||||
if(m_kart_behind &&
|
||||
m_distance_behind < overtake_distance &&
|
||||
m_kart_behind->getSpeed() > m_kart->getSpeed() )
|
||||
{
|
||||
// Only prevent overtaking on highest level
|
||||
m_controls.m_nitro = m_nitro_level==NITRO_ALL;
|
||||
m_controls->m_nitro = m_nitro_level==NITRO_ALL;
|
||||
return;
|
||||
}
|
||||
|
||||
} // handleNitroAndZipper
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float DefaultRobot::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
float DefaultAIController::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
{
|
||||
float angle = m_quad_graph->getAngleToNext(SECTOR,
|
||||
m_successor_index[SECTOR]);
|
||||
|
||||
//Desired angle minus current angle equals how many angles to turn
|
||||
float steer_angle = angle - getHPR().getHeading();
|
||||
float steer_angle = angle - m_kart->getHPR().getHeading();
|
||||
|
||||
if(hasViewBlockedByPlunger())
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
steer_angle += ANGLE/5;
|
||||
else
|
||||
steer_angle += ANGLE;
|
||||
@@ -791,20 +797,20 @@ float DefaultRobot::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
* \param point Point to steer towards.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
float DefaultRobot::steerToPoint(const Vec3 &point, float dt)
|
||||
float DefaultAIController::steerToPoint(const Vec3 &point, float dt)
|
||||
{
|
||||
// No sense steering if we are not driving.
|
||||
if(getSpeed()==0) return 0.0f;
|
||||
const float dx = point.getX() - getXYZ().getX();
|
||||
const float dy = point.getY() - getXYZ().getY();
|
||||
if(m_kart->getSpeed()==0) return 0.0f;
|
||||
const float dx = point.getX() - m_kart->getXYZ().getX();
|
||||
const float dy = point.getY() - m_kart->getXYZ().getY();
|
||||
/** Angle from the kart position to the point in world coordinates. */
|
||||
float theta = -atan2(dx, dy);
|
||||
|
||||
// Angle is the point is relative to the heading - but take the current
|
||||
// angular velocity into account, too. The value is multiplied by two
|
||||
// to avoid 'oversteering' - experimentally found.
|
||||
float angle_2_point = theta - getHPR().getHeading()
|
||||
- dt*m_body->getAngularVelocity().getZ()*2.0f;
|
||||
float angle_2_point = theta - m_kart->getHPR().getHeading()
|
||||
- dt*m_kart->getBody()->getAngularVelocity().getZ()*2.0f;
|
||||
angle_2_point = normalizeAngle(angle_2_point);
|
||||
if(fabsf(angle_2_point)<0.1) return 0.0f;
|
||||
|
||||
@@ -820,8 +826,8 @@ float DefaultRobot::steerToPoint(const Vec3 &point, float dt)
|
||||
* computed, and from that the turn radius, and then the steer angle.
|
||||
* (note: the 2*M_PI can be removed from the computations)
|
||||
*/
|
||||
float radius = dt*getSpeed()/angle_2_point;
|
||||
float sin_steer_angle = m_kart_properties->getWheelBase()/radius;
|
||||
float radius = dt*m_kart->getSpeed()/angle_2_point;
|
||||
float sin_steer_angle = m_kart->getKartProperties()->getWheelBase()/radius;
|
||||
#ifdef DEBUG_OUTPUT
|
||||
printf("theta %f a2p %f angularv %f radius %f ssa %f\n",
|
||||
theta, angle_2_point, m_body->getAngularVelocity().getZ(),
|
||||
@@ -829,14 +835,16 @@ float DefaultRobot::steerToPoint(const Vec3 &point, float dt)
|
||||
#endif
|
||||
// Add 0.1 since rouding errors will otherwise result in the kart
|
||||
// not using drifting.
|
||||
if(sin_steer_angle <= -1.0f) return -getMaxSteerAngle()*m_skidding_threshold-0.1f;
|
||||
if(sin_steer_angle >= 1.0f) return getMaxSteerAngle()*m_skidding_threshold+0.1f;
|
||||
if(sin_steer_angle <= -1.0f)
|
||||
return -m_kart->getMaxSteerAngle()*m_skidding_threshold-0.1f;
|
||||
if(sin_steer_angle >= 1.0f)
|
||||
return m_kart->getMaxSteerAngle()*m_skidding_threshold+0.1f;
|
||||
float steer_angle = asin(sin_steer_angle);
|
||||
return steer_angle;
|
||||
} // steerToPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
void DefaultAIController::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
{
|
||||
//Right now there are 2 kind of 'crashes': with other karts and another
|
||||
//with the track. The sight line is used to find if the karts crash with
|
||||
@@ -848,7 +856,7 @@ void DefaultRobot::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
const size_t NUM_KARTS = m_world->getNumKarts();
|
||||
|
||||
//Protection against having vel_normal with nan values
|
||||
const Vec3 &VEL = getVelocity();
|
||||
const Vec3 &VEL = m_kart->getVelocity();
|
||||
Vec3 vel_normal(VEL.getX(), VEL.getY(), 0.0);
|
||||
float speed=vel_normal.length();
|
||||
// If the velocity is zero, no sense in checking for crashes in time
|
||||
@@ -871,10 +879,10 @@ void DefaultRobot::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
for( unsigned int j = 0; j < NUM_KARTS; ++j )
|
||||
{
|
||||
const Kart* kart = m_world->getKart(j);
|
||||
if(kart==this||kart->isEliminated()) continue; // ignore eliminated karts
|
||||
if(kart==m_kart||kart->isEliminated()) continue; // ignore eliminated karts
|
||||
const Kart *other_kart = m_world->getKart(j);
|
||||
// Ignore karts ahead that are faster than this kart.
|
||||
if(getVelocityLC().getY() < other_kart->getVelocityLC().getY())
|
||||
if(m_kart->getVelocityLC().getY() < other_kart->getVelocityLC().getY())
|
||||
continue;
|
||||
Vec3 other_kart_xyz = other_kart->getXYZ() + other_kart->getVelocity()*(i*dt);
|
||||
float kart_distance = (step_coord - other_kart_xyz).length_2d();
|
||||
@@ -904,7 +912,7 @@ void DefaultRobot::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
* the two edges of the track is closest to the next curve after wards,
|
||||
* and return the position of that edge.
|
||||
*/
|
||||
void DefaultRobot::findNonCrashingPoint(Vec3 *result)
|
||||
void DefaultAIController::findNonCrashingPoint(Vec3 *result)
|
||||
{
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
@@ -922,7 +930,8 @@ void DefaultRobot::findNonCrashingPoint(Vec3 *result)
|
||||
target_sector = m_next_node_index[sector];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = m_quad_graph->getQuad(target_sector).getCenter() - getXYZ();
|
||||
direction = m_quad_graph->getQuad(target_sector).getCenter()
|
||||
- m_kart->getXYZ();
|
||||
|
||||
float len=direction.length_2d();
|
||||
steps = int( len / m_kart_length );
|
||||
@@ -937,7 +946,7 @@ void DefaultRobot::findNonCrashingPoint(Vec3 *result)
|
||||
//Test if we crash if we drive towards the target sector
|
||||
for( int i = 2; i < steps; ++i )
|
||||
{
|
||||
step_coord = getXYZ()+direction*m_kart_length * float(i);
|
||||
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
|
||||
|
||||
m_quad_graph->spatialToTrack(&step_track_coord, step_coord,
|
||||
sector );
|
||||
@@ -957,11 +966,11 @@ void DefaultRobot::findNonCrashingPoint(Vec3 *result)
|
||||
} // findNonCrashingPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void DefaultRobot::reset()
|
||||
void DefaultAIController::reset()
|
||||
{
|
||||
m_time_since_last_shot = 0.0f;
|
||||
m_start_kart_crash_direction = 0;
|
||||
m_curve_target_speed = getMaxSpeedOnTerrain();
|
||||
m_curve_target_speed = m_kart->getMaxSpeedOnTerrain();
|
||||
m_curve_angle = 0.0;
|
||||
m_time_till_start = -1.0f;
|
||||
m_crash_time = 0.0f;
|
||||
@@ -972,20 +981,20 @@ void DefaultRobot::reset()
|
||||
m_kart_behind = NULL;
|
||||
m_distance_behind = 0.0f;
|
||||
|
||||
AutoKart::reset();
|
||||
Controller::reset();
|
||||
m_track_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
m_quad_graph->findRoadSector(getXYZ(), &m_track_node);
|
||||
m_quad_graph->findRoadSector(m_kart->getXYZ(), &m_track_node);
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
fprintf(stderr, "Invalid starting position for '%s' - not on track - can be ignored.\n",
|
||||
getIdent().c_str());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(getXYZ());
|
||||
m_kart->getIdent().c_str());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline float DefaultRobot::normalizeAngle(float angle)
|
||||
inline float DefaultAIController::normalizeAngle(float angle)
|
||||
{
|
||||
while( angle > 2*M_PI ) angle -= 2*M_PI;
|
||||
while( angle < -2*M_PI ) angle += 2*M_PI;
|
||||
@@ -1001,9 +1010,9 @@ inline float DefaultRobot::normalizeAngle(float angle)
|
||||
* and gets the number of steps to use for the sight line of the kart.
|
||||
* The calling sequence guarantees that m_future_sector is not UNKNOWN.
|
||||
*/
|
||||
int DefaultRobot::calcSteps()
|
||||
int DefaultAIController::calcSteps()
|
||||
{
|
||||
int steps = int( getVelocityLC().getY() / m_kart_length );
|
||||
int steps = int( m_kart->getVelocityLC().getY() / m_kart_length );
|
||||
if( steps < m_min_steps ) steps = m_min_steps;
|
||||
|
||||
//Increase the steps depending on the width, if we steering hard,
|
||||
@@ -1013,7 +1022,7 @@ int DefaultRobot::calcSteps()
|
||||
// for more steps if we hit another kart?? If we steer hard,
|
||||
// the approximation used (pos + velocity*dt) will be even
|
||||
// worse, since it doesn't take steering into account.
|
||||
if( fabsf(m_controls.m_steer) > 0.95 )
|
||||
if( fabsf(m_controls->m_steer) > 0.95 )
|
||||
{
|
||||
const int WIDTH_STEPS =
|
||||
(int)( m_quad_graph->getNode(m_future_sector).getPathWidth()
|
||||
@@ -1036,32 +1045,32 @@ int DefaultRobot::calcSteps()
|
||||
* \param angle Steering angle.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
void DefaultRobot::setSteering(float angle, float dt)
|
||||
void DefaultAIController::setSteering(float angle, float dt)
|
||||
{
|
||||
float steer_fraction = angle / getMaxSteerAngle();
|
||||
m_controls.m_drift = fabsf(steer_fraction)>=m_skidding_threshold;
|
||||
if(hasViewBlockedByPlunger()) m_controls.m_drift = false;
|
||||
float old_steer = m_controls.m_steer;
|
||||
float steer_fraction = angle / m_kart->getMaxSteerAngle();
|
||||
m_controls->m_drift = fabsf(steer_fraction)>=m_skidding_threshold;
|
||||
if(m_kart->hasViewBlockedByPlunger()) m_controls->m_drift = false;
|
||||
float old_steer = m_controls->m_steer;
|
||||
|
||||
if (steer_fraction > 1.0f) steer_fraction = 1.0f;
|
||||
else if(steer_fraction < -1.0f) steer_fraction = -1.0f;
|
||||
|
||||
if(hasViewBlockedByPlunger())
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
{
|
||||
if (steer_fraction > 0.5f) steer_fraction = 0.5f;
|
||||
else if(steer_fraction < -0.5f) steer_fraction = -0.5f;
|
||||
}
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_kart_properties->getTimeFullSteerAI();
|
||||
float max_steer_change = dt/m_kart->getKartProperties()->getTimeFullSteerAI();
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls.m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls.m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
m_controls->m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change;
|
||||
}
|
||||
} // setSteering
|
||||
@@ -1073,11 +1082,11 @@ void DefaultRobot::setSteering(float angle, float dt)
|
||||
*
|
||||
* The number of sectors that form the curve is dependant on the kart's speed.
|
||||
*/
|
||||
void DefaultRobot::findCurve()
|
||||
void DefaultAIController::findCurve()
|
||||
{
|
||||
float total_dist = 0.0f;
|
||||
int i;
|
||||
for(i = m_track_node; total_dist < getVelocityLC().getY();
|
||||
for(i = m_track_node; total_dist < m_kart->getVelocityLC().getY();
|
||||
i = m_next_node_index[i])
|
||||
{
|
||||
total_dist += m_quad_graph->getDistanceToNext(i, m_successor_index[i]);
|
||||
@@ -1089,5 +1098,5 @@ void DefaultRobot::findCurve()
|
||||
-m_quad_graph->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node]) );
|
||||
|
||||
m_curve_target_speed = getMaxSpeedOnTerrain();
|
||||
m_curve_target_speed = m_kart->getMaxSpeedOnTerrain();
|
||||
} // findCurve
|
||||
@@ -1,6 +1,7 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2010 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@@ -16,14 +17,14 @@
|
||||
// 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_DEFAULT_HPP
|
||||
#define HEADER_DEFAULT_HPP
|
||||
#ifndef HEADER_DEFAULT_SI_CONTROLLER_HPP
|
||||
#define HEADER_DEFAULT_AI_CONTROLLER_HPP
|
||||
|
||||
#include "karts/auto_kart.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
|
||||
/* third coord won't be used */
|
||||
//#include "karts/auto_kart.hpp"
|
||||
//#include "modes/profile_world.hpp"
|
||||
//#include "utils/vec3.hpp"
|
||||
|
||||
class Track;
|
||||
class LinearWorld;
|
||||
@@ -37,7 +38,7 @@ namespace irr
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultRobot : public AutoKart
|
||||
class DefaultAIController : public Controller
|
||||
{
|
||||
private:
|
||||
enum FallbackTactic
|
||||
@@ -194,22 +195,12 @@ private:
|
||||
void findCurve();
|
||||
|
||||
public:
|
||||
DefaultRobot(const std::string& kart_name, int position,
|
||||
const btTransform& init_pos, const Track *track);
|
||||
~DefaultRobot();
|
||||
void update (float delta) ;
|
||||
void reset ();
|
||||
DefaultAIController(Kart *kart);
|
||||
~DefaultAIController();
|
||||
virtual void update (float delta) ;
|
||||
virtual void reset ();
|
||||
virtual void crashed (Kart *k) {if(k) m_collided = true;};
|
||||
virtual const irr::core::stringw& getName() const
|
||||
{
|
||||
// Static to avoid returning the address of a temporary stringq
|
||||
static irr::core::stringw name=m_kart_properties->getName();
|
||||
// Add the name of the AI in case of profile mode, to make it
|
||||
// easier to compare AIs
|
||||
if(ProfileWorld::isProfileMode())
|
||||
name+="(default)";
|
||||
return name;
|
||||
}
|
||||
virtual const irr::core::stringw& getNamePostfix() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
551
src/karts/controller/end_controller.cpp
Normal file
551
src/karts/controller/end_controller.cpp
Normal file
@@ -0,0 +1,551 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2008 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.
|
||||
|
||||
|
||||
//The AI debugging works best with just 1 AI kart, so set the number of karts
|
||||
//to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
|
||||
#undef AI_DEBUG
|
||||
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
# include "irrlicht.h"
|
||||
using namespace irr;
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#endif
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/quad_graph.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
EndController::EndController(Kart *kart) : Controller(kart)
|
||||
{
|
||||
m_kart_length = m_kart->getKartProperties()->getKartModel()->getLength();
|
||||
m_kart_width = m_kart->getKartProperties()->getKartModel()->getWidth();
|
||||
m_world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
|
||||
m_quad_graph = &m_track->getQuadGraph();
|
||||
m_next_node_index.reserve(m_quad_graph->getNumNodes());
|
||||
m_successor_index.reserve(m_quad_graph->getNumNodes());
|
||||
|
||||
// Initialise the fields with -1
|
||||
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
|
||||
{
|
||||
m_next_node_index.push_back(-1);
|
||||
m_successor_index.push_back(-1);
|
||||
}
|
||||
// For now pick one part on random, which is not adjusted during the run
|
||||
std::vector<unsigned int> next;
|
||||
int count=0;
|
||||
int current_node=0;
|
||||
while (1)
|
||||
{
|
||||
next.clear();
|
||||
m_quad_graph->getSuccessors(current_node, next);
|
||||
int indx = rand() % next.size();
|
||||
m_successor_index[current_node] = indx;
|
||||
m_next_node_index[current_node] = next[indx];
|
||||
current_node = next[indx];
|
||||
if(current_node==0) break;
|
||||
count++;
|
||||
if(count>(int)m_quad_graph->getNumNodes())
|
||||
{
|
||||
fprintf(stderr, "AI can't find a loop going back to node 0, aborting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
};
|
||||
|
||||
const unsigned int look_ahead=10;
|
||||
// Now compute for each node in the graph the list of the next 'look_ahead'
|
||||
// graph nodes. This is the list of node that is tested in checkCrashes.
|
||||
// If the look_ahead is too big, the AI can skip loops (see
|
||||
// QuadGraph::findRoadSector for details), if it's too short the AI won't
|
||||
// find too good a driveline. Note that in general this list should
|
||||
// be computed recursively, but since the AI for now is using only
|
||||
// (randomly picked) path this is fine
|
||||
m_all_look_aheads.reserve(m_quad_graph->getNumNodes());
|
||||
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
|
||||
{
|
||||
std::vector<int> l;
|
||||
int current = i;
|
||||
for(unsigned int j=0; j<look_ahead; j++)
|
||||
{
|
||||
int next = m_next_node_index[current];
|
||||
if(next==-1) break;
|
||||
l.push_back(m_next_node_index[current]);
|
||||
current = m_next_node_index[current];
|
||||
} // for j<look_ahead
|
||||
m_all_look_aheads.push_back(l);
|
||||
}
|
||||
// Reset must be called after m_quad_graph etc. is set up
|
||||
reset();
|
||||
|
||||
m_max_handicap_accel = 1.0f;
|
||||
m_min_steps = 2;
|
||||
m_skidding_threshold = 1.3f;
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere = irr_driver->getSceneManager()->addSphereSceneNode(1);
|
||||
#endif
|
||||
} // EndController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The destructor deletes the shared TrackInfo objects if no more EndController
|
||||
* instances are around.
|
||||
*/
|
||||
EndController::~EndController()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
#endif
|
||||
} // ~EndController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//TODO: if the AI is crashing constantly, make it move backwards in a straight
|
||||
//line, then move forward while turning.
|
||||
void EndController::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
|
||||
// Update the current node:
|
||||
if(m_track_node!=QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
int old_node = m_track_node;
|
||||
m_quad_graph->findRoadSector(m_kart->getXYZ(), &m_track_node,
|
||||
&m_all_look_aheads[m_track_node]);
|
||||
// IF the AI is off track (or on a branch of the track it did not
|
||||
// select to be on), keep the old position.
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR ||
|
||||
m_next_node_index[m_track_node]==-1)
|
||||
m_track_node = old_node;
|
||||
}
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
// The client does not do any AI computations.
|
||||
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
|
||||
{
|
||||
Controller::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*Get information that is needed by more than 1 of the handling funcs*/
|
||||
//Detect if we are going to crash with the track and/or kart
|
||||
int steps = 0;
|
||||
|
||||
steps = calcSteps();
|
||||
|
||||
findCurve();
|
||||
|
||||
/*Response handling functions*/
|
||||
handleAcceleration(dt);
|
||||
handleSteering(dt);
|
||||
handleRescue(dt);
|
||||
handleBraking();
|
||||
|
||||
/*And obviously general kart stuff*/
|
||||
Controller::update(dt);
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void EndController::handleBraking()
|
||||
{
|
||||
// In follow the leader mode, the kart should brake if they are ahead of
|
||||
// the leader (and not the leader, i.e. don't have initial position 1)
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
m_kart->getPosition() < m_world->getKart(0)->getPosition() &&
|
||||
m_kart->getInitialPosition()>1 )
|
||||
{
|
||||
m_controls->m_brake = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const float MIN_SPEED = 5.0f;
|
||||
//We may brake if we are about to get out of the road, but only if the
|
||||
//kart is on top of the road, and if we won't slow down below a certain
|
||||
//limit.
|
||||
m_controls->m_brake = false;
|
||||
} // handleBraking
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void EndController::handleSteering(float dt)
|
||||
{
|
||||
const int next = m_next_node_index[m_track_node];
|
||||
|
||||
float steer_angle = 0.0f;
|
||||
|
||||
/*The AI responds based on the information we just gathered, using a
|
||||
*finite state machine.
|
||||
*/
|
||||
//Reaction to being outside of the road
|
||||
if( fabsf(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )) >
|
||||
0.5f* m_quad_graph->getNode(m_track_node).getPathWidth()+0.5f )
|
||||
{
|
||||
steer_angle = steerToPoint(m_quad_graph->getQuad(next).getCenter(),
|
||||
dt );
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(m_quad_graph->getQuad(next).getCenter().toIrrVector());
|
||||
std::cout << "- Outside of road: steer to center point." <<
|
||||
std::endl;
|
||||
#endif
|
||||
}
|
||||
//If we are going to crash against a kart, avoid it if it doesn't
|
||||
//drives the kart out of the road
|
||||
|
||||
else
|
||||
{
|
||||
m_start_kart_crash_direction = 0;
|
||||
Vec3 straight_point;
|
||||
findNonCrashingPoint(&straight_point);
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(straight_point.toIrrVector());
|
||||
#endif
|
||||
steer_angle = steerToPoint(straight_point, dt);
|
||||
}
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
std::cout << "- Fallback." << std::endl;
|
||||
#endif
|
||||
|
||||
|
||||
setSteering(steer_angle, dt);
|
||||
} // handleSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void EndController::handleAcceleration( const float DELTA )
|
||||
{
|
||||
//Do not accelerate until we have delayed the start enough
|
||||
if( m_time_till_start > 0.0f )
|
||||
{
|
||||
m_time_till_start -= DELTA;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_controls->m_brake == true )
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
{
|
||||
if(!(m_kart->getSpeed() > m_kart->getMaxSpeedOnTerrain() / 2))
|
||||
m_controls->m_accel = 0.05f;
|
||||
else
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
m_controls->m_accel = 1.0f;
|
||||
} // handleAcceleration
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void EndController::handleRescue(const float DELTA)
|
||||
{
|
||||
// check if kart is stuck
|
||||
if(m_kart->getSpeed()<2.0f && !m_kart->isRescue() && !m_world->isStartPhase())
|
||||
{
|
||||
m_time_since_stuck += DELTA;
|
||||
if(m_time_since_stuck > 2.0f)
|
||||
{
|
||||
m_kart->forceRescue();
|
||||
m_time_since_stuck=0.0f;
|
||||
} // m_time_since_stuck > 2.0f
|
||||
}
|
||||
else
|
||||
{
|
||||
m_time_since_stuck = 0.0f;
|
||||
}
|
||||
} // handleRescue
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float EndController::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
{
|
||||
float angle = m_quad_graph->getAngleToNext(SECTOR,
|
||||
m_successor_index[SECTOR]);
|
||||
|
||||
//Desired angle minus current angle equals how many angles to turn
|
||||
float steer_angle = angle - m_kart->getHPR().getHeading();
|
||||
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
steer_angle += ANGLE/5;
|
||||
else
|
||||
steer_angle += ANGLE;
|
||||
steer_angle = normalizeAngle( steer_angle );
|
||||
|
||||
return steer_angle;
|
||||
} // steerToAngle
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Computes the steering angle to reach a certain point. Note that the
|
||||
* steering angle depends on the velocity of the kart (simple setting the
|
||||
* steering angle towards the angle the point has is not correct: a slower
|
||||
* kart will obviously turn less in one time step than a faster kart).
|
||||
* \param point Point to steer towards.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
float EndController::steerToPoint(const Vec3 &point, float dt)
|
||||
{
|
||||
// No sense steering if we are not driving.
|
||||
if(m_kart->getSpeed()==0) return 0.0f;
|
||||
const float dx = point.getX() - m_kart->getXYZ().getX();
|
||||
const float dy = point.getY() - m_kart->getXYZ().getY();
|
||||
/** Angle from the kart position to the point in world coordinates. */
|
||||
float theta = -atan2(dx, dy);
|
||||
|
||||
// Angle is the point is relative to the heading - but take the current
|
||||
// angular velocity into account, too. The value is multiplied by two
|
||||
// to avoid 'oversteering' - experimentally found.
|
||||
float angle_2_point = theta - m_kart->getHPR().getHeading()
|
||||
- dt*m_kart->getBody()->getAngularVelocity().getZ()*2.0f;
|
||||
angle_2_point = normalizeAngle(angle_2_point);
|
||||
if(fabsf(angle_2_point)<0.1) return 0.0f;
|
||||
|
||||
/** To understand this code, consider how a given steering angle determines
|
||||
* the angle the kart is facing after one timestep:
|
||||
* sin(steer_angle) = wheel_base / radius; --> compute radius of turn
|
||||
* circumference = radius * 2 * M_PI; --> circumference of turn circle
|
||||
* The kart drives dt*V units during a timestep of size dt. So the ratio
|
||||
* of the driven distance to the circumference is the same as the angle
|
||||
* the whole circle, or:
|
||||
* angle / (2*M_PI) = dt*V / circumference
|
||||
* Reversly, if the angle to drive to is given, the circumference can be
|
||||
* computed, and from that the turn radius, and then the steer angle.
|
||||
* (note: the 2*M_PI can be removed from the computations)
|
||||
*/
|
||||
float radius = dt*m_kart->getSpeed()/angle_2_point;
|
||||
float sin_steer_angle = m_kart->getKartProperties()->getWheelBase()/radius;
|
||||
#ifdef DEBUG_OUTPUT
|
||||
printf("theta %f a2p %f angularv %f radius %f ssa %f\n",
|
||||
theta, angle_2_point, m_body->getAngularVelocity().getZ(),
|
||||
radius, sin_steer_angle);
|
||||
#endif
|
||||
// Add 0.1 since rouding errors will otherwise result in the kart
|
||||
// not using drifting.
|
||||
if(sin_steer_angle <= -1.0f) return -m_kart->getMaxSteerAngle()*m_skidding_threshold-0.1f;
|
||||
if(sin_steer_angle >= 1.0f) return m_kart->getMaxSteerAngle()*m_skidding_threshold+0.1f;
|
||||
float steer_angle = asin(sin_steer_angle);
|
||||
return steer_angle;
|
||||
} // steerToPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Find the sector that at the longest distance from the kart, that can be
|
||||
* 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.
|
||||
*/
|
||||
void EndController::findNonCrashingPoint(Vec3 *result)
|
||||
{
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
Vec3 step_track_coord;
|
||||
float distance;
|
||||
int steps;
|
||||
|
||||
//We exit from the function when we have found a solution
|
||||
while( 1 )
|
||||
{
|
||||
//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];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = m_quad_graph->getQuad(target_sector).getCenter() - m_kart->getXYZ();
|
||||
|
||||
float len=direction.length_2d();
|
||||
steps = int( len / m_kart_length );
|
||||
if( steps < 3 ) steps = 3;
|
||||
|
||||
//Protection against having vel_normal with nan values
|
||||
if(len>0.0f) {
|
||||
direction*= 1.0f/len;
|
||||
}
|
||||
|
||||
Vec3 step_coord;
|
||||
//Test if we crash if we drive towards the target sector
|
||||
for( int i = 2; i < steps; ++i )
|
||||
{
|
||||
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
|
||||
|
||||
m_quad_graph->spatialToTrack(&step_track_coord, step_coord,
|
||||
sector );
|
||||
|
||||
distance = fabsf(step_track_coord[0]);
|
||||
|
||||
//If we are outside, the previous sector is what we are looking for
|
||||
if ( distance + m_kart_width * 0.5f
|
||||
> m_quad_graph->getNode(sector).getPathWidth() )
|
||||
{
|
||||
*result = m_quad_graph->getQuad(sector).getCenter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
sector = target_sector;
|
||||
}
|
||||
} // findNonCrashingPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void EndController::reset()
|
||||
{
|
||||
m_start_kart_crash_direction = 0;
|
||||
m_curve_target_speed = m_kart->getMaxSpeedOnTerrain();
|
||||
m_curve_angle = 0.0;
|
||||
m_time_till_start = -1.0f;
|
||||
m_crash_time = 0.0f;
|
||||
m_time_since_stuck = 0.0f;
|
||||
|
||||
Controller::reset();
|
||||
m_track_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
m_quad_graph->findRoadSector(m_kart->getXYZ(), &m_track_node);
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
fprintf(stderr, "Invalid starting position for '%s' - not on track - can be ignored.\n",
|
||||
m_kart->getIdent().c_str());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline float EndController::normalizeAngle(float angle)
|
||||
{
|
||||
while( angle > 2*M_PI ) angle -= 2*M_PI;
|
||||
while( angle < -2*M_PI ) angle += 2*M_PI;
|
||||
|
||||
if( angle > M_PI ) angle -= 2*M_PI;
|
||||
else if( angle < -M_PI ) angle += 2*M_PI;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** calc_steps() divides the velocity vector by the lenght of the kart,
|
||||
* and gets the number of steps to use for the sight line of the kart.
|
||||
* The calling sequence guarantees that m_future_sector is not UNKNOWN.
|
||||
*/
|
||||
int EndController::calcSteps()
|
||||
{
|
||||
int steps = int( m_kart->getVelocityLC().getY() / m_kart_length );
|
||||
if( steps < m_min_steps ) steps = m_min_steps;
|
||||
|
||||
//Increase the steps depending on the width, if we steering hard,
|
||||
//mostly for curves.
|
||||
#if 0
|
||||
// FIXME: I don't understand this: if we are steering hard, we check
|
||||
// for more steps if we hit another kart?? If we steer hard,
|
||||
// the approximation used (pos + velocity*dt) will be even
|
||||
// worse, since it doesn't take steering into account.
|
||||
if( fabsf(m_controls->m_steer) > 0.95 )
|
||||
{
|
||||
const int WIDTH_STEPS =
|
||||
(int)( m_quad_graph->getNode(m_future_sector).getPathWidth()
|
||||
/( m_kart_length * 2.0 ) );
|
||||
|
||||
steps += WIDTH_STEPS;
|
||||
}
|
||||
#endif
|
||||
return steps;
|
||||
} // calcSteps
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Converts the steering angle to a lr steering in the range of -1 to 1.
|
||||
* If the steering angle is too great, it will also trigger skidding. This
|
||||
* function uses a 'time till full steer' value specifying the time it takes
|
||||
* for the wheel to reach full left/right steering similar to player karts
|
||||
* when using a digital input device. This is done to remove shaking of
|
||||
* AI karts (which happens when the kart frequently changes the direction
|
||||
* of a turn). The parameter is defined in the kart properties.
|
||||
* \param angle Steering angle.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
void EndController::setSteering(float angle, float dt)
|
||||
{
|
||||
float steer_fraction = angle / m_kart->getMaxSteerAngle();
|
||||
m_controls->m_drift = fabsf(steer_fraction)>=m_skidding_threshold;
|
||||
if(m_kart->hasViewBlockedByPlunger()) m_controls->m_drift = false;
|
||||
float old_steer = m_controls->m_steer;
|
||||
|
||||
if (steer_fraction > 1.0f) steer_fraction = 1.0f;
|
||||
else if(steer_fraction < -1.0f) steer_fraction = -1.0f;
|
||||
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
{
|
||||
if (steer_fraction > 0.5f) steer_fraction = 0.5f;
|
||||
else if(steer_fraction < -0.5f) steer_fraction = -0.5f;
|
||||
}
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_kart->getKartProperties()->getTimeFullSteerAI();
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change;
|
||||
}
|
||||
} // setSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**FindCurve() gathers info about the closest sectors ahead: the curve
|
||||
* angle, the direction of the next turn, and the optimal speed at which the
|
||||
* curve can be travelled at it's widest angle.
|
||||
*
|
||||
* The number of sectors that form the curve is dependant on the kart's speed.
|
||||
*/
|
||||
void EndController::findCurve()
|
||||
{
|
||||
float total_dist = 0.0f;
|
||||
int i;
|
||||
for(i = m_track_node; total_dist < m_kart->getVelocityLC().getY();
|
||||
i = m_next_node_index[i])
|
||||
{
|
||||
total_dist += m_quad_graph->getDistanceToNext(i, m_successor_index[i]);
|
||||
}
|
||||
|
||||
|
||||
m_curve_angle =
|
||||
normalizeAngle(m_quad_graph->getAngleToNext(i, m_successor_index[i])
|
||||
-m_quad_graph->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node]) );
|
||||
|
||||
m_curve_target_speed = m_kart->getMaxSpeedOnTerrain();
|
||||
} // findCurve
|
||||
138
src/karts/controller/end_controller.hpp
Normal file
138
src/karts/controller/end_controller.hpp
Normal file
@@ -0,0 +1,138 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
//
|
||||
// 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_END_KART_HPP
|
||||
#define HEADER_END_KART_HPP
|
||||
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
class Track;
|
||||
class LinearWorld;
|
||||
class QuadGraph;
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
class ISceneNode;
|
||||
}
|
||||
}
|
||||
|
||||
class EndController : public Controller
|
||||
{
|
||||
private:
|
||||
int m_min_steps; //Minimum number of steps to check. If 0, the AI doesn't
|
||||
//even has check around the kart, if 1, it checks around
|
||||
//the kart always, and more than that will check the
|
||||
//remaining number of steps in front of the kart, always
|
||||
float m_max_handicap_accel; //The allowed maximum speed, in percentage,
|
||||
//from 0.0 to 1.0. Used only when
|
||||
//m_wait_for_players == true.
|
||||
|
||||
/*General purpose variables*/
|
||||
//The crash percentage is how much of the time the AI has been crashing,
|
||||
//if the AI has been crashing for some time, use the rescue.
|
||||
float m_crash_time;
|
||||
|
||||
float m_time_till_start; //Used to simulate a delay at the start of the
|
||||
//race, since human players don't accelerate
|
||||
//at the same time and rarely repeat the a
|
||||
//previous timing.
|
||||
|
||||
float m_curve_target_speed;
|
||||
float m_curve_angle;
|
||||
|
||||
/** Keep a pointer to the track to reduce calls */
|
||||
Track *m_track;
|
||||
|
||||
/** Keep a pointer to world. */
|
||||
LinearWorld *m_world;
|
||||
/** The current node the kart is on. This can be different from the value
|
||||
* in LinearWorld, since it takes the chosen path of the AI into account
|
||||
* (e.g. the closest point in LinearWorld might be on a branch not
|
||||
* chosen by the AI). */
|
||||
int m_track_node;
|
||||
/** The graph of qudas of this track. */
|
||||
const QuadGraph *m_quad_graph;
|
||||
|
||||
/** Which of the successors of a node was selected by the AI. */
|
||||
std::vector<int> m_successor_index;
|
||||
/** For each node in the graph this list contains the chosen next node.
|
||||
* For normal lap track without branches we always have
|
||||
* m_next_node_index[i] = (i+1) % size;
|
||||
* but if a branch is possible, the AI will select one option here.
|
||||
* If the node is not used, m_next_node_index will be -1. */
|
||||
std::vector<int> m_next_node_index;
|
||||
/** For each graph node this list contains a list of the next X
|
||||
* graph nodes. */
|
||||
std::vector<std::vector<int> > m_all_look_aheads;
|
||||
|
||||
float m_time_since_stuck;
|
||||
|
||||
int m_start_kart_crash_direction; //-1 = left, 1 = right, 0 = no crash.
|
||||
|
||||
/** Length of the kart, storing it here saves many function calls. */
|
||||
float m_kart_length;
|
||||
|
||||
/** Cache width of kart. */
|
||||
float m_kart_width;
|
||||
|
||||
/** For debugging purpose: a sphere indicating where the AI
|
||||
* is targeting at. */
|
||||
irr::scene::ISceneNode *m_debug_sphere;
|
||||
|
||||
/** The minimum steering angle at which the AI adds skidding. Lower values
|
||||
* tend to improve the line the AI is driving. This is used to adjust for
|
||||
* different AI levels.
|
||||
*/
|
||||
float m_skidding_threshold;
|
||||
|
||||
/*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
|
||||
*specific action (more like, associated with inaction).
|
||||
*/
|
||||
void handleAcceleration(const float DELTA);
|
||||
void handleSteering(float dt);
|
||||
void handleRescue(const float DELTA);
|
||||
void handleBraking();
|
||||
|
||||
/*Lower level functions not called directly from update()*/
|
||||
float steerToAngle(const size_t SECTOR, const float ANGLE);
|
||||
float steerToPoint(const Vec3 &point, float dt);
|
||||
|
||||
void checkCrashes(const int STEPS, const Vec3& pos);
|
||||
void findNonCrashingPoint(Vec3 *result);
|
||||
|
||||
float normalizeAngle(float angle);
|
||||
int calcSteps();
|
||||
void setSteering(float angle, float dt);
|
||||
void findCurve();
|
||||
|
||||
public:
|
||||
EndController(Kart *kart);
|
||||
~EndController();
|
||||
virtual void update (float delta) ;
|
||||
virtual void reset ();
|
||||
}; // EndKart
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -22,7 +22,7 @@
|
||||
//to 2 in main.cpp with quickstart and run supertuxkart with the arg -N.
|
||||
#undef AI_DEBUG
|
||||
|
||||
#include "robots/new_ai.hpp"
|
||||
#include "karts/controller/new_ai_controller.hpp"
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
# include "irrlicht.h"
|
||||
@@ -37,7 +37,6 @@
|
||||
#ifdef AI_DEBUG
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#endif
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@@ -45,13 +44,11 @@
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
NewAI::NewAI(const std::string& kart_name,
|
||||
int position, const btTransform& init_pos,
|
||||
const Track *track) :
|
||||
AutoKart( kart_name, position, init_pos )
|
||||
NewAIController::NewAIController(Kart *kart) : Controller(kart)
|
||||
{
|
||||
m_kart_length = m_kart_properties->getKartModel()->getLength();
|
||||
m_kart_width = m_kart_properties->getKartModel()->getWidth();
|
||||
m_kart = kart;
|
||||
m_kart_length = m_kart->getKartProperties()->getKartModel()->getLength();
|
||||
m_kart_width = m_kart->getKartProperties()->getKartModel()->getWidth();
|
||||
m_world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
m_quad_graph = &m_track->getQuadGraph();
|
||||
@@ -155,35 +152,35 @@ NewAI::NewAI(const std::string& kart_name,
|
||||
m_debug_left = irr_driver->getSceneManager()->addSphereSceneNode(1);
|
||||
m_debug_right = irr_driver->getSceneManager()->addSphereSceneNode(1);
|
||||
#endif
|
||||
} // NewAI
|
||||
} // NewAIController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The destructor deletes the shared TrackInfo objects if no more NewAI
|
||||
/** The destructor deletes the shared TrackInfo objects if no more NewAIController
|
||||
* instances are around.
|
||||
*/
|
||||
NewAI::~NewAI()
|
||||
NewAIController::~NewAIController()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
irr_driver->removeNode(m_debug_left );
|
||||
irr_driver->removeNode(m_debug_right );
|
||||
#endif
|
||||
} // ~NewAI
|
||||
} // ~NewAIController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//TODO: if the AI is crashing constantly, make it move backwards in a straight
|
||||
//line, then move forward while turning.
|
||||
void NewAI::update(float dt)
|
||||
void NewAIController::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls.m_look_back = false;
|
||||
m_controls.m_nitro = false;
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
|
||||
// Update the current node:
|
||||
if(m_track_node!=QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
int old_node = m_track_node;
|
||||
m_quad_graph->findRoadSector(getXYZ(), &m_track_node,
|
||||
m_quad_graph->findRoadSector(m_kart->getXYZ(), &m_track_node,
|
||||
&m_all_look_aheads[m_track_node]);
|
||||
// IF the AI is off track (or on a branch of the track it did not
|
||||
// select to be on), keep the old position.
|
||||
@@ -193,19 +190,19 @@ void NewAI::update(float dt)
|
||||
}
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(getXYZ());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
// The client does not do any AI computations.
|
||||
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
|
||||
{
|
||||
AutoKart::update(dt);
|
||||
Controller::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_world->isStartPhase() )
|
||||
{
|
||||
handleRaceStart();
|
||||
AutoKart::update(dt);
|
||||
Controller::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,18 +213,18 @@ void NewAI::update(float dt)
|
||||
steps = calcSteps();
|
||||
|
||||
computeNearestKarts();
|
||||
checkCrashes( steps, getXYZ() );
|
||||
checkCrashes( steps, m_kart->getXYZ() );
|
||||
findCurve();
|
||||
|
||||
// Special behaviour if we have a bomb attach: try to hit the kart ahead
|
||||
// of us.
|
||||
bool commands_set = false;
|
||||
if(m_handle_bomb && getAttachment()->getType()==ATTACH_BOMB &&
|
||||
if(m_handle_bomb && m_kart->getAttachment()->getType()==ATTACH_BOMB &&
|
||||
m_kart_ahead )
|
||||
{
|
||||
// Use nitro if the kart is far ahead, or faster than this kart
|
||||
m_controls.m_nitro = m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > getSpeed();
|
||||
m_controls->m_nitro = m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > m_kart->getSpeed();
|
||||
// If we are close enough, try to hit this kart
|
||||
if(m_distance_ahead<=10)
|
||||
{
|
||||
@@ -235,10 +232,10 @@ void NewAI::update(float dt)
|
||||
|
||||
// If we are faster, try to predict the point where we will hit
|
||||
// the other kart
|
||||
if(m_kart_ahead->getSpeed() < getSpeed())
|
||||
if(m_kart_ahead->getSpeed() < m_kart->getSpeed())
|
||||
{
|
||||
float time_till_hit = m_distance_ahead
|
||||
/ (getSpeed()-m_kart_ahead->getSpeed());
|
||||
/ (m_kart->getSpeed()-m_kart_ahead->getSpeed());
|
||||
target += m_kart_ahead->getVelocity()*time_till_hit;
|
||||
}
|
||||
float steer_angle = steerToPoint(m_kart_ahead->getXYZ(),
|
||||
@@ -257,13 +254,13 @@ void NewAI::update(float dt)
|
||||
handleRescue(dt);
|
||||
handleBraking();
|
||||
// If a bomb is attached, nitro might already be set.
|
||||
if(!m_controls.m_nitro)
|
||||
if(!m_controls->m_nitro)
|
||||
handleNitroAndZipper();
|
||||
}
|
||||
// If we are supposed to use nitro, but have a zipper,
|
||||
// use the zipper instead
|
||||
if(m_controls.m_nitro && m_powerup.getType()==POWERUP_ZIPPER &&
|
||||
getSpeed()>1.0f && m_zipper_time_left<=0)
|
||||
if(m_controls->m_nitro && m_kart->getPowerup()->getType()==POWERUP_ZIPPER &&
|
||||
m_kart->getSpeed()>1.0f && m_kart->getZipperTimeLeft()<=0)
|
||||
{
|
||||
// Make sure that not all AI karts use the zipper at the same
|
||||
// time in time trial at start up, so during the first 5 seconds
|
||||
@@ -271,26 +268,26 @@ void NewAI::update(float dt)
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
(m_world->getTime()<3.0f && rand()%50==1) )
|
||||
{
|
||||
m_controls.m_nitro = false;
|
||||
m_controls.m_fire = true;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->m_fire = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*And obviously general kart stuff*/
|
||||
AutoKart::update(dt);
|
||||
Controller::update(dt);
|
||||
m_collided = false;
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::handleBraking()
|
||||
void NewAIController::handleBraking()
|
||||
{
|
||||
// In follow the leader mode, the kart should brake if they are ahead of
|
||||
// the leader (and not the leader, i.e. don't have initial position 1)
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
getPosition() < m_world->getKart(0)->getPosition() &&
|
||||
getInitialPosition()>1 )
|
||||
m_kart->getPosition() < m_world->getKart(0)->getPosition() &&
|
||||
m_kart->getInitialPosition()>1 )
|
||||
{
|
||||
m_controls.m_brake = true;
|
||||
m_controls->m_brake = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -298,13 +295,13 @@ void NewAI::handleBraking()
|
||||
//We may brake if we are about to get out of the road, but only if the
|
||||
//kart is on top of the road, and if we won't slow down below a certain
|
||||
//limit.
|
||||
if (m_crashes.m_road && getVelocityLC().getY() > MIN_SPEED &&
|
||||
m_world->isOnRoad(getWorldKartId()) )
|
||||
if (m_crashes.m_road && m_kart->getVelocityLC().getY() > MIN_SPEED &&
|
||||
m_world->isOnRoad(m_kart->getWorldKartId()) )
|
||||
{
|
||||
float kart_ang_diff =
|
||||
m_quad_graph->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node])
|
||||
- getHPR().getHeading();
|
||||
- m_kart->getHPR().getHeading();
|
||||
kart_ang_diff = normalizeAngle(kart_ang_diff);
|
||||
kart_ang_diff = fabsf(kart_ang_diff);
|
||||
|
||||
@@ -318,21 +315,21 @@ void NewAI::handleBraking()
|
||||
//if the curve angle is bigger than what the kart can steer, brake
|
||||
//even if we are in the inside, because the kart would be 'thrown'
|
||||
//out of the curve.
|
||||
if(!(m_world->getDistanceToCenterForKart(getWorldKartId())
|
||||
if(!(m_world->getDistanceToCenterForKart(m_kart->getWorldKartId())
|
||||
> m_quad_graph->getNode(m_track_node).getPathWidth() *
|
||||
-CURVE_INSIDE_PERC || m_curve_angle > RAD_TO_DEGREE*getMaxSteerAngle()))
|
||||
-CURVE_INSIDE_PERC || m_curve_angle > RAD_TO_DEGREE*m_kart->getMaxSteerAngle()))
|
||||
{
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_brake = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if( m_curve_angle < -MIN_TRACK_ANGLE ) //Next curve is right
|
||||
{
|
||||
if(!(m_world->getDistanceToCenterForKart( getWorldKartId() )
|
||||
if(!(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )
|
||||
< m_quad_graph->getNode(m_track_node).getPathWidth() *
|
||||
CURVE_INSIDE_PERC || m_curve_angle < -RAD_TO_DEGREE*getMaxSteerAngle()))
|
||||
CURVE_INSIDE_PERC || m_curve_angle < -RAD_TO_DEGREE*m_kart->getMaxSteerAngle()))
|
||||
{
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_brake = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -340,23 +337,23 @@ void NewAI::handleBraking()
|
||||
//Brake if the kart's speed is bigger than the speed we need
|
||||
//to go through the curve at the widest angle, or if the kart
|
||||
//is not going straight in relation to the road.
|
||||
if(getVelocityLC().getY() > m_curve_target_speed ||
|
||||
kart_ang_diff > MIN_TRACK_ANGLE )
|
||||
if(m_kart->getVelocityLC().getY() > m_curve_target_speed ||
|
||||
kart_ang_diff > MIN_TRACK_ANGLE )
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
std::cout << "BRAKING" << std::endl;
|
||||
#endif
|
||||
m_controls.m_brake = true;
|
||||
m_controls->m_brake = true;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_brake = false;
|
||||
} // handleBraking
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::handleSteering(float dt)
|
||||
void NewAIController::handleSteering(float dt)
|
||||
{
|
||||
const int next = m_next_node_index[m_track_node];
|
||||
|
||||
@@ -366,7 +363,7 @@ void NewAI::handleSteering(float dt)
|
||||
*finite state machine.
|
||||
*/
|
||||
//Reaction to being outside of the road
|
||||
if( fabsf(m_world->getDistanceToCenterForKart( getWorldKartId() )) >
|
||||
if( fabsf(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )) >
|
||||
0.5f* m_quad_graph->getNode(m_track_node).getPathWidth()+1.0f )
|
||||
{
|
||||
steer_angle = steerToPoint(m_quad_graph->getQuad(next).getCenter(),
|
||||
@@ -395,7 +392,7 @@ void NewAI::handleSteering(float dt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_world->getDistanceToCenterForKart( getWorldKartId() ) >
|
||||
if(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() ) >
|
||||
m_world->getDistanceToCenterForKart( m_crashes.m_kart ))
|
||||
{
|
||||
steer_angle = steerToAngle(next, -M_PI*0.5f );
|
||||
@@ -450,10 +447,10 @@ void NewAI::handleSteering(float dt)
|
||||
} // handleSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
void NewAIController::handleItems( const float DELTA, const int STEPS )
|
||||
{
|
||||
m_controls.m_fire = false;
|
||||
if(isRescue() || m_powerup.getType() == POWERUP_NOTHING ) return;
|
||||
m_controls->m_fire = false;
|
||||
if(m_kart->isRescue() || m_kart->getPowerup()->getType() == POWERUP_NOTHING ) return;
|
||||
|
||||
m_time_since_last_shot += DELTA;
|
||||
|
||||
@@ -463,7 +460,7 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
{
|
||||
if( m_time_since_last_shot > 10.0f )
|
||||
{
|
||||
m_controls.m_fire = true;
|
||||
m_controls->m_fire = true;
|
||||
m_time_since_last_shot = 0.0f;
|
||||
}
|
||||
return;
|
||||
@@ -471,7 +468,7 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
|
||||
// Tactic 2: calculate
|
||||
// -------------------
|
||||
switch( m_powerup.getType() )
|
||||
switch(m_kart->getPowerup()->getType() )
|
||||
{
|
||||
case POWERUP_ZIPPER:
|
||||
// Do nothing. Further up a zipper is used if nitro should be selected,
|
||||
@@ -486,7 +483,7 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
// kart as well? I.e. only drop if the kart behind is faster? Otoh
|
||||
// this approach helps preventing an overtaken kart to overtake us
|
||||
// again.
|
||||
m_controls.m_fire = (m_distance_behind < 15.0f &&
|
||||
m_controls->m_fire = (m_distance_behind < 15.0f &&
|
||||
m_distance_behind > 3.0f ) ||
|
||||
m_time_since_last_shot>10.0f;
|
||||
if(m_distance_behind < 10.0f && m_distance_behind > 2.0f )
|
||||
@@ -496,7 +493,7 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
// towards m_kart_ahead. And some of them can fire backwards, too - which
|
||||
// isn't yet supported for AI karts.
|
||||
case POWERUP_CAKE:
|
||||
m_controls.m_fire = (m_kart_ahead && m_distance_ahead < 20.0f) ||
|
||||
m_controls->m_fire = (m_kart_ahead && m_distance_ahead < 20.0f) ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
break;
|
||||
case POWERUP_BOWLING:
|
||||
@@ -509,11 +506,11 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
!m_kart_ahead;
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls.m_fire = (fire_backwards && distance < 30.0f) ||
|
||||
(!fire_backwards && distance <10.0f) ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls.m_fire)
|
||||
m_controls.m_look_back = fire_backwards;
|
||||
m_controls->m_fire = (fire_backwards && distance < 30.0f) ||
|
||||
(!fire_backwards && distance <10.0f) ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
break;
|
||||
}
|
||||
case POWERUP_PLUNGER:
|
||||
@@ -525,26 +522,26 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
!m_kart_ahead;
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls.m_fire = distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls.m_fire)
|
||||
m_controls.m_look_back = fire_backwards;
|
||||
m_controls->m_fire = distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
break;
|
||||
}
|
||||
case POWERUP_ANVIL:
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
m_controls.m_fire = m_world->getTime()<1.0f && getPosition()>2;
|
||||
m_controls->m_fire = m_world->getTime()<1.0f && m_kart->getPosition()>2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls.m_fire = m_time_since_last_shot > 3.0f &&
|
||||
getPosition()>1;
|
||||
m_controls->m_fire = m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1;
|
||||
}
|
||||
default:
|
||||
m_controls.m_fire = true;
|
||||
m_controls->m_fire = true;
|
||||
}
|
||||
if(m_controls.m_fire) m_time_since_last_shot = 0.0f;
|
||||
if(m_controls->m_fire) m_time_since_last_shot = 0.0f;
|
||||
return;
|
||||
} // handleItems
|
||||
|
||||
@@ -553,10 +550,10 @@ void NewAI::handleItems( const float DELTA, const int STEPS )
|
||||
* 'closeness' is for now simply based on the position, i.e. if a kart is
|
||||
* more than one lap behind or ahead, it is not considered to be closest.
|
||||
*/
|
||||
void NewAI::computeNearestKarts()
|
||||
void NewAIController::computeNearestKarts()
|
||||
{
|
||||
bool need_to_check = false;
|
||||
int my_position = getPosition();
|
||||
int my_position = m_kart->getPosition();
|
||||
// See if the kart ahead has changed:
|
||||
if( ( m_kart_ahead && m_kart_ahead->getPosition()+1!=my_position ) ||
|
||||
(!m_kart_ahead && my_position>1 ) )
|
||||
@@ -569,11 +566,11 @@ void NewAI::computeNearestKarts()
|
||||
|
||||
m_kart_behind = m_kart_ahead = NULL;
|
||||
m_distance_ahead = m_distance_behind = 9999999.9f;
|
||||
float my_dist = m_world->getDistanceDownTrackForKart(getWorldKartId());
|
||||
float my_dist = m_world->getDistanceDownTrackForKart(m_kart->getWorldKartId());
|
||||
for(unsigned int i=0; i<m_world->getNumKarts(); i++)
|
||||
{
|
||||
Kart *k = m_world->getKart(i);
|
||||
if(k->isEliminated() || k==this) continue;
|
||||
if(k->isEliminated() || k==m_kart) continue;
|
||||
if(k->getPosition()==my_position+1)
|
||||
{
|
||||
m_kart_behind = k;
|
||||
@@ -593,28 +590,28 @@ void NewAI::computeNearestKarts()
|
||||
} // computeNearestKarts
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::handleAcceleration( const float DELTA )
|
||||
void NewAIController::handleAcceleration( const float DELTA )
|
||||
{
|
||||
//Do not accelerate until we have delayed the start enough
|
||||
if( m_time_till_start > 0.0f )
|
||||
{
|
||||
m_time_till_start -= DELTA;
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_controls.m_brake == true )
|
||||
if( m_controls->m_brake == true )
|
||||
{
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if(hasViewBlockedByPlunger())
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
{
|
||||
if(!(getSpeed() > getMaxSpeedOnTerrain() / 2))
|
||||
m_controls.m_accel = 0.05f;
|
||||
if(!(m_kart->getSpeed() > m_kart->getMaxSpeedOnTerrain() / 2))
|
||||
m_controls->m_accel = 0.05f;
|
||||
else
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -623,7 +620,7 @@ void NewAI::handleAcceleration( const float DELTA )
|
||||
//Find if any player is ahead of this kart
|
||||
bool player_winning = false;
|
||||
for(unsigned int i = 0; i < race_manager->getNumPlayers(); ++i )
|
||||
if( getPosition() > m_world->getPlayerKart(i)->getPosition() )
|
||||
if( m_kart->getPosition() > m_world->getPlayerKart(i)->getPosition() )
|
||||
{
|
||||
player_winning = true;
|
||||
break;
|
||||
@@ -631,16 +628,16 @@ void NewAI::handleAcceleration( const float DELTA )
|
||||
|
||||
if( player_winning )
|
||||
{
|
||||
m_controls.m_accel = m_max_handicap_accel;
|
||||
m_controls->m_accel = m_max_handicap_accel;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_controls.m_accel = 1.0f;
|
||||
m_controls->m_accel = 1.0f;
|
||||
} // handleAcceleration
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::handleRaceStart()
|
||||
void NewAIController::handleRaceStart()
|
||||
{
|
||||
//FIXME: make karts able to get a penalty for accelerating too soon
|
||||
//like players, should happen to about 20% of the karts in easy,
|
||||
@@ -656,15 +653,15 @@ void NewAI::handleRaceStart()
|
||||
} // handleRaceStart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::handleRescue(const float DELTA)
|
||||
void NewAIController::handleRescue(const float DELTA)
|
||||
{
|
||||
// check if kart is stuck
|
||||
if(getSpeed()<2.0f && !isRescue() && !m_world->isStartPhase())
|
||||
if(m_kart->getSpeed()<2.0f && !m_kart->isRescue() && !m_world->isStartPhase())
|
||||
{
|
||||
m_time_since_stuck += DELTA;
|
||||
if(m_time_since_stuck > 2.0f)
|
||||
{
|
||||
forceRescue();
|
||||
m_kart->forceRescue();
|
||||
m_time_since_stuck=0.0f;
|
||||
} // m_time_since_stuck > 2.0f
|
||||
}
|
||||
@@ -677,36 +674,36 @@ void NewAI::handleRescue(const float DELTA)
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Decides wether to use nitro or not.
|
||||
*/
|
||||
void NewAI::handleNitroAndZipper()
|
||||
void NewAIController::handleNitroAndZipper()
|
||||
{
|
||||
m_controls.m_nitro = false;
|
||||
m_controls->m_nitro = false;
|
||||
// If we are already very fast, save nitro.
|
||||
if(getSpeed() > 0.95f*getMaxSpeedOnTerrain())
|
||||
if(m_kart->getSpeed() > 0.95f*m_kart->getMaxSpeedOnTerrain())
|
||||
return;
|
||||
// Don't use nitro when the AI has a plunger in the face!
|
||||
if(hasViewBlockedByPlunger()) return;
|
||||
if(m_kart->hasViewBlockedByPlunger()) return;
|
||||
|
||||
// Don't use nitro if the kart doesn't have any or is not on ground.
|
||||
if(!isOnGround() || hasFinishedRace()) return;
|
||||
if(!m_kart->isOnGround() || m_kart->hasFinishedRace()) return;
|
||||
|
||||
// Don't compute nitro usage if we don't have nitro or are not supposed
|
||||
// to use it, and we don't have a zipper or are not supposed to use
|
||||
// it (calculated).
|
||||
if( (getEnergy()==0 || m_nitro_level==NITRO_NONE) &&
|
||||
(m_powerup.getType()!=POWERUP_ZIPPER || m_item_tactic==IT_TEN_SECONDS) )
|
||||
if( (m_kart->getEnergy()==0 || m_nitro_level==NITRO_NONE) &&
|
||||
(m_kart->getPowerup()->getType()!=POWERUP_ZIPPER || m_item_tactic==IT_TEN_SECONDS) )
|
||||
return;
|
||||
|
||||
// If a parachute or anvil is attached, the nitro doesn't give much
|
||||
// benefit. Better wait till later.
|
||||
const bool has_slowdown_attachment =
|
||||
m_attachment.getType()==ATTACH_PARACHUTE ||
|
||||
m_attachment.getType()==ATTACH_ANVIL;
|
||||
m_kart->getAttachment()->getType()==ATTACH_PARACHUTE ||
|
||||
m_kart->getAttachment()->getType()==ATTACH_ANVIL;
|
||||
if(has_slowdown_attachment) return;
|
||||
|
||||
// If the kart is very slow (e.g. after rescue), use nitro
|
||||
if(getSpeed()<5)
|
||||
if(m_kart->getSpeed()<5)
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -714,9 +711,9 @@ void NewAI::handleNitroAndZipper()
|
||||
// (i.e. more than 2) nitro, use it.
|
||||
// -------------------------------------------------
|
||||
const unsigned int num_karts = m_world->getCurrentNumKarts();
|
||||
if(getPosition()== (int)num_karts && getEnergy()>2.0f)
|
||||
if(m_kart->getPosition()== (int)num_karts && m_kart->getEnergy()>2.0f)
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -724,13 +721,13 @@ void NewAI::handleNitroAndZipper()
|
||||
// anyway. Since the kart is faster with nitro, estimate a 50% time
|
||||
// decrease (additionally some nitro will be saved when top speed
|
||||
// is reached).
|
||||
if(m_world->getLapForKart(getWorldKartId())==race_manager->getNumLaps()-1 &&
|
||||
if(m_world->getLapForKart(m_kart->getWorldKartId())==race_manager->getNumLaps()-1 &&
|
||||
m_nitro_level == NITRO_ALL)
|
||||
{
|
||||
float finish = m_world->getEstimatedFinishTime(getWorldKartId());
|
||||
if( 1.5f*getEnergy() >= finish - m_world->getTime() )
|
||||
float finish = m_world->getEstimatedFinishTime(m_kart->getWorldKartId());
|
||||
if( 1.5f*m_kart->getEnergy() >= finish - m_world->getTime() )
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -744,33 +741,33 @@ void NewAI::handleNitroAndZipper()
|
||||
// --------------------------------------------------
|
||||
if(m_kart_ahead &&
|
||||
m_distance_ahead < overtake_distance &&
|
||||
m_kart_ahead->getSpeed()+5.0f > getSpeed() )
|
||||
m_kart_ahead->getSpeed()+5.0f > m_kart->getSpeed() )
|
||||
{
|
||||
m_controls.m_nitro = true;
|
||||
m_controls->m_nitro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_kart_behind &&
|
||||
m_distance_behind < overtake_distance &&
|
||||
m_kart_behind->getSpeed() > getSpeed() )
|
||||
m_kart_behind->getSpeed() > m_kart->getSpeed() )
|
||||
{
|
||||
// Only prevent overtaking on highest level
|
||||
m_controls.m_nitro = m_nitro_level==NITRO_ALL;
|
||||
m_controls->m_nitro = m_nitro_level==NITRO_ALL;
|
||||
return;
|
||||
}
|
||||
|
||||
} // handleNitroAndZipper
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float NewAI::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
float NewAIController::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
{
|
||||
float angle = m_quad_graph->getAngleToNext(SECTOR,
|
||||
m_successor_index[SECTOR]);
|
||||
|
||||
//Desired angle minus current angle equals how many angles to turn
|
||||
float steer_angle = angle - getHPR().getHeading();
|
||||
float steer_angle = angle - m_kart->getHPR().getHeading();
|
||||
|
||||
if(hasViewBlockedByPlunger())
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
steer_angle += ANGLE/5;
|
||||
else
|
||||
steer_angle += ANGLE;
|
||||
@@ -787,20 +784,20 @@ float NewAI::steerToAngle(const size_t SECTOR, const float ANGLE)
|
||||
* \param point Point to steer towards.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
float NewAI::steerToPoint(const Vec3 &point, float dt)
|
||||
float NewAIController::steerToPoint(const Vec3 &point, float dt)
|
||||
{
|
||||
// No sense steering if we are not driving.
|
||||
if(getSpeed()==0) return 0.0f;
|
||||
const float dx = point.getX() - getXYZ().getX();
|
||||
const float dy = point.getY() - getXYZ().getY();
|
||||
if(m_kart->getSpeed()==0) return 0.0f;
|
||||
const float dx = point.getX() - m_kart->getXYZ().getX();
|
||||
const float dy = point.getY() - m_kart->getXYZ().getY();
|
||||
/** Angle from the kart position to the point in world coordinates. */
|
||||
float theta = -atan2(dx, dy);
|
||||
|
||||
// Angle is the point is relative to the heading - but take the current
|
||||
// angular velocity into account, too. The value is multiplied by two
|
||||
// to avoid 'oversteering' - experimentally found.
|
||||
float angle_2_point = theta - getHPR().getHeading()
|
||||
- dt*m_body->getAngularVelocity().getZ()*2.0f;
|
||||
float angle_2_point = theta - m_kart->getHPR().getHeading()
|
||||
- dt*m_kart->getBody()->getAngularVelocity().getZ()*2.0f;
|
||||
angle_2_point = normalizeAngle(angle_2_point);
|
||||
if(fabsf(angle_2_point)<0.1) return 0.0f;
|
||||
|
||||
@@ -816,8 +813,8 @@ float NewAI::steerToPoint(const Vec3 &point, float dt)
|
||||
* computed, and from that the turn radius, and then the steer angle.
|
||||
* (note: the 2*M_PI can be removed from the computations)
|
||||
*/
|
||||
float radius = dt*getSpeed()/angle_2_point;
|
||||
float sin_steer_angle = m_kart_properties->getWheelBase()/radius;
|
||||
float radius = dt*m_kart->getSpeed()/angle_2_point;
|
||||
float sin_steer_angle = m_kart->getKartProperties()->getWheelBase()/radius;
|
||||
#ifdef DEBUG_OUTPUT
|
||||
printf("theta %f a2p %f angularv %f radius %f ssa %f\n",
|
||||
theta, angle_2_point, m_body->getAngularVelocity().getZ(),
|
||||
@@ -825,14 +822,14 @@ float NewAI::steerToPoint(const Vec3 &point, float dt)
|
||||
#endif
|
||||
// Add 0.1 since rouding errors will otherwise result in the kart
|
||||
// not using drifting.
|
||||
if(sin_steer_angle <= -1.0f) return -getMaxSteerAngle()*m_skidding_threshold-0.1f;
|
||||
if(sin_steer_angle >= 1.0f) return getMaxSteerAngle()*m_skidding_threshold+0.1f;
|
||||
if(sin_steer_angle <= -1.0f) return -m_kart->getMaxSteerAngle()*m_skidding_threshold-0.1f;
|
||||
if(sin_steer_angle >= 1.0f) return m_kart->getMaxSteerAngle()*m_skidding_threshold+0.1f;
|
||||
float steer_angle = asin(sin_steer_angle);
|
||||
return steer_angle;
|
||||
} // steerToPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
void NewAIController::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
{
|
||||
//Right now there are 2 kind of 'crashes': with other karts and another
|
||||
//with the track. The sight line is used to find if the karts crash with
|
||||
@@ -844,7 +841,7 @@ void NewAI::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
const size_t NUM_KARTS = m_world->getNumKarts();
|
||||
|
||||
//Protection against having vel_normal with nan values
|
||||
const Vec3 &VEL = getVelocity();
|
||||
const Vec3 &VEL = m_kart->getVelocity();
|
||||
Vec3 vel_normal(VEL.getX(), VEL.getY(), 0.0);
|
||||
float speed=vel_normal.length();
|
||||
// If the velocity is zero, no sense in checking for crashes in time
|
||||
@@ -867,10 +864,10 @@ void NewAI::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
for( unsigned int j = 0; j < NUM_KARTS; ++j )
|
||||
{
|
||||
const Kart* kart = m_world->getKart(j);
|
||||
if(kart==this||kart->isEliminated()) continue; // ignore eliminated karts
|
||||
if(kart==m_kart||kart->isEliminated()) continue; // ignore eliminated karts
|
||||
const Kart *other_kart = m_world->getKart(j);
|
||||
// Ignore karts ahead that are faster than this kart.
|
||||
if(getVelocityLC().getY() < other_kart->getVelocityLC().getY())
|
||||
if(m_kart->getVelocityLC().getY() < other_kart->getVelocityLC().getY())
|
||||
continue;
|
||||
Vec3 other_kart_xyz = other_kart->getXYZ() + other_kart->getVelocity()*(i*dt);
|
||||
float kart_distance = (step_coord - other_kart_xyz).length_2d();
|
||||
@@ -895,10 +892,10 @@ void NewAI::checkCrashes( const int STEPS, const Vec3& pos )
|
||||
} // checkCrashes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float NewAI::findNonCrashingAngle()
|
||||
float NewAIController::findNonCrashingAngle()
|
||||
{
|
||||
unsigned int current_sector = m_track_node;
|
||||
const Vec3 &xyz = getXYZ();
|
||||
const Vec3 &xyz = m_kart->getXYZ();
|
||||
const Quad &q = m_quad_graph->getQuad(current_sector);
|
||||
const Vec3 &right = q[2];
|
||||
const Vec3 &left = q[3];
|
||||
@@ -907,10 +904,10 @@ float NewAI::findNonCrashingAngle()
|
||||
|
||||
float very_right = -atan2(right.getX()-xyz.getX(),
|
||||
right.getY()-xyz.getY())
|
||||
- getHPR().getHeading();
|
||||
- m_kart->getHPR().getHeading();
|
||||
float very_left = -atan2(left.getX()-xyz.getX(),
|
||||
left.getY()-xyz.getY())
|
||||
- getHPR().getHeading();
|
||||
- m_kart->getHPR().getHeading();
|
||||
very_left = normalizeAngle(very_left);
|
||||
very_right = normalizeAngle(very_right);
|
||||
float dist = 0;
|
||||
@@ -923,10 +920,10 @@ float NewAI::findNonCrashingAngle()
|
||||
|
||||
float angle_right = -atan2(right.getX()-xyz.getX(),
|
||||
right.getY()-xyz.getY())
|
||||
- getHPR().getHeading();
|
||||
- m_kart->getHPR().getHeading();
|
||||
float angle_left = -atan2(left.getX()-xyz.getX(),
|
||||
left.getY()-xyz.getY())
|
||||
- getHPR().getHeading();
|
||||
- m_kart->getHPR().getHeading();
|
||||
angle_left = normalizeAngle(angle_left);
|
||||
angle_right = normalizeAngle(angle_right);
|
||||
|
||||
@@ -964,7 +961,7 @@ float NewAI::findNonCrashingAngle()
|
||||
* the two edges of the track is closest to the next curve after wards,
|
||||
* and return the position of that edge.
|
||||
*/
|
||||
void NewAI::findNonCrashingPoint(Vec3 *result)
|
||||
void NewAIController::findNonCrashingPoint(Vec3 *result)
|
||||
{
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
@@ -982,7 +979,7 @@ void NewAI::findNonCrashingPoint(Vec3 *result)
|
||||
target_sector = m_next_node_index[sector];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = m_quad_graph->getQuad(target_sector).getCenter() - getXYZ();
|
||||
direction = m_quad_graph->getQuad(target_sector).getCenter() - m_kart->getXYZ();
|
||||
|
||||
float len=direction.length_2d();
|
||||
steps = int( len / m_kart_length );
|
||||
@@ -997,7 +994,7 @@ void NewAI::findNonCrashingPoint(Vec3 *result)
|
||||
//Test if we crash if we drive towards the target sector
|
||||
for( int i = 2; i < steps; ++i )
|
||||
{
|
||||
step_coord = getXYZ()+direction*m_kart_length * float(i);
|
||||
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
|
||||
|
||||
m_quad_graph->spatialToTrack(&step_track_coord, step_coord,
|
||||
sector );
|
||||
@@ -1017,11 +1014,11 @@ void NewAI::findNonCrashingPoint(Vec3 *result)
|
||||
} // findNonCrashingPoint
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NewAI::reset()
|
||||
void NewAIController::reset()
|
||||
{
|
||||
m_time_since_last_shot = 0.0f;
|
||||
m_start_kart_crash_direction = 0;
|
||||
m_curve_target_speed = getMaxSpeedOnTerrain();
|
||||
m_curve_target_speed = m_kart->getMaxSpeedOnTerrain();
|
||||
m_curve_angle = 0.0;
|
||||
m_time_till_start = -1.0f;
|
||||
m_crash_time = 0.0f;
|
||||
@@ -1032,19 +1029,19 @@ void NewAI::reset()
|
||||
m_kart_behind = NULL;
|
||||
m_distance_behind = 0.0f;
|
||||
m_track_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
AutoKart::reset();
|
||||
m_quad_graph->findRoadSector(getXYZ(), &m_track_node);
|
||||
Controller::reset();
|
||||
m_quad_graph->findRoadSector(m_kart->getXYZ(), &m_track_node);
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
fprintf(stderr, "Invalid starting position for '%s' - not on track - can be ignored.\n",
|
||||
getIdent().c_str());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(getXYZ());
|
||||
m_kart->getIdent().c_str());
|
||||
m_track_node = m_quad_graph->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
inline float NewAI::normalizeAngle(float angle)
|
||||
inline float NewAIController::normalizeAngle(float angle)
|
||||
{
|
||||
while( angle > 2*M_PI ) angle -= 2*M_PI;
|
||||
while( angle < -2*M_PI ) angle += 2*M_PI;
|
||||
@@ -1060,9 +1057,9 @@ inline float NewAI::normalizeAngle(float angle)
|
||||
* and gets the number of steps to use for the sight line of the kart.
|
||||
* The calling sequence guarantees that m_future_sector is not UNKNOWN.
|
||||
*/
|
||||
int NewAI::calcSteps()
|
||||
int NewAIController::calcSteps()
|
||||
{
|
||||
int steps = int( getVelocityLC().getY() / m_kart_length );
|
||||
int steps = int( m_kart->getVelocityLC().getY() / m_kart_length );
|
||||
if( steps < m_min_steps ) steps = m_min_steps;
|
||||
|
||||
//Increase the steps depending on the width, if we steering hard,
|
||||
@@ -1072,7 +1069,7 @@ int NewAI::calcSteps()
|
||||
// for more steps if we hit another kart?? If we steer hard,
|
||||
// the approximation used (pos + velocity*dt) will be even
|
||||
// worse, since it doesn't take steering into account.
|
||||
if( fabsf(m_controls.m_steer) > 0.95 )
|
||||
if( fabsf(m_controls->m_steer) > 0.95 )
|
||||
{
|
||||
const int WIDTH_STEPS =
|
||||
(int)( m_quad_graph->getNode(m_future_sector).getPathWidth()
|
||||
@@ -1095,32 +1092,32 @@ int NewAI::calcSteps()
|
||||
* \param angle Steering angle.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
void NewAI::setSteering(float angle, float dt)
|
||||
void NewAIController::setSteering(float angle, float dt)
|
||||
{
|
||||
float steer_fraction = angle / getMaxSteerAngle();
|
||||
m_controls.m_drift = fabsf(steer_fraction)>=m_skidding_threshold;
|
||||
if(hasViewBlockedByPlunger()) m_controls.m_drift = false;
|
||||
float old_steer = m_controls.m_steer;
|
||||
float steer_fraction = angle / m_kart->getMaxSteerAngle();
|
||||
m_controls->m_drift = fabsf(steer_fraction)>=m_skidding_threshold;
|
||||
if(m_kart->hasViewBlockedByPlunger()) m_controls->m_drift = false;
|
||||
float old_steer = m_controls->m_steer;
|
||||
|
||||
if (steer_fraction > 1.0f) steer_fraction = 1.0f;
|
||||
else if(steer_fraction < -1.0f) steer_fraction = -1.0f;
|
||||
|
||||
if(hasViewBlockedByPlunger())
|
||||
if(m_kart->hasViewBlockedByPlunger())
|
||||
{
|
||||
if (steer_fraction > 0.5f) steer_fraction = 0.5f;
|
||||
else if(steer_fraction < -0.5f) steer_fraction = -0.5f;
|
||||
}
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_kart_properties->getTimeFullSteerAI();
|
||||
float max_steer_change = dt/m_kart->getKartProperties()->getTimeFullSteerAI();
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls.m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls.m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
m_controls->m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change;
|
||||
}
|
||||
} // setSteering
|
||||
@@ -1132,11 +1129,11 @@ void NewAI::setSteering(float angle, float dt)
|
||||
*
|
||||
* The number of sectors that form the curve is dependant on the kart's speed.
|
||||
*/
|
||||
void NewAI::findCurve()
|
||||
void NewAIController::findCurve()
|
||||
{
|
||||
float total_dist = 0.0f;
|
||||
int i;
|
||||
for(i = m_track_node; total_dist < getVelocityLC().getY();
|
||||
for(i = m_track_node; total_dist < m_kart->getVelocityLC().getY();
|
||||
i = m_next_node_index[i])
|
||||
{
|
||||
total_dist += m_quad_graph->getDistanceToNext(i, m_successor_index[i]);
|
||||
@@ -1148,5 +1145,5 @@ void NewAI::findCurve()
|
||||
-m_quad_graph->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node]) );
|
||||
|
||||
m_curve_target_speed = getMaxSpeedOnTerrain();
|
||||
m_curve_target_speed = m_kart->getMaxSpeedOnTerrain();
|
||||
} // findCurve
|
||||
@@ -16,10 +16,10 @@
|
||||
// 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_NEWAI_HPP
|
||||
#define HEADER_NEWAI_HPP
|
||||
#ifndef HEADER_NEWAI_CONTROLLER_HPP
|
||||
#define HEADER_NEWAI_CONTROLLER_HPP
|
||||
|
||||
#include "karts/auto_kart.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
/* third coord won't be used */
|
||||
@@ -35,7 +35,7 @@ namespace irr
|
||||
}
|
||||
}
|
||||
|
||||
class NewAI : public AutoKart
|
||||
class NewAIController : public Controller
|
||||
{
|
||||
private:
|
||||
enum FallbackTactic
|
||||
@@ -194,15 +194,14 @@ private:
|
||||
void findCurve();
|
||||
|
||||
public:
|
||||
NewAI(const std::string& kart_name, int position,
|
||||
const btTransform& init_pos, const Track *track);
|
||||
~NewAI();
|
||||
void update (float delta) ;
|
||||
void reset ();
|
||||
NewAIController(Kart *kart);
|
||||
virtual ~NewAIController();
|
||||
virtual void update (float delta) ;
|
||||
virtual void reset ();
|
||||
virtual void crashed (Kart *k) {if(k) m_collided = true;};
|
||||
virtual const irr::core::stringw& getName() const
|
||||
virtual const irr::core::stringw& getN() const
|
||||
{
|
||||
static irr::core::stringw name = Kart::getName()+irr::core::stringw("(NewAI)");
|
||||
static irr::core::stringw name("(NewAI)");
|
||||
return name;
|
||||
} // getName
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
// 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/player_kart.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "audio/sfx_manager.hpp"
|
||||
@@ -38,17 +38,17 @@
|
||||
* \param position The starting position (1 to n).
|
||||
* \param player The player to which this kart belongs.
|
||||
* \param init_pos The start coordinates and heading of the kart.
|
||||
* \param player_index Index of the player akrt.
|
||||
* \param player_index Index of the player kart.
|
||||
*/
|
||||
PlayerKart::PlayerKart(const std::string& kart_name, int position,
|
||||
ActivePlayer *player, const btTransform& init_pos,
|
||||
unsigned int player_index) :
|
||||
Kart(kart_name, position, init_pos)
|
||||
PlayerController::PlayerController(Kart *kart, ActivePlayer *player,
|
||||
unsigned int player_index)
|
||||
: Controller(kart)
|
||||
{
|
||||
m_player = player;
|
||||
m_player->setKart(kart);
|
||||
m_penalty_time = 0.0f;
|
||||
setCamera(new Camera(player_index, this));
|
||||
m_camera->setMode(Camera::CM_NORMAL);
|
||||
kart->setCamera(new Camera(player_index, kart));
|
||||
kart->getCamera()->setMode(Camera::CM_NORMAL);
|
||||
|
||||
m_bzzt_sound = sfx_manager->newSFX(SFXManager::SOUND_BZZT );
|
||||
m_wee_sound = sfx_manager->newSFX(SFXManager::SOUND_WEE );
|
||||
@@ -57,25 +57,24 @@ PlayerKart::PlayerKart(const std::string& kart_name, int position,
|
||||
m_full_sound = sfx_manager->newSFX(SFXManager::SOUND_FULL );
|
||||
|
||||
reset();
|
||||
} // PlayerKart
|
||||
} // PlayerController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Destructor for a player kart.
|
||||
*/
|
||||
PlayerKart::~PlayerKart()
|
||||
PlayerController::~PlayerController()
|
||||
{
|
||||
delete m_camera;
|
||||
sfx_manager->deleteSFX(m_bzzt_sound);
|
||||
sfx_manager->deleteSFX(m_wee_sound );
|
||||
sfx_manager->deleteSFX(m_ugh_sound );
|
||||
sfx_manager->deleteSFX(m_grab_sound);
|
||||
sfx_manager->deleteSFX(m_full_sound);
|
||||
} // ~PlayerKart
|
||||
} // ~PlayerController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Resets the player kart for a new or restarted race.
|
||||
*/
|
||||
void PlayerKart::reset()
|
||||
void PlayerController::reset()
|
||||
{
|
||||
m_steer_val_l = 0;
|
||||
m_steer_val_r = 0;
|
||||
@@ -83,8 +82,7 @@ void PlayerKart::reset()
|
||||
m_prev_brake = 0;
|
||||
m_prev_accel = 0;
|
||||
m_penalty_time = 0;
|
||||
Kart::reset();
|
||||
m_camera->reset();
|
||||
Controller::reset();
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -92,7 +90,7 @@ void PlayerKart::reset()
|
||||
* avoid that any keys pressed at the time the menu is opened are still
|
||||
* considered to be pressed.
|
||||
*/
|
||||
void PlayerKart::resetInputState()
|
||||
void PlayerController::resetInputState()
|
||||
{
|
||||
m_steer_val_l = 0;
|
||||
m_steer_val_r = 0;
|
||||
@@ -114,7 +112,7 @@ void PlayerKart::resetInputState()
|
||||
* and if it's 0 it indicates that the corresponding button
|
||||
* was released.
|
||||
*/
|
||||
void PlayerKart::action(PlayerAction action, int value)
|
||||
void PlayerController::action(PlayerAction action, int value)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
@@ -138,42 +136,42 @@ void PlayerKart::action(PlayerAction action, int value)
|
||||
m_prev_accel = value;
|
||||
if(value)
|
||||
{
|
||||
m_controls.m_accel = value/32768.0f;
|
||||
m_controls.m_brake = false;
|
||||
m_controls->m_accel = value/32768.0f;
|
||||
m_controls->m_brake = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls.m_brake = m_prev_brake;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->m_brake = m_prev_brake;
|
||||
}
|
||||
break;
|
||||
case PA_BRAKE:
|
||||
m_prev_brake = value!=0;
|
||||
if(value)
|
||||
{
|
||||
m_controls.m_brake = true;
|
||||
m_controls.m_accel = 0.0f;
|
||||
m_controls->m_brake = true;
|
||||
m_controls->m_accel = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls.m_brake = false;
|
||||
m_controls.m_accel = m_prev_accel/32768.0f;
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = m_prev_accel/32768.0f;
|
||||
}
|
||||
break;
|
||||
case PA_NITRO:
|
||||
m_controls.m_nitro = (value!=0);
|
||||
m_controls->m_nitro = (value!=0);
|
||||
break;
|
||||
case PA_RESCUE:
|
||||
m_controls.m_rescue = (value!=0);
|
||||
m_controls->m_rescue = (value!=0);
|
||||
break;
|
||||
case PA_FIRE:
|
||||
m_controls.m_fire = (value!=0);
|
||||
m_controls->m_fire = (value!=0);
|
||||
break;
|
||||
case PA_LOOK_BACK:
|
||||
m_controls.m_look_back = (value!=0);
|
||||
m_controls->m_look_back = (value!=0);
|
||||
break;
|
||||
case PA_DRIFT:
|
||||
m_controls.m_drift = (value!=0);
|
||||
m_controls->m_drift = (value!=0);
|
||||
break;
|
||||
default: assert(false);
|
||||
}
|
||||
@@ -183,57 +181,56 @@ void PlayerKart::action(PlayerAction action, int value)
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Handles steering for a player kart.
|
||||
*/
|
||||
void PlayerKart::steer(float dt, int steer_val)
|
||||
void PlayerController::steer(float dt, int steer_val)
|
||||
{
|
||||
if(UserConfigParams::m_gamepad_debug)
|
||||
{
|
||||
printf("steering: steer_val %d ", steer_val);
|
||||
}
|
||||
const float STEER_CHANGE = dt/getTimeFullSteer(); // amount the steering is changed
|
||||
const float STEER_CHANGE = dt/m_kart->getTimeFullSteer(); // amount the steering is changed
|
||||
if (steer_val < 0)
|
||||
{
|
||||
// If we got analog values do not cumulate.
|
||||
if (steer_val > -32767)
|
||||
m_controls.m_steer = -steer_val/32767.0f;
|
||||
m_controls->m_steer = -steer_val/32767.0f;
|
||||
else
|
||||
m_controls.m_steer += STEER_CHANGE;
|
||||
m_controls->m_steer += STEER_CHANGE;
|
||||
}
|
||||
else if(steer_val > 0)
|
||||
{
|
||||
// If we got analog values do not cumulate.
|
||||
if (steer_val < 32767)
|
||||
m_controls.m_steer = -steer_val/32767.0f;
|
||||
m_controls->m_steer = -steer_val/32767.0f;
|
||||
else
|
||||
m_controls.m_steer -= STEER_CHANGE;
|
||||
m_controls->m_steer -= STEER_CHANGE;
|
||||
}
|
||||
else
|
||||
{ // no key is pressed
|
||||
if(m_controls.m_steer>0.0f)
|
||||
if(m_controls->m_steer>0.0f)
|
||||
{
|
||||
m_controls.m_steer -= STEER_CHANGE;
|
||||
if(m_controls.m_steer<0.0f) m_controls.m_steer=0.0f;
|
||||
m_controls->m_steer -= STEER_CHANGE;
|
||||
if(m_controls->m_steer<0.0f) m_controls->m_steer=0.0f;
|
||||
}
|
||||
else
|
||||
{ // m_controls.m_steer<=0.0f;
|
||||
m_controls.m_steer += STEER_CHANGE;
|
||||
if(m_controls.m_steer>0.0f) m_controls.m_steer=0.0f;
|
||||
} // if m_controls.m_steer<=0.0f
|
||||
{ // m_controls->m_steer<=0.0f;
|
||||
m_controls->m_steer += STEER_CHANGE;
|
||||
if(m_controls->m_steer>0.0f) m_controls->m_steer=0.0f;
|
||||
} // if m_controls->m_steer<=0.0f
|
||||
} // no key is pressed
|
||||
if(UserConfigParams::m_gamepad_debug)
|
||||
{
|
||||
printf(" set to: %f\n", m_controls.m_steer);
|
||||
printf(" set to: %f\n", m_controls->m_steer);
|
||||
}
|
||||
|
||||
m_controls.m_steer = std::min(1.0f, std::max(-1.0f, m_controls.m_steer));
|
||||
m_controls->m_steer = std::min(1.0f, std::max(-1.0f, m_controls->m_steer));
|
||||
|
||||
} // steer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the player kart, called once each timestep.
|
||||
*/
|
||||
void PlayerKart::update(float dt)
|
||||
void PlayerController::update(float dt)
|
||||
{
|
||||
m_camera->update(dt);
|
||||
// Don't do steering if it's replay. In position only replay it doesn't
|
||||
// matter, but if it's physics replay the gradual steering causes
|
||||
// incorrect results, since the stored values are already adjusted.
|
||||
@@ -242,8 +239,8 @@ void PlayerKart::update(float dt)
|
||||
|
||||
if(World::getWorld()->isStartPhase())
|
||||
{
|
||||
if(m_controls.m_accel || m_controls.m_brake ||
|
||||
m_controls.m_fire || m_controls.m_nitro || m_controls.m_drift)
|
||||
if(m_controls->m_accel || m_controls->m_brake ||
|
||||
m_controls->m_fire || m_controls->m_nitro || m_controls->m_drift)
|
||||
{
|
||||
if(m_penalty_time == 0.0)//eliminates machine-gun-effect for SOUND_BZZT
|
||||
{
|
||||
@@ -251,8 +248,7 @@ void PlayerKart::update(float dt)
|
||||
RaceGUI* m=World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
{
|
||||
m->addMessage(_("Penalty time!!"),
|
||||
this, 2.0f, 60);
|
||||
m->addMessage(_("Penalty time!!"), m_kart, 2.0f, 60);
|
||||
}
|
||||
m_bzzt_sound->play();
|
||||
} // if penalty_time = 0
|
||||
@@ -262,7 +258,7 @@ void PlayerKart::update(float dt)
|
||||
// The call to update is necessary here (even though the kart
|
||||
// shouldn't actually change) to update m_transform. Otherwise
|
||||
// the camera gets the wrong position.
|
||||
Kart::update(dt);
|
||||
Controller::update(dt);
|
||||
}
|
||||
return;
|
||||
} // if isStartPhase
|
||||
@@ -273,52 +269,45 @@ void PlayerKart::update(float dt)
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_controls.m_fire && !isRescue())
|
||||
if ( m_controls->m_fire && !m_kart->isRescue())
|
||||
{
|
||||
if (m_powerup.getType()==POWERUP_NOTHING)
|
||||
Kart::beep();
|
||||
if (m_kart->getPowerup()->getType()==POWERUP_NOTHING)
|
||||
m_kart->beep();
|
||||
}
|
||||
|
||||
// Camera looks back when reversing
|
||||
if(m_camera->getMode()!=Camera::CM_FINAL)
|
||||
if(m_kart->getCamera()->getMode()!=Camera::CM_FINAL)
|
||||
{
|
||||
// look backward when the player requests or
|
||||
// if automatic reverse camera is active
|
||||
if (m_controls.m_look_back || (UserConfigParams::m_reverse_look_threshold>0 && Kart::getSpeed()<-UserConfigParams::m_reverse_look_threshold))
|
||||
m_camera->setMode(Camera::CM_REVERSE);
|
||||
if (m_controls->m_look_back || (UserConfigParams::m_reverse_look_threshold>0 &&
|
||||
m_kart->getSpeed()<-UserConfigParams::m_reverse_look_threshold))
|
||||
m_kart->getCamera()->setMode(Camera::CM_REVERSE);
|
||||
else
|
||||
m_camera->setMode(Camera::CM_NORMAL);
|
||||
m_kart->getCamera()->setMode(Camera::CM_NORMAL);
|
||||
}
|
||||
|
||||
// We can't restrict rescue to fulfil isOnGround() (which would be more like
|
||||
// MK), since e.g. in the City track it is possible for the kart to end
|
||||
// up sitting on a brick wall, with all wheels in the air :((
|
||||
if ( m_controls.m_rescue )
|
||||
if ( m_controls->m_rescue )
|
||||
{
|
||||
forceRescue();
|
||||
m_controls.m_rescue=false;
|
||||
m_kart->forceRescue();
|
||||
m_controls->m_rescue=false;
|
||||
}
|
||||
if (isRescue() && m_attachment.getType() != ATTACH_TINYTUX)
|
||||
if (m_kart->isRescue() && m_kart->getAttachment()->getType() != ATTACH_TINYTUX)
|
||||
{
|
||||
m_bzzt_sound->play();
|
||||
}
|
||||
Kart::update(dt);
|
||||
Controller::update(dt);
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Marks the kart as having had a crash.
|
||||
*/
|
||||
void PlayerKart::crashed(Kart *kart)
|
||||
{
|
||||
Kart::crashed(kart);
|
||||
} // crashed
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Checks if the kart was overtaken, and if so plays a sound
|
||||
*/
|
||||
void PlayerKart::setPosition(int p)
|
||||
void PlayerController::setPosition(int p)
|
||||
{
|
||||
if(getPosition()<p)
|
||||
if(m_kart->getPosition()<p)
|
||||
{
|
||||
World *world = World::getWorld();
|
||||
//have the kart that did the passing beep.
|
||||
@@ -333,36 +322,33 @@ void PlayerKart::setPosition(int p)
|
||||
}
|
||||
}
|
||||
}
|
||||
Kart::setPosition(p);
|
||||
} // setPosition
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when a kart finishes race.
|
||||
* /param time Finishing time for this kart.
|
||||
*/
|
||||
void PlayerKart::raceFinished(float time)
|
||||
void PlayerController::finishedRace(float time)
|
||||
{
|
||||
Kart::raceFinished(time);
|
||||
// Set race over camera (but not in follow the leader mode, since the kart
|
||||
// will most likely not be at the starting line at the end of the race
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
m_camera->setMode(Camera::CM_FINAL);
|
||||
m_kart->getCamera()->setMode(Camera::CM_FINAL);
|
||||
|
||||
RaceGUI* m=World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
{
|
||||
m->addMessage(getPosition()==1 ? _("You won the race!")
|
||||
: _("You finished the race!") ,
|
||||
this, 2.0f, 60);
|
||||
m->addMessage(m_kart->getPosition()==1 ? _("You won the race!")
|
||||
: _("You finished the race!") ,
|
||||
m_kart, 2.0f, 60);
|
||||
}
|
||||
} // raceFinished
|
||||
} // finishedRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when a kart hits or uses a zipper.
|
||||
*/
|
||||
void PlayerKart::handleZipper()
|
||||
void PlayerController::handleZipper()
|
||||
{
|
||||
Kart::handleZipper();
|
||||
m_wee_sound->play();
|
||||
} // handleZipper
|
||||
|
||||
@@ -376,14 +362,10 @@ void PlayerKart::handleZipper()
|
||||
* let the server determine the powerup/attachment for
|
||||
* the clients.
|
||||
*/
|
||||
void PlayerKart::collectedItem(const Item &item, int add_info)
|
||||
void PlayerController::collectedItem(const Item &item, int add_info, float old_energy)
|
||||
{
|
||||
// FIXME - how does the old item relate to the total amount of items?
|
||||
const float old_energy= getEnergy();
|
||||
Kart::collectedItem(item, add_info);
|
||||
|
||||
if(old_energy < MAX_ITEMS_COLLECTED &&
|
||||
getEnergy() == MAX_ITEMS_COLLECTED)
|
||||
m_kart->getEnergy() == MAX_ITEMS_COLLECTED)
|
||||
{
|
||||
m_full_sound->play();
|
||||
}
|
||||
@@ -23,14 +23,14 @@
|
||||
#define HEADER_PLAYERKART_HPP
|
||||
|
||||
#include "config/player.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
|
||||
class SFXBase;
|
||||
class Player;
|
||||
|
||||
/** PlayerKart manages control events from the player and moves
|
||||
them to the Kart */
|
||||
class PlayerKart : public Kart
|
||||
class PlayerController : public Controller
|
||||
{
|
||||
private:
|
||||
int m_steer_val, m_steer_val_l, m_steer_val_r;
|
||||
@@ -48,22 +48,20 @@ private:
|
||||
|
||||
void steer(float, int);
|
||||
public:
|
||||
PlayerKart(const std::string& kart_name,
|
||||
int position, ActivePlayer *_player,
|
||||
const btTransform& init_pos,
|
||||
unsigned int player_index);
|
||||
~PlayerKart ();
|
||||
PlayerController (Kart *kart, ActivePlayer *_player,
|
||||
unsigned int player_index);
|
||||
~PlayerController ();
|
||||
ActivePlayer *getPlayer () { return m_player; }
|
||||
PlayerProfile *getPlayerProfile () { return m_player->getProfile(); }
|
||||
void update (float);
|
||||
void action (PlayerAction action, int value);
|
||||
void handleZipper ();
|
||||
void collectedItem (const Item &item, int add_info=-1);
|
||||
virtual void crashed (Kart *k);
|
||||
void collectedItem (const Item &item, int add_info=-1,
|
||||
float previous_energy=0);
|
||||
virtual void setPosition (int p);
|
||||
virtual void raceFinished (float time);
|
||||
bool isPlayerKart () const {return true;}
|
||||
void reset ();
|
||||
virtual void finishedRace (float time);
|
||||
bool isPlayerController() const {return true;}
|
||||
virtual void reset ();
|
||||
void resetInputState ();
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
Kart::Kart (const std::string& kart_name, int position,
|
||||
Kart::Kart (const std::string& ident, int position,
|
||||
const btTransform& init_transform)
|
||||
: TerrainInfo(1),
|
||||
Moveable(), m_powerup(this), m_attachment(this)
|
||||
@@ -66,11 +66,10 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
# pragma warning(1:4355)
|
||||
#endif
|
||||
{
|
||||
m_kart_properties = kart_properties_manager->getKart(kart_name);
|
||||
m_kart_properties = kart_properties_manager->getKart(ident);
|
||||
assert(m_kart_properties != NULL);
|
||||
m_initial_position = position;
|
||||
m_collected_energy = 0;
|
||||
m_eliminated = false;
|
||||
m_finished_race = false;
|
||||
m_finish_time = 0.0f;
|
||||
m_slipstream_time = 0.0f;
|
||||
@@ -84,6 +83,8 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
m_skidmarks = NULL;
|
||||
m_animated_node = NULL;
|
||||
m_camera = NULL;
|
||||
m_controller = NULL;
|
||||
m_saved_controller = NULL;
|
||||
|
||||
m_view_blocked_by_plunger = 0;
|
||||
|
||||
@@ -100,12 +101,12 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
m_max_speed_reverse_ratio = m_kart_properties->getMaxSpeedReverseRatio();
|
||||
m_speed = 0.0f;
|
||||
|
||||
// Setting rescue to false is important! If rescue is set when reset() is
|
||||
// called, it is assumed that this was triggered by a restart, and that
|
||||
// the vehicle must be added back to the physics world. Since reset() is
|
||||
// also called at the very start, it must be guaranteed that rescue is
|
||||
// not set.
|
||||
m_rescue = false;
|
||||
// Re-setting kart mode is important! If the mode should be rescue when
|
||||
// reset() is called, it is assumed that this was triggered by a restart,
|
||||
// and that the vehicle must be added back to the physics world. Since
|
||||
// reset() is also called at the very start, it must be guaranteed that
|
||||
// rescue is not set.
|
||||
m_kart_mode = KM_RACE;
|
||||
m_wheel_rotation = 0;
|
||||
|
||||
// Create SFXBase for each custom sound
|
||||
@@ -142,6 +143,19 @@ Kart::Kart (const std::string& kart_name, int position,
|
||||
reset();
|
||||
} // Kart
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Saves the old controller in m_saved_controller and stores a new
|
||||
* controller. The save controller is needed in case of a reset.
|
||||
* \param controller The new controller to use (atm it's always an
|
||||
* end controller).
|
||||
*/
|
||||
void Kart::setController(Controller *controller)
|
||||
{
|
||||
assert(m_saved_controller==NULL);
|
||||
m_saved_controller = m_controller;
|
||||
m_controller = controller;
|
||||
} // setController
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
btTransform Kart::getKartHeading(const float customPitch)
|
||||
@@ -302,17 +316,19 @@ Kart::~Kart()
|
||||
} // ~Kart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Eliminates a kart from the race. It removes the kart from the physics
|
||||
* world, and makes the scene node invisible.
|
||||
*/
|
||||
void Kart::eliminate()
|
||||
{
|
||||
m_eliminated = true;
|
||||
if (!m_rescue)
|
||||
if (m_kart_mode!=KM_RESCUE)
|
||||
{
|
||||
World::getWorld()->getPhysics()->removeKart(this);
|
||||
}
|
||||
m_kart_mode = KM_ELIMINATED;
|
||||
|
||||
// make the kart invisible by placing it way under the track
|
||||
Vec3 hell(0, 0, -10000.0f);
|
||||
getNode()->setPosition(hell.toIrrVector());
|
||||
getNode()->setVisible(false);
|
||||
} // eliminate
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -350,23 +366,35 @@ void Kart::updatedWeight()
|
||||
} // updatedWeight
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Reset before a new race.
|
||||
*/
|
||||
void Kart::reset()
|
||||
{
|
||||
// If the kart was eliminated or rescued, the body was removed from the
|
||||
// physics world. Add it again.
|
||||
if(m_eliminated || m_rescue)
|
||||
if(m_kart_mode==KM_ELIMINATED || m_kart_mode==KM_RESCUE)
|
||||
{
|
||||
World::getWorld()->getPhysics()->addKart(this);
|
||||
}
|
||||
|
||||
if(m_node)
|
||||
m_node->setVisible(true); // In case that the kart was eliminated
|
||||
if(m_camera)
|
||||
m_camera->reset();
|
||||
// If the controller was replaced (e.g. replaced by end controller),
|
||||
// restore the original controller.
|
||||
if(m_saved_controller)
|
||||
{
|
||||
m_controller = m_saved_controller;
|
||||
m_saved_controller = NULL;
|
||||
}
|
||||
m_view_blocked_by_plunger = 0.0;
|
||||
m_attachment.clear();
|
||||
m_powerup.reset();
|
||||
|
||||
m_race_position = 9;
|
||||
m_finished_race = false;
|
||||
m_eliminated = false;
|
||||
m_rescue = false;
|
||||
m_kart_mode = KM_RACE;
|
||||
m_finish_time = 0.0f;
|
||||
m_zipper_time_left = 0.0f;
|
||||
m_collected_energy = 0;
|
||||
@@ -417,16 +445,19 @@ void Kart::reset()
|
||||
* player kart have finished the race and all AI karts get
|
||||
* an estimated finish time set.
|
||||
*/
|
||||
void Kart::raceFinished(float time)
|
||||
void Kart::finishedRace(float time)
|
||||
{
|
||||
m_finished_race = true;
|
||||
m_finish_time = time;
|
||||
m_kart_mode = KM_END_ANIM;
|
||||
m_controller->finishedRace(time);
|
||||
race_manager->RaceFinished(this, time);
|
||||
} // raceFinished
|
||||
} // finishedRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::collectedItem(const Item &item, int add_info)
|
||||
{
|
||||
float old_energy = m_collected_energy;
|
||||
const Item::ItemType type = item.getType();
|
||||
|
||||
switch (type)
|
||||
@@ -467,6 +498,7 @@ void Kart::collectedItem(const Item &item, int add_info)
|
||||
|
||||
if ( m_collected_energy > MAX_ITEMS_COLLECTED )
|
||||
m_collected_energy = MAX_ITEMS_COLLECTED;
|
||||
m_controller->collectedItem(item, add_info, old_energy);
|
||||
|
||||
} // collectedItem
|
||||
|
||||
@@ -563,6 +595,9 @@ void Kart::handleExplosion(const Vec3& pos, bool direct_hit)
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::update(float dt)
|
||||
{
|
||||
m_controller->update(dt);
|
||||
if(m_camera)
|
||||
m_camera->update(dt);
|
||||
// if its view is blocked by plunger, decrease remaining time
|
||||
if(m_view_blocked_by_plunger > 0) m_view_blocked_by_plunger -= dt;
|
||||
|
||||
@@ -598,7 +633,7 @@ void Kart::update(float dt)
|
||||
m_wheel_rotation += m_speed*dt / m_kart_properties->getWheelRadius();
|
||||
m_wheel_rotation=fmodf(m_wheel_rotation, 2*M_PI);
|
||||
|
||||
if ( m_rescue )
|
||||
if ( m_kart_mode==KM_RESCUE )
|
||||
{
|
||||
// Let the kart raise 2m in the 2 seconds of the rescue
|
||||
const float rescue_time = 2.0f;
|
||||
@@ -618,7 +653,7 @@ void Kart::update(float dt)
|
||||
-m_rescue_pitch*dt/rescue_time*M_PI/180.0f);
|
||||
setXYZRotation(getXYZ()+Vec3(0, 0, rescue_height*dt/rescue_time),
|
||||
getRotation()*q_roll*q_pitch);
|
||||
} // if m_rescue
|
||||
} // if rescue mode
|
||||
m_attachment.update(dt);
|
||||
|
||||
//smoke drawing control point
|
||||
@@ -723,12 +758,12 @@ void Kart::update(float dt)
|
||||
// is rescued isOnGround might still be true, since the kart rigid
|
||||
// body was removed from the physics, but still retain the old
|
||||
// values for the raycasts).
|
||||
if( (!isOnGround() || m_rescue) && m_shadow_enabled)
|
||||
if( (!isOnGround() || m_kart_mode==KM_RESCUE) && m_shadow_enabled)
|
||||
{
|
||||
m_shadow_enabled = false;
|
||||
m_shadow->disableShadow();
|
||||
}
|
||||
if(!m_shadow_enabled && isOnGround() && !m_rescue)
|
||||
if(!m_shadow_enabled && isOnGround() && m_kart_mode!=KM_RESCUE)
|
||||
{
|
||||
m_shadow->enableShadow();
|
||||
m_shadow_enabled = true;
|
||||
@@ -753,6 +788,7 @@ void Kart::handleZipper()
|
||||
m_vehicle->activateZipper(speed);
|
||||
// Play custom character sound (weee!)
|
||||
playCustomSFX(SFXManager::CUSTOM_ZIPPER);
|
||||
m_controller->handleZipper();
|
||||
} // handleZipper
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -890,9 +926,14 @@ void Kart::resetBrakes()
|
||||
{
|
||||
for(int i=0; i<4; i++) m_vehicle->setBrake(0.0f, i);
|
||||
} // resetBrakes
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Called when the kart crashes against the track (k=NULL) or another kart.
|
||||
* \params k Either a kart if a kart was hit, or NULL if the track was hit.
|
||||
*/
|
||||
void Kart::crashed(Kart *k)
|
||||
{
|
||||
m_controller->crashed();
|
||||
/** If a kart is crashing against the track, the collision is often
|
||||
* reported more than once, resulting in a machine gun effect, and too
|
||||
* long disabling of the engine. Therefore, this reaction is disabled
|
||||
@@ -1009,7 +1050,7 @@ void Kart::updatePhysics (float dt)
|
||||
// order to make them more competitive (this might be removed once
|
||||
// the AI is better).
|
||||
if(m_controls.m_drift &&
|
||||
(race_manager->getDifficulty()==RaceManager::RD_EASY || isPlayerKart()) )
|
||||
(race_manager->getDifficulty()==RaceManager::RD_EASY || m_controller->isPlayerController()) )
|
||||
engine_power *= 0.5f;
|
||||
m_vehicle->applyEngineForce(engine_power, 2);
|
||||
m_vehicle->applyEngineForce(engine_power, 3);
|
||||
@@ -1205,16 +1246,19 @@ void Kart::updatePhysics (float dt)
|
||||
} // updatePhysics
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets the mode of the kart to being rescued.
|
||||
*/
|
||||
void Kart::forceRescue()
|
||||
{
|
||||
m_rescue=true;
|
||||
m_kart_mode=KM_RESCUE;
|
||||
} // forceRescue
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Drops a kart which was rescued back on the track.
|
||||
*/
|
||||
void Kart::endRescue()
|
||||
{
|
||||
m_rescue = false ;
|
||||
m_kart_mode = KM_RACE;
|
||||
|
||||
World::getWorld()->getPhysics()->addKart(this);
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
#include "items/powerup.hpp"
|
||||
#include "karts/moveable.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/kart_control.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "tracks/terrain_info.hpp"
|
||||
|
||||
@@ -46,6 +47,14 @@ class btVehicleTuning;
|
||||
class Quad;
|
||||
class Stars;
|
||||
|
||||
/** The main kart class. All type of karts are of this object, but with
|
||||
* different controllers. The controllers are what turn a kart into a
|
||||
* player kart (i.e. the controller handle input), or an AI kart (the
|
||||
* controller runs the AI code to set steering etc).
|
||||
* Kart has two base classes: the most important one is moveable (which
|
||||
* is an object that is moved on the track, and has position and rotations)
|
||||
* and TerrainInfo, which manages the terrain the kart is on.
|
||||
*/
|
||||
class Kart : public TerrainInfo, public Moveable
|
||||
{
|
||||
private:
|
||||
@@ -56,8 +65,20 @@ private:
|
||||
/** Accumulated skidding factor. */
|
||||
float m_skidding;
|
||||
|
||||
int m_initial_position; // initial position of kart
|
||||
int m_race_position; // current race position (1-numKarts)
|
||||
/** The main controller of this object, used for driving. This
|
||||
* controller is used to run the kart. It will be replaced
|
||||
* with an end kart controller when the kart finishes the race. */
|
||||
Controller *m_controller;
|
||||
/** This saves the original controller when the end controller is
|
||||
* used. This is an easy solution for restarting the race, since
|
||||
* the controller do not need to be reinitialised. */
|
||||
Controller *m_saved_controller;
|
||||
|
||||
/** Initial rank of the kart. */
|
||||
int m_initial_position;
|
||||
|
||||
/** Current race position (1-num_karts). */
|
||||
int m_race_position;
|
||||
|
||||
/** The camera for each kart. Not all karts have cameras (e.g. AI karts
|
||||
* usually don't), but there are exceptions: e.g. after the end of a
|
||||
@@ -91,7 +112,8 @@ private:
|
||||
btKart *m_vehicle;
|
||||
btUprightConstraint *m_uprightConstraint;
|
||||
|
||||
/** The amount of energy collected by hitting coins. */
|
||||
/** The amount of energy collected by hitting coins. Note that it
|
||||
* must be float, since dt is subtraced in each timestep. */
|
||||
float m_collected_energy;
|
||||
|
||||
// Graphical effects
|
||||
@@ -153,8 +175,11 @@ private:
|
||||
float m_view_blocked_by_plunger;
|
||||
float m_speed;
|
||||
float m_current_gear_ratio;
|
||||
bool m_rescue;
|
||||
bool m_eliminated;
|
||||
/** Different kart modes: normal racing, being rescued, showing end
|
||||
* animation, explosions, kart eliminated. */
|
||||
enum {KM_RACE, KM_RESCUE, KM_END_ANIM, KM_EXPLOSION,
|
||||
KM_ELIMINATED}
|
||||
m_kart_mode;
|
||||
|
||||
std::vector<SFXBase*> m_custom_sounds;
|
||||
SFXBase *m_beep_sound;
|
||||
@@ -173,7 +198,7 @@ protected:
|
||||
|
||||
|
||||
public:
|
||||
Kart(const std::string& kart_name, int position,
|
||||
Kart(const std::string& ident, int position,
|
||||
const btTransform& init_transform);
|
||||
virtual ~Kart();
|
||||
unsigned int getWorldKartId() const { return m_world_kart_id; }
|
||||
@@ -199,18 +224,22 @@ public:
|
||||
void setPowerup (PowerupType t, int n)
|
||||
{
|
||||
m_powerup.set(t, n);
|
||||
}
|
||||
} // setPowerup
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the position in race this kart has (1<=p<=n). */
|
||||
virtual void setPosition(int p)
|
||||
{
|
||||
m_race_position = p;
|
||||
}
|
||||
m_controller->setPosition(p);
|
||||
} // setPosition
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
Attachment *getAttachment()
|
||||
{
|
||||
return &m_attachment;
|
||||
}
|
||||
} // getAttachment
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void setAttachmentType(attachmentType t, float time_left=0.0f, Kart*k=NULL)
|
||||
{
|
||||
@@ -218,25 +247,30 @@ public:
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the camera of this kart (or NULL if no camera is attached
|
||||
* to this kart. */
|
||||
Camera* getCamera () {return m_camera;}
|
||||
* to this kart). */
|
||||
Camera* getCamera () {return m_camera;}
|
||||
/** Returns the camera of this kart (or NULL if no camera is attached
|
||||
* to this kart) - const version. */
|
||||
const Camera* getCamera () const {return m_camera;}
|
||||
/** Sets the camera for this kart. */
|
||||
void setCamera(Camera *camera) {m_camera=camera; }
|
||||
/** Sets viewport etc. for the camera of this kart. */
|
||||
void activateCamera () {m_camera->activate(); }
|
||||
/** Returns the viewport of the camera of this kart. */
|
||||
const core::recti& getViewport() const {return m_camera->getViewport(); }
|
||||
/** Returns the scaling in x/y direction for the camera of this kart. */
|
||||
const core::vector2df& getScaling() const {return m_camera->getScaling(); }
|
||||
|
||||
const Powerup *getPowerup () const { return &m_powerup; }
|
||||
Powerup *getPowerup () { return &m_powerup; }
|
||||
int getNumPowerup () const { return m_powerup.getNum();}
|
||||
float getEnergy () const { return m_collected_energy;}
|
||||
int getPosition () const { return m_race_position; }
|
||||
int getInitialPosition () const { return m_initial_position; }
|
||||
float getFinishTime () const { return m_finish_time; }
|
||||
bool hasFinishedRace () const { return m_finished_race; }
|
||||
/** Returns the number of powerups. */
|
||||
int getNumPowerup () const { return m_powerup.getNum(); }
|
||||
/** Returns the time left for a zipper. */
|
||||
float getZipperTimeLeft () const { return m_zipper_time_left; }
|
||||
/** Returns the remaining collected energy. */
|
||||
float getEnergy () const { return m_collected_energy; }
|
||||
/** Returns the current position of this kart in the race. */
|
||||
int getPosition () const { return m_race_position; }
|
||||
/** Returns the initial position of this kart. */
|
||||
int getInitialPosition () const { return m_initial_position; }
|
||||
/** Returns the finished time for a kart. */
|
||||
float getFinishTime () const { return m_finish_time; }
|
||||
/** Returns true if this kart has finished the race. */
|
||||
bool hasFinishedRace () const { return m_finished_race; }
|
||||
void endRescue ();
|
||||
void getClosestKart (float *cdist, int *closest);
|
||||
|
||||
@@ -270,6 +304,8 @@ public:
|
||||
const Vec3& getGravityCenterShift () const
|
||||
{return m_kart_properties->getGravityCenterShift(); }
|
||||
float getSteerPercent () const {return m_controls.m_steer; }
|
||||
KartControl&
|
||||
getControls () {return m_controls; }
|
||||
const KartControl&
|
||||
getControls () const {return m_controls; }
|
||||
/** Sets the kart controls. Used e.g. by replaying history. */
|
||||
@@ -303,20 +339,24 @@ public:
|
||||
void setSuspensionLength();
|
||||
float handleNitro (float dt);
|
||||
float getActualWheelForce();
|
||||
/** True if the wheels are touching the ground. */
|
||||
bool isOnGround () const;
|
||||
/** Returns true if the kart is close to the ground, used to dis/enable
|
||||
* the upright constraint to allow for more realistic explosions. */
|
||||
bool isNearGround () const;
|
||||
bool isEliminated () const {return m_eliminated;}
|
||||
/** Returns true if the kart is eliminated. */
|
||||
bool isEliminated () const {return m_kart_mode==KM_ELIMINATED;}
|
||||
/** Returns true if the kart is being rescued. */
|
||||
bool isRescue () const {return m_kart_mode==KM_RESCUE;}
|
||||
void eliminate ();
|
||||
bool isRescue () const {return m_rescue;}
|
||||
void resetBrakes ();
|
||||
void adjustSpeed (float f);
|
||||
void updatedWeight ();
|
||||
void forceRescue ();
|
||||
void handleExplosion (const Vec3& pos, bool direct_hit);
|
||||
/** Returns a name to be displayed for this kart. */
|
||||
virtual const irr::core::stringw& getName() const {return m_kart_properties->getName();}
|
||||
const std::string& getIdent () const {return m_kart_properties->getIdent();}
|
||||
virtual bool isPlayerKart () const {return false; }
|
||||
virtual bool isNetworkKart () const { return true; }
|
||||
// addMessages gets called by world to add messages to the gui
|
||||
virtual void addMessages () {};
|
||||
virtual void collectedItem (const Item &item, int random_attachment);
|
||||
@@ -325,9 +365,16 @@ public:
|
||||
virtual void crashed (Kart *k);
|
||||
|
||||
virtual void update (float dt);
|
||||
virtual void raceFinished (float time);
|
||||
virtual void finishedRace (float time);
|
||||
void beep ();
|
||||
bool playCustomSFX (unsigned int type);
|
||||
/** Returns the start transform, i.e. position and rotation. */
|
||||
const btTransform getResetTransform() const {return m_reset_transform;}
|
||||
/** Returns the controller of this kart. */
|
||||
Controller* getController() { return m_controller; }
|
||||
/** Returns the controller of this kart (const version). */
|
||||
const Controller* getController() const { return m_controller; }
|
||||
void setController(Controller *controller);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "utils/coord.hpp"
|
||||
|
||||
Moveable::Moveable()
|
||||
|
||||
@@ -89,13 +89,13 @@ void LinearWorld::restartRace()
|
||||
World::restartRace();
|
||||
|
||||
const unsigned int kart_amount = m_karts.size();
|
||||
for(unsigned int n=0; n<kart_amount; n++)
|
||||
for(unsigned int i=0; i<kart_amount; i++)
|
||||
{
|
||||
KartInfo& info = m_kart_info[n];
|
||||
KartInfo& info = m_kart_info[i];
|
||||
info.m_track_sector = QuadGraph::UNKNOWN_SECTOR;
|
||||
info.m_last_valid_sector = QuadGraph::UNKNOWN_SECTOR;
|
||||
info.m_lap_start_time = 0;
|
||||
m_track->getQuadGraph().findRoadSector(m_karts[n]->getXYZ(),
|
||||
m_track->getQuadGraph().findRoadSector(m_karts[i]->getXYZ(),
|
||||
&info.m_track_sector);
|
||||
|
||||
//If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
|
||||
@@ -104,19 +104,23 @@ void LinearWorld::restartRace()
|
||||
if (!info.m_on_road)
|
||||
{
|
||||
info.m_track_sector =
|
||||
m_track->getQuadGraph().findOutOfRoadSector(m_karts[n]->getXYZ(),
|
||||
m_track->getQuadGraph().findOutOfRoadSector(m_karts[i]->getXYZ(),
|
||||
QuadGraph::UNKNOWN_SECTOR );
|
||||
}
|
||||
|
||||
m_track->getQuadGraph().spatialToTrack(&info.m_curr_track_coords,
|
||||
m_karts[n]->getXYZ(),
|
||||
m_karts[i]->getXYZ(),
|
||||
info.m_track_sector );
|
||||
info.m_race_lap = -1;
|
||||
info.m_lap_start_time = -0;
|
||||
info.m_time_at_last_lap = 99999.9f;
|
||||
|
||||
updateRacePosition(m_karts[n], info);
|
||||
} // next kart
|
||||
|
||||
// First all kart infos must be updated before the kart position can be
|
||||
// recomputed, since otherwise 'new' (initialised) valued will be compared
|
||||
// with old values.
|
||||
for(unsigned int i=0; i<kart_amount; i++)
|
||||
updateRacePosition(m_karts[i], m_kart_info[i]);
|
||||
} // restartRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -236,7 +240,10 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
// receive a message from the server. So a client does not do
|
||||
// anything here.
|
||||
if(network_manager->getMode()!=NetworkManager::NW_CLIENT)
|
||||
kart->raceFinished(getTime());
|
||||
{
|
||||
kart->finishedRace(getTime());
|
||||
createEndKart(kart_index);
|
||||
}
|
||||
}
|
||||
{
|
||||
float time_per_lap;
|
||||
@@ -416,7 +423,8 @@ void LinearWorld::terminateRace()
|
||||
if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
|
||||
{
|
||||
const float est_finish_time = m_kart_info[i].m_estimated_finish;
|
||||
m_karts[i]->raceFinished(est_finish_time);
|
||||
m_karts[i]->finishedRace(est_finish_time);
|
||||
createEndKart(i);
|
||||
} // if !hasFinishedRace
|
||||
} // for i
|
||||
} // terminateRace
|
||||
@@ -563,7 +571,6 @@ void LinearWorld::updateRacePosition ( Kart* kart, KartInfo& kart_info )
|
||||
p++;
|
||||
}
|
||||
} //next kart
|
||||
|
||||
kart->setPosition(p);
|
||||
// Switch on faster music if not already done so, if the
|
||||
// first kart is doing its last lap, and if the estimated
|
||||
@@ -587,7 +594,7 @@ void LinearWorld::updateRacePosition ( Kart* kart, KartInfo& kart_info )
|
||||
*/
|
||||
void LinearWorld::checkForWrongDirection(unsigned int i)
|
||||
{
|
||||
if(!m_karts[i]->isPlayerKart()) return;
|
||||
if(!m_karts[i]->getController()->isPlayerController()) return;
|
||||
if(!m_kart_info[i].m_on_road) return;
|
||||
|
||||
// FIXME: Don't do this if the in-game option menu is on the screen!
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "robots/default_robot.hpp"
|
||||
|
||||
|
||||
ProfileWorld::ProfileType ProfileWorld::m_profile_mode=PROFILE_NONE;
|
||||
int ProfileWorld::m_num_laps = 0;
|
||||
@@ -83,17 +81,15 @@ Kart *ProfileWorld::createKart(const std::string &kart_ident, int index,
|
||||
{
|
||||
// Create a camera for the last kart (since this way more of the
|
||||
// karts can be seen.
|
||||
Kart *newkart = loadRobot(kart_ident, index+1, init_pos);
|
||||
Kart *new_kart = new Kart(kart_ident, index+1, init_pos);
|
||||
Controller *controller = loadAIController(new_kart);
|
||||
new_kart->setController(controller);
|
||||
|
||||
if (index == (int)getNumKarts()-1)
|
||||
{
|
||||
// The pointer to the camera does not have to be stored, since it
|
||||
// the camera for robots is not modified.
|
||||
// FIXME: this is broken now, where do we store the camera in case
|
||||
// of profile mode???
|
||||
new Camera(index, newkart);
|
||||
new_kart->setCamera(new Camera(index, new_kart));
|
||||
}
|
||||
return newkart;
|
||||
return new_kart;
|
||||
} // createKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -57,7 +57,10 @@ void StandardRace::update(float dt)
|
||||
for(unsigned int i = 0; i < kart_amount ; i++)
|
||||
{
|
||||
if(!m_karts[i]->hasFinishedRace())
|
||||
m_karts[i]->raceFinished(estimateFinishTimeForKart(m_karts[i]));
|
||||
{
|
||||
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
|
||||
createEndKart(i);
|
||||
}
|
||||
} // i<kart_amount
|
||||
|
||||
// Set delay mode to have time for camera animation, and
|
||||
|
||||
@@ -71,7 +71,8 @@ void ThreeStrikesBattle::terminateRace()
|
||||
{
|
||||
if(!m_karts[i]->hasFinishedRace())
|
||||
{
|
||||
m_karts[i]->raceFinished(WorldStatus::getTime());
|
||||
m_karts[i]->finishedRace(WorldStatus::getTime());
|
||||
createEndKart(i);
|
||||
} // if !hasFinishedRace
|
||||
} // for i
|
||||
|
||||
@@ -92,8 +93,10 @@ void ThreeStrikesBattle::kartHit(const int kart_id)
|
||||
// check if kart is 'dead'
|
||||
if(m_kart_info[kart_id].m_lives < 1)
|
||||
{
|
||||
m_karts[kart_id]->raceFinished(WorldStatus::getTime());
|
||||
m_karts[kart_id]->finishedRace(WorldStatus::getTime());
|
||||
removeKart(kart_id);
|
||||
// FIXME - what about end camera here??
|
||||
// createEndCamera(kart_id)
|
||||
}
|
||||
|
||||
const unsigned int NUM_KARTS = getNumKarts();
|
||||
|
||||
@@ -36,7 +36,10 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/auto_kart.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "karts/controller/default_ai_controller.hpp"
|
||||
#include "karts/controller/new_ai_controller.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "network/race_state.hpp"
|
||||
@@ -44,8 +47,6 @@
|
||||
#include "race/highscore_manager.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "robots/default_robot.hpp"
|
||||
#include "robots/new_ai.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
@@ -151,42 +152,44 @@ Kart *World::createKart(const std::string &kart_ident, int index,
|
||||
int local_player_id, int global_player_id,
|
||||
const btTransform &init_pos)
|
||||
{
|
||||
Kart *newkart = NULL;
|
||||
int position = index+1;
|
||||
int position = index+1;
|
||||
Kart *new_kart = new Kart(kart_ident, position, init_pos);
|
||||
Controller *controller = NULL;
|
||||
switch(race_manager->getKartType(index))
|
||||
{
|
||||
case RaceManager::KT_PLAYER:
|
||||
std::cout << "===== World : creating player kart for kart #" << index << " which has local_player_id " << local_player_id << " ===========\n";
|
||||
newkart = new PlayerKart(kart_ident, position,
|
||||
StateManager::get()->getActivePlayer(local_player_id),
|
||||
init_pos, local_player_id);
|
||||
controller = new PlayerController(new_kart,
|
||||
StateManager::get()->getActivePlayer(local_player_id),
|
||||
local_player_id);
|
||||
m_num_players ++;
|
||||
break;
|
||||
case RaceManager::KT_NETWORK_PLAYER:
|
||||
newkart = new NetworkKart(kart_ident, position, init_pos,
|
||||
global_player_id);
|
||||
m_num_players++;
|
||||
break;
|
||||
//case RaceManager::KT_NETWORK_PLAYER:
|
||||
//controller = new NetworkController(kart_ident, position, init_pos,
|
||||
// global_player_id);
|
||||
//m_num_players++;
|
||||
//break;
|
||||
case RaceManager::KT_AI:
|
||||
std::cout << "===== World : creating AI kart for #" << index << "===========\n";
|
||||
|
||||
newkart = loadRobot(kart_ident, position, init_pos);
|
||||
controller = loadAIController(new_kart);
|
||||
break;
|
||||
case RaceManager::KT_GHOST:
|
||||
break;
|
||||
case RaceManager::KT_LEADER:
|
||||
break;
|
||||
}
|
||||
return newkart;
|
||||
new_kart->setController(controller);
|
||||
return new_kart;
|
||||
} // createKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Kart* World::loadRobot(const std::string& kart_name, int position,
|
||||
const btTransform& init_pos)
|
||||
/** Creates an AI controller for the kart.
|
||||
* \param kart The kart to be controlled by an AI.
|
||||
*/
|
||||
Controller* World::loadAIController(Kart *kart)
|
||||
{
|
||||
Kart* currentRobot;
|
||||
|
||||
|
||||
Controller *controller;
|
||||
// const int NUM_ROBOTS = 1;
|
||||
// For now: instead of random switching, use each
|
||||
// robot in turns: switch(m_random.get(NUM_ROBOTS))
|
||||
@@ -198,19 +201,19 @@ Kart* World::loadRobot(const std::string& kart_name, int position,
|
||||
switch(turn)
|
||||
{
|
||||
case 0:
|
||||
currentRobot = new DefaultRobot(kart_name, position, init_pos, m_track);
|
||||
controller = new DefaultAIController(kart);
|
||||
break;
|
||||
case 1:
|
||||
currentRobot = new NewAI(kart_name, position, init_pos, m_track);
|
||||
controller = new NewAIController(kart);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Warning: Unknown robot, using default." << std::endl;
|
||||
currentRobot = new DefaultRobot(kart_name, position, init_pos, m_track);
|
||||
controller = new DefaultAIController(kart);
|
||||
break;
|
||||
}
|
||||
|
||||
return currentRobot;
|
||||
} // loadRobot
|
||||
return controller;
|
||||
} // loadAIController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
World::~World()
|
||||
@@ -440,17 +443,18 @@ void World::updateHighscores()
|
||||
}
|
||||
|
||||
// Only record times for player karts and only if they finished the race
|
||||
if(!m_karts[index[pos]]->isPlayerKart()) continue;
|
||||
if(!m_karts[index[pos]]->getController()->isPlayerController()) continue;
|
||||
if (!m_karts[index[pos]]->hasFinishedRace()) continue;
|
||||
|
||||
assert(index[pos] >= 0);
|
||||
assert(index[pos] < m_karts.size());
|
||||
PlayerKart *k = (PlayerKart*)m_karts[index[pos]];
|
||||
Kart *k = (Kart*)m_karts[index[pos]];
|
||||
|
||||
HighscoreEntry* highscores = getHighscores();
|
||||
|
||||
PlayerController *controller = (PlayerController*)(k->getController());
|
||||
if(highscores->addData(k->getIdent(),
|
||||
k->getPlayer()->getProfile()->getName(),
|
||||
controller->getPlayer()->getProfile()->getName(),
|
||||
k->getFinishTime())>0 )
|
||||
{
|
||||
highscore_manager->Save();
|
||||
@@ -465,15 +469,15 @@ void World::updateHighscores()
|
||||
* so it shouldn't be called inside of loops.
|
||||
* \param n Index of player kart to return.
|
||||
*/
|
||||
PlayerKart *World::getPlayerKart(unsigned int n) const
|
||||
Kart *World::getPlayerKart(unsigned int n) const
|
||||
{
|
||||
unsigned int count=-1;
|
||||
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
if(m_karts[i]->isPlayerKart())
|
||||
if(m_karts[i]->getController()->isPlayerController())
|
||||
{
|
||||
count++;
|
||||
if(count==n) return (PlayerKart*)m_karts[i];
|
||||
if(count==n) return m_karts[i];
|
||||
}
|
||||
return NULL;
|
||||
} // getPlayerKart
|
||||
@@ -482,15 +486,15 @@ PlayerKart *World::getPlayerKart(unsigned int n) const
|
||||
/** Returns the nth local player kart, i.e. a player kart that has a camera.
|
||||
* \param n Index of player kart to return.
|
||||
*/
|
||||
PlayerKart *World::getLocalPlayerKart(unsigned int n) const
|
||||
Kart *World::getLocalPlayerKart(unsigned int n) const
|
||||
{
|
||||
unsigned int count=-1;
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
{
|
||||
if(m_karts[i]->getCamera() && m_karts[i]->isPlayerKart())
|
||||
if(m_karts[i]->getCamera() && m_karts[i]->getController()->isPlayerController())
|
||||
{
|
||||
count++;
|
||||
if(count==n) return (PlayerKart*)m_karts[i];
|
||||
if(count==n) return m_karts[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -518,11 +522,11 @@ void World::removeKart(int kart_number)
|
||||
*i, 2.0f, 60);
|
||||
}
|
||||
} // for i in kart
|
||||
if(kart->isPlayerKart())
|
||||
if(kart->getController()->isPlayerController())
|
||||
{
|
||||
// Change the camera so that it will be attached to the leader
|
||||
// and facing backwards.
|
||||
Camera* camera=((PlayerKart*)kart)->getCamera();
|
||||
Camera* camera=kart->getCamera();
|
||||
camera->setMode(Camera::CM_LEADER_MODE);
|
||||
m_eliminated_players++;
|
||||
}
|
||||
@@ -580,13 +584,23 @@ void World::pause()
|
||||
} // pause
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::unpause()
|
||||
void World::unpause()
|
||||
{
|
||||
sound_manager->resumeMusic() ;
|
||||
sfx_manager->resumeAll();
|
||||
WorldStatus::unpause();
|
||||
for(unsigned int i=0; i<m_karts.size(); i++)
|
||||
if(m_karts[i]->isPlayerKart()) ((PlayerKart*)m_karts[i])->resetInputState();
|
||||
if(m_karts[i]->getController()->isPlayerController())
|
||||
((PlayerController*)(m_karts[i]->getController()))->resetInputState();
|
||||
} // pause
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Replaces the kart with index i with an EndKart, i.e. a kart that shows the
|
||||
* end animation, and does not use any items anymore.
|
||||
* \param i Index of the kart to be replaced.
|
||||
*/
|
||||
void World::createEndKart(unsigned int i)
|
||||
{
|
||||
m_karts[i]->setController(new EndController(m_karts[i]));
|
||||
} // createEndKart
|
||||
/* EOF */
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
class btRigidBody;
|
||||
class Kart;
|
||||
class PlayerKart;
|
||||
class SFXBase;
|
||||
class Track;
|
||||
|
||||
@@ -109,8 +108,8 @@ protected:
|
||||
void updateHighscores ();
|
||||
void resetAllKarts ();
|
||||
void removeKart (int kart_number);
|
||||
Kart* loadRobot (const std::string& kart_name, int position,
|
||||
const btTransform& init_pos);
|
||||
Controller*
|
||||
loadAIController (Kart *kart);
|
||||
void estimateFinishTimes();
|
||||
|
||||
virtual Kart *createKart(const std::string &kart_ident, int index,
|
||||
@@ -147,8 +146,8 @@ public:
|
||||
void disableRace(); // Put race into limbo phase
|
||||
/** Returns a pointer to the race gui. */
|
||||
RaceGUI *getRaceGUI() const { return m_race_gui; }
|
||||
PlayerKart *getPlayerKart(unsigned int player) const;
|
||||
PlayerKart *getLocalPlayerKart(unsigned int n) const;
|
||||
Kart *getPlayerKart(unsigned int player) const;
|
||||
Kart *getLocalPlayerKart(unsigned int n) const;
|
||||
unsigned int getNumKarts() const { return m_karts.size(); }
|
||||
Kart *getKart(int kartId) const { assert(kartId >= 0 &&
|
||||
kartId < int(m_karts.size()));
|
||||
@@ -226,7 +225,7 @@ public:
|
||||
/** Called by the race result GUI at the end of the race to know the final order
|
||||
(fill in the 'order' array) */
|
||||
virtual void raceResultOrder( int* order ) = 0;
|
||||
|
||||
void createEndKart(unsigned int i);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "network/kart_control_message.hpp"
|
||||
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_kart.hpp"
|
||||
|
||||
@@ -53,7 +52,7 @@ KartControlMessage::KartControlMessage(ENetPacket* pkt, int kart_id_offset,
|
||||
{
|
||||
KartControl kc(this);
|
||||
Kart *kart = World::getWorld()->getKart(i);
|
||||
if(kart->isNetworkKart())
|
||||
if(kart->getController()->isNetworkController())
|
||||
{
|
||||
((NetworkKart*)kart)->setControl(kc);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ RaceResultMessage::RaceResultMessage(ENetPacket* pkt)
|
||||
float time = getFloat();
|
||||
char position = getChar();
|
||||
kart->setPosition(position);
|
||||
kart->raceFinished(time);
|
||||
kart->finishedRace(time);
|
||||
world->createEndKart(i);
|
||||
}
|
||||
} // RaceResultMessage
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
#include "items/flyable.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_control.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/flyable_info.hpp"
|
||||
#include "network/item_info.hpp"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "LinearMath/btQuaternion.h"
|
||||
|
||||
#include "karts/kart_control.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
class Kart;
|
||||
|
||||
@@ -391,7 +391,7 @@ void RaceManager::RaceFinished(const Kart *kart, float time)
|
||||
m_kart_status[id].m_overall_time += time;
|
||||
m_kart_status[id].m_last_time = time;
|
||||
m_num_finished_karts ++;
|
||||
if(kart->isPlayerKart()) m_num_finished_players++;
|
||||
if(kart->getController()->isPlayerController()) m_num_finished_players++;
|
||||
} // raceFinished
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
class Kart;
|
||||
class PlayerKart;
|
||||
class Kart;
|
||||
class Track;
|
||||
|
||||
/** The race manager has two functions:
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/* This is a template to avoid writing boring stuff again and again when
|
||||
* creating a new robot.
|
||||
*
|
||||
* Don't forget to replace the copyright in the fourth line of the header in
|
||||
* this file and the header file, with the current year and your name, the
|
||||
* #include to <name of your robot>_robot.hpp, the class name references in
|
||||
* this file and in empty_robot.hpp to <robot name>Robot and the #ifdef at
|
||||
* beginning of the header file.
|
||||
*
|
||||
* You should also delete these intructions. Oh, and if you use this template
|
||||
* as a robot, it does nothing.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) <insert year here> <insert name here>
|
||||
//
|
||||
// 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 "modes/world.hpp"
|
||||
|
||||
#include "robot/empty_robot.hpp"
|
||||
|
||||
EmptyRobot::EmptyRobot(const KartProperties *kart_properties, int position,
|
||||
sgCoord init_pos) :
|
||||
AutoKart(kart_properties, position, init_pos)
|
||||
{
|
||||
//This is called just once per *competition*
|
||||
|
||||
reset();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void EmptyRobot::update (float delta)
|
||||
{
|
||||
/*General kart stuff*/
|
||||
AutoKart::update(delta);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void EmptyRobot::reset()
|
||||
{
|
||||
//This function is called at the beginning of *each race*
|
||||
|
||||
m_controls.lr = 0.0;
|
||||
m_controls.accel = false;
|
||||
m_controls.brake = false;
|
||||
m_controls.brake = false;
|
||||
m_controls.wheelie = false;
|
||||
m_controls.jump = false;
|
||||
m_controls.rescue = false;
|
||||
m_controls.fire = false;
|
||||
/*General kart stuff*/
|
||||
AutoKart::reset();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) <insert year here> <insert name here>
|
||||
//
|
||||
// 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_EMPTY_HPP
|
||||
#define HEADER_EMPTY_HPP
|
||||
|
||||
#include "karts/auto_kart.hpp"
|
||||
|
||||
class EmptyRobot : public AutoKart
|
||||
{
|
||||
public:
|
||||
EmptyRobot(const KartProperties *kart_properties, int position,
|
||||
sgCoord init_pos);
|
||||
|
||||
void update (float delta);
|
||||
void reset ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -34,7 +34,6 @@ using namespace irr;
|
||||
#include "input/input.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
@@ -223,8 +222,8 @@ void RaceGUI::renderGlobal(float dt)
|
||||
*/
|
||||
void RaceGUI::renderPlayerView(const Kart *kart)
|
||||
{
|
||||
const core::recti &viewport = kart->getViewport();
|
||||
const core::vector2df &scaling = kart->getScaling();
|
||||
const core::recti &viewport = kart->getCamera()->getViewport();
|
||||
const core::vector2df &scaling = kart->getCamera()->getScaling();
|
||||
drawAllMessages (kart, viewport, scaling);
|
||||
if(!World::getWorld()->isRacePhase()) return;
|
||||
|
||||
@@ -309,8 +308,9 @@ void RaceGUI::drawGlobalMiniMap()
|
||||
// int marker_height = m_marker->getOriginalSize().Height;
|
||||
core::rect<s32> source(i *m_marker_rendered_size, 0,
|
||||
(i+1)*m_marker_rendered_size, m_marker_rendered_size);
|
||||
int marker_half_size = (kart->isPlayerKart() ? m_marker_player_size
|
||||
: m_marker_ai_size )>>1;
|
||||
int marker_half_size = (kart->getController()->isPlayerController()
|
||||
? m_marker_player_size
|
||||
: m_marker_ai_size )>>1;
|
||||
core::rect<s32> position(m_map_left+(int)(draw_at.getX()-marker_half_size),
|
||||
lower_y -(int)(draw_at.getY()+marker_half_size),
|
||||
m_map_left+(int)(draw_at.getX()+marker_half_size),
|
||||
@@ -373,8 +373,10 @@ void RaceGUI::drawGlobalPlayerIcons(const KartIconDisplayInfo* info)
|
||||
}
|
||||
|
||||
// draw icon
|
||||
video::ITexture *icon = kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
int w = kart->isPlayerKart() ? ICON_PLAYER_WIDTH : ICON_WIDTH;
|
||||
video::ITexture *icon =
|
||||
kart->getKartProperties()->getIconMaterial()->getTexture();
|
||||
int w = kart->getController()->isPlayerController() ? ICON_PLAYER_WIDTH
|
||||
: ICON_WIDTH;
|
||||
const core::rect<s32> pos(x, y, x+w, y+w);
|
||||
|
||||
// Fixes crash bug, why are certain icons not showing up?
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "graphics/camera.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "karts/player_kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
@@ -70,7 +69,7 @@ void AmbientLightSphere::update(float dt)
|
||||
const video::SColor &def = track->getDefaultAmbientColor();
|
||||
color = m_ambient_color.getInterpolated(def, f);
|
||||
}
|
||||
((PlayerKart*)kart)->getCamera()->setAmbientLight(color);
|
||||
kart->getCamera()->setAmbientLight(color);
|
||||
} // if active
|
||||
} // for i<num_karts
|
||||
} // update
|
||||
@@ -86,6 +85,6 @@ void AmbientLightSphere::update(float dt)
|
||||
bool AmbientLightSphere::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
int indx)
|
||||
{
|
||||
if(!World::getWorld()->getKart(indx)->isPlayerKart()) return false;
|
||||
if(!World::getWorld()->getKart(indx)->getCamera()) return false;
|
||||
return CheckSphere::isTriggered(old_pos, new_pos, indx);
|
||||
} // isTriggered
|
||||
|
||||
Reference in New Issue
Block a user