Started re-factoring attachments: the swatter is now implemented as

a plugin, which makes the attachment objects much smaller. Other
attachments will likely follow :)


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9142 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-07-03 11:54:41 +00:00
parent 487a45eb17
commit 9ff4fdd2ef
7 changed files with 471 additions and 232 deletions

View File

@ -164,6 +164,7 @@ supertuxkart_SOURCES = \
items/attachment.hpp \
items/attachment_manager.cpp \
items/attachment_manager.hpp \
items/attachment_plugin.hpp \
items/bowling.cpp \
items/bowling.hpp \
items/cake.cpp \
@ -184,6 +185,8 @@ supertuxkart_SOURCES = \
items/projectile_manager.hpp \
items/rubber_band.cpp \
items/rubber_band.hpp \
items\swatter.cpp \
items\swatter.hpp \
karts/controller/ai_base_controller.cpp \
karts/controller/ai_base_controller.hpp \
karts/controller/controller.cpp \

View File

@ -574,6 +574,10 @@
RelativePath="..\..\items\rubber_band.cpp"
>
</File>
<File
RelativePath="..\..\items\swatter.cpp"
>
</File>
</Filter>
<Filter
Name="physics"
@ -1576,6 +1580,10 @@
RelativePath="..\..\items\attachment_manager.hpp"
>
</File>
<File
RelativePath="..\..\items\attachment_plugin.hpp"
>
</File>
<File
RelativePath="..\..\items\bowling.hpp"
>
@ -1616,6 +1624,10 @@
RelativePath="..\..\items\rubber_band.hpp"
>
</File>
<File
RelativePath="..\..\items\swatter.hpp"
>
</File>
</Filter>
<Filter
Name="physics"

View File

@ -25,18 +25,18 @@
#include "graphics/irr_driver.hpp"
#include "items/attachment_manager.hpp"
#include "items/projectile_manager.hpp"
#include "items/swatter.hpp"
#include "karts/kart.hpp"
#include "modes/three_strikes_battle.hpp"
#include "network/race_state.hpp"
#include "network/network_manager.hpp"
#include "utils/constants.hpp"
#define SWAT_ANGLE 22.0f
Attachment::Attachment(Kart* kart)
{
m_type = ATTACH_NOTHING;
m_time_left = 0.0;
m_plugin = NULL;
m_kart = kart;
m_previous_owner = NULL;
@ -64,6 +64,14 @@ void Attachment::set(AttachmentType type, float time, Kart *current_kart)
{
clear();
// If necessary create the appropriate plugin which encapsulates
switch(type)
{
case ATTACH_SWATTER :
m_plugin = new Swatter(this, m_kart);
default: break;
} // switch(type)
m_node->setMesh(attachment_manager->getMesh(type));
if (!UserConfigParams::m_graphical_effects)
@ -79,10 +87,6 @@ void Attachment::set(AttachmentType type, float time, Kart *current_kart)
m_count = m_type==ATTACH_SWATTER
? m_kart->getKartProperties()->getSwatterCount()
: 1;
m_animation_timer = 0.0f;
m_animation_phase = SWATTER_AIMING;
m_rot_per_sec = core::vector3df(0,0,0);
m_animation_target = NULL;
// A parachute can be attached as result of the usage of an item. In this
// case we have to save the current kart speed so that it can be detached
@ -90,11 +94,13 @@ void Attachment::set(AttachmentType type, float time, Kart *current_kart)
if(m_type==ATTACH_PARACHUTE)
{
m_initial_speed = m_kart->getSpeed();
if(m_initial_speed <= 1.5) m_initial_speed = 1.5; // if going very slowly or backwards, braking won't remove parachute
// if going very slowly or backwards, braking won't remove parachute
if(m_initial_speed <= 1.5) m_initial_speed = 1.5;
if (UserConfigParams::m_graphical_effects)
{
m_node->setAnimationSpeed(50); // .blend was created @25 (<10 real, slow computer), make it faster
// .blend was created @25 (<10 real, slow computer), make it faster
m_node->setAnimationSpeed(50);
}
}
m_node->setVisible(true);
@ -107,6 +113,12 @@ void Attachment::set(AttachmentType type, float time, Kart *current_kart)
*/
void Attachment::clear()
{
if(m_plugin)
{
delete m_plugin;
m_plugin = NULL;
}
m_type=ATTACH_NOTHING;
m_time_left=0.0;
@ -143,7 +155,8 @@ void Attachment::hitBanana(Item *item, int new_attachment)
case ATTACH_BOMB:
{
add_a_new_item = false;
projectile_manager->newExplosion(m_kart->getXYZ(), "explosion", m_kart->getController()->isPlayerController());
projectile_manager->newExplosion(m_kart->getXYZ(), "explosion",
m_kart->getController()->isPlayerController());
m_kart->handleExplosion(m_kart->getXYZ(), /*direct_hit*/ true);
clear();
if(new_attachment==-1)
@ -153,7 +166,7 @@ void Attachment::hitBanana(Item *item, int new_attachment)
// same banana again once the explosion animation is finished, giving
// the kart the same penalty twice.
float f = std::max(item->getDisableTime(),
m_kart->getKartProperties()->getExplosionTime()+2.0f);
m_kart->getKartProperties()->getExplosionTime()+2.0f);
item->setDisableTime(f);
break;
}
@ -192,7 +205,9 @@ void Attachment::hitBanana(Item *item, int new_attachment)
case 0:
set( ATTACH_PARACHUTE,stk_config->m_parachute_time+leftover_time);
m_initial_speed = m_kart->getSpeed();
if(m_initial_speed <= 1.5) m_initial_speed = 1.5; // if going very slowly or backwards, braking won't remove parachute
// if going very slowly or backwards, braking won't remove parachute
if(m_initial_speed <= 1.5) m_initial_speed = 1.5;
// if ( m_kart == m_kart[0] )
// sound -> playSfx ( SOUND_SHOOMF ) ;
break ;
@ -230,13 +245,25 @@ void Attachment::update(float dt)
if(m_type==ATTACH_NOTHING) return;
m_time_left -=dt;
if(m_plugin)
{
bool discard = m_plugin->updateAndTestFinished(dt);
if(discard)
{
clear(); // also removes the plugin
return;
}
m_node->setRotation(m_plugin->getRotation());
}
switch (m_type)
{
case ATTACH_PARACHUTE:
// Partly handled in Kart::updatePhysics
// Otherwise: disable if a certain percantage of
// initial speed was lost
if(m_kart->getSpeed() <= m_initial_speed*stk_config->m_parachute_done_fraction)
if(m_kart->getSpeed() <=
m_initial_speed*stk_config->m_parachute_done_fraction)
{
m_time_left = -1;
}
@ -246,24 +273,24 @@ void Attachment::update(float dt)
case ATTACH_MAX:
break;
case ATTACH_SWATTER:
updateSwatter(dt);
// If the swatter is used up, trigger cleaning up
if(m_count==0) m_time_left = -1.0f;
// Everything is done in the plugin.
break;
case ATTACH_BOMB:
if(m_time_left <= (m_node->getEndFrame() - m_node->getStartFrame() - 1))
if(m_time_left <= (m_node->getEndFrame() - m_node->getStartFrame()-1))
{
m_node->setCurrentFrame(m_node->getEndFrame() - m_node->getStartFrame() - 1 -m_time_left);
m_node->setCurrentFrame(m_node->getEndFrame()
- m_node->getStartFrame()-1-m_time_left);
}
if(m_time_left<=0.0)
{
projectile_manager->newExplosion(m_kart->getXYZ(), "explosion", m_kart->getController()->isPlayerController());
projectile_manager->newExplosion(m_kart->getXYZ(), "explosion",
m_kart->getController()->isPlayerController());
m_kart->handleExplosion(m_kart->getXYZ(),
/*direct_hit*/ true);
}
break;
case ATTACH_TINYTUX:
// Nothing to do for tiny tux, this is all handled in EmergencyAnimation
// Nothing to do for tinytux, this is all handled in EmergencyAnimation
break;
} // switch
@ -272,188 +299,21 @@ void Attachment::update(float dt)
clear();
} // update
//-----------------------------------------------------------------------------
/** Updates an armed swatter: it checks for any karts that are close enough
* and not invulnerable, it swats the kart.
* \param dt Time step size.
*/
void Attachment::updateSwatter(float dt)
{
core::vector3df r = m_node->getRotation();
r += m_rot_per_sec * dt;
switch(m_animation_phase)
{
case SWATTER_AIMING:
aimSwatter();
break;
case SWATTER_TO_KART:
if(fabsf(r.Z)>=90)
{
checkForHitKart(r.Z>0);
m_rot_per_sec *= -1.0f;
m_animation_phase = SWATTER_BACK_FROM_KART;
}
break;
case SWATTER_BACK_FROM_KART:
if (r.Z>0)
{
r = core::vector3df(0,0,0);
m_rot_per_sec = r;
m_animation_phase = SWATTER_AIMING;
m_animation_target = NULL;
}
break;
case SWATTER_ITEM_1: // swatter going to the left
if(r.Z>SWAT_ANGLE)
{
m_animation_phase = SWATTER_ITEM_2;
m_rot_per_sec *= -1.0f;
}
break;
case SWATTER_ITEM_2: // swatter going all the way to the right
if(r.Z<-SWAT_ANGLE)
{
m_animation_phase = SWATTER_ITEM_3;
m_rot_per_sec *= -1.0f;
}
break;
case SWATTER_ITEM_3: // swatter going back to rest position.
if(r.Z>0)
{
r = core::vector3df(0,0,0);
m_rot_per_sec = r;
m_animation_phase = SWATTER_AIMING;
}
break;
} // switch m_animation_phase
m_node->setRotation(r);
} // updateSwatter
//-----------------------------------------------------------------------------
/** Returns true if the point xyz is to the left of the kart.
* \param xyz Point to determine the direction
*/
bool Attachment::isLeftSideOfKart(const Vec3 &xyz)
{
Vec3 forw_vec = m_kart->getTrans().getBasis().getColumn(2);
const Vec3& k1 = m_kart->getXYZ();
const Vec3 k2 = k1+forw_vec;
return xyz.sideOfLine2D(k1, k2)>0;
} // isLeftSideOfKart
//-----------------------------------------------------------------------------
/** This function is called when the swatter reaches the hit angle (i.e. it
* is furthest down). Check all karts if any one is hit, i.e. is at the right
* side and at the right angle and distance.
* \param isWattingLeft True if the swatter is aiming to the left side
* of the kart.
*/
void Attachment::checkForHitKart(bool isSwattingLeft)
{
// Square of the minimum distance
const KartProperties *kp = m_kart->getKartProperties();
float min_dist2 = kp->getSwatterDistance2();
Kart *hit_kart = NULL;
Vec3 forw_vec = m_kart->getTrans().getBasis().getColumn(2);
const World *world = World::getWorld();
for(unsigned int i=0; i<world->getNumKarts(); i++)
{
Kart *kart = world->getKart(i);
if(kart->isEliminated() || kart==m_kart || kart->isSquashed())
continue;
float f = (kart->getXYZ()-m_kart->getXYZ()).length2();
// Distance is too great, ignore this kart.
if(f>min_dist2) continue;
// Check if the kart is at the right side.
const bool left = isLeftSideOfKart(kart->getXYZ());
if(left!=isSwattingLeft)
{
//printf("%s wrong side: %d %d\n",
// kart->getIdent().c_str(), left, isSwattingLeft);
continue;
}
Vec3 kart_vec = m_kart->getXYZ()-kart->getXYZ();
// cos alpha = a*b/||a||/||b||
// Since forw_vec is a unit vector, we only have to divide by
// the length of the vector to the kart.
float cos_angle = kart_vec.dot(forw_vec)/kart_vec.length();
float angle = acosf(cos_angle)*180/M_PI;
if(angle<45 || angle>135)
{
//printf("%s angle %f\n", kart->getIdent().c_str(), angle);
continue;
}
kart->setSquash(kp->getSquashDuration(),
kp->getSquashSlowdown());
// It is assumed that only one kart is within reach of the swatter,
// so we can stop testing karts here.
return;
} // for i < num_karts
} // angleToKart
//-----------------------------------------------------------------------------
/** Checks for any kart that is not already squashed that is close enough.
* If a kart is found, it changes the state of the swatter to be
* SWATTER_TARGET and starts the animation.
*/
void Attachment::aimSwatter()
{
const World *world = World::getWorld();
Kart *min_kart = NULL;
// Square of the minimum distance
float min_dist2 = m_kart->getKartProperties()->getSwatterDistance2();
for(unsigned int i=0; i<world->getNumKarts(); i++)
{
Kart *kart = world->getKart(i);
if(kart->isEliminated() || kart==m_kart || kart->isSquashed())
continue;
float f = (kart->getXYZ()-m_kart->getXYZ()).length2();
if(f<min_dist2)
{
min_dist2 = f;
min_kart = kart;
}
}
// No kart close enough, nothing to do.
if(!min_kart) return;
m_count --;
m_animation_phase = SWATTER_TO_KART;
m_animation_target = min_kart;
if(UserConfigParams::logMisc())
printf("[swatter] %s aiming at %s.\n",
m_kart->getIdent().c_str(), min_kart->getIdent().c_str());
const KartProperties *kp = m_kart->getKartProperties();
m_animation_timer = kp->getSwatterAnimationTime();
const bool left = isLeftSideOfKart(min_kart->getXYZ());
m_rot_per_sec = core::vector3df(0, 0,
left ?90.0f:-90.0f) / m_animation_timer;
} // aimSwatter
//-----------------------------------------------------------------------------
/** Starts a (smaller) and faster swatting movement to be played
* when the kart is hit by an item.
// ----------------------------------------------------------------------------
/** Uses the swatter to swat at an item. The actual functionality is
* implemented in the swatter plugin.
* \pre The item must be an attachment (and m_plugin must be a swatter).
*/
void Attachment::swatItem()
{
if(UserConfigParams::logMisc())
printf("[swatter] %s swatting item.\n",
m_kart->getIdent().c_str());
assert(m_type==ATTACH_SWATTER);
assert(m_animation_target==NULL);
m_animation_phase = SWATTER_ITEM_1;
m_animation_timer =
m_kart->getKartProperties()->getSwatterItemAnimationTime();
m_count--;
m_rot_per_sec = core::vector3df(0, 0, SWAT_ANGLE) / m_animation_timer;
((Swatter*)m_plugin)->swatItem();
} // swatItem
// ----------------------------------------------------------------------------
/** Returns if the swatter is currently aiming, i.e. can be used to
* swat an incoming projectile. */
bool Attachment::isSwatterReady() const
{
assert(m_type==ATTACH_SWATTER);
return ((Swatter*)m_plugin)->isSwatterReady();
} // isSwatterReady

View File

@ -21,15 +21,26 @@
#define HEADER_ATTACHMENT_HPP
#include "config/stk_config.hpp"
#include "items/attachment_plugin.hpp"
#include "utils/no_copy.hpp"
#include "utils/random_generator.hpp"
class Kart;
class Item;
/**
* \ingroup items
*/
/** This objects is permanently available in a kart and stores information
* about addons. If a kart has no attachment, this object will have the
* attachment type ATTACH_NOTHING. This way other tests for attachment
* in STK do not have to additionally test if there is an attachment, all
* tests for a type will always be valid.
* Certain attachments need additional coding, this is supported by
* a 'plugin' mechanism: This attachment will forward certain calls to
* (see attachment_pluging abstract class). Compared to normal subclassing
* (i.e. replacing the attachment object each time an attachment changes)
* this has less overhead (since the attachment class always creates
* a scene node).
* \ingroup items
*/
class Attachment: public NoCopy
{
public:
@ -72,40 +83,22 @@ private:
/** Used by bombs so that it's not passed back to previous owner. */
Kart *m_previous_owner;
/** State of a swatter animation. The swatter is either aiming (looking
* for a kart and/or swatting an incoming item), moving towards or back
* from a kart, or swatting left and right to hit an item - which has
* three phases: going left to an angle a (phae 1), then going to -a
* (phase 2), then going back to 0. */
enum {SWATTER_AIMING, SWATTER_TO_KART,
SWATTER_BACK_FROM_KART,
SWATTER_ITEM_1, SWATTER_ITEM_2, SWATTER_ITEM_3,
SWATTER_BACK_FROM_ITEM} m_animation_phase;
/** Timer for swatter animation. */
float m_animation_timer;
/** The kart the swatter is aiming at. */
Kart *m_animation_target;
/** Rotation per second so that the swatter will hit the kart. */
core::vector3df m_rot_per_sec;
/** An optional attachment - additional functionality can be implemented
* for certain attachments. */
AttachmentPlugin *m_plugin;
/** Pseudo random number generator. */
RandomGenerator m_random;
void aimSwatter();
bool isLeftSideOfKart(const Vec3 &xyz);
void checkForHitKart(bool isSwattingToLeft);
public:
Attachment(Kart* kart);
~Attachment();
void clear ();
void hitBanana(Item *item, int new_attachment=-1);
void update (float dt);
void updateSwatter(float dt);
void moveBombFromTo(Kart *from, Kart *to);
void swatItem();
bool isSwatterReady() const;
void set (AttachmentType type, float time, Kart *previous_kart=NULL);
// ------------------------------------------------------------------------
@ -129,13 +122,6 @@ public:
float weightAdjust() const {
return m_type==ATTACH_ANVIL ? stk_config->m_anvil_weight : 0.0f; }
// ------------------------------------------------------------------------
/** Returns if the swatter is currently aiming, i.e. can be used to
* swat an incoming projectile. */
bool isSwatterReady() const {
assert(m_type==ATTACH_SWATTER);
return m_animation_phase == SWATTER_AIMING;
} // isSwatterReady
// ------------------------------------------------------------------------
}; // Attachment
#endif

View File

@ -0,0 +1,62 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2011 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_ATTACHMENT_PLUGIN_HPP
#define HEADER_ATTACHMENT_PLUGIN_HPP
#include "vector3d.h"
class Kart;
class Attachment;
/**
* \ingroup items
* This is the base class for a plugin into an attachment. Plugins are
* used to handle attachment specific data so that the attachment class
* that is used in every kart isn't overloaded. It could be done by
* inheriting from Attachment, but then every time an attachment is
* changed, we could delete and create a new SceneNode. To avoid this
* overhead, we use plugins to encapsulate additional code for some
* plugins.
*/
class AttachmentPlugin
{
protected:
/** Keeps track of the rotation of an attachment, this base class
* will set it to 0. */
core::vector3df m_rotation;
public:
/** Constructor for a plugin. */
AttachmentPlugin(Attachment *attachment, Kart *kart)
{
m_rotation = core::vector3df(0,0,0);
}
// ------------------------------------------------------------------------
/** Updates a plugin. This is called once each time frame. If the
* function returns true, the attachment is discarded. */
virtual bool updateAndTestFinished(float dt) = 0;
// ------------------------------------------------------------------------
/** Returns the rotation of the attachment. */
virtual const core::vector3df& getRotation() const { return m_rotation; }
}; // AttachmentPlugin
#endif

230
src/items/swatter.cpp Normal file
View File

@ -0,0 +1,230 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2011 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "items/swatter.hpp"
#include "items/attachment.hpp"
#include "modes/world.hpp"
#include "karts/kart.hpp"
#define SWAT_ANGLE 22.0f
Swatter::Swatter(Attachment *attachment, Kart *kart)
: AttachmentPlugin(attachment, kart)
{
m_kart = kart;
m_count = kart->getKartProperties()->getSwatterCount();
m_animation_timer = 0.0f;
m_animation_phase = SWATTER_AIMING;
m_rot_per_sec = core::vector3df(0,0,0);
m_rotation = core::vector3df(0,0,0);
m_animation_target = NULL;
} // Swatter
//-----------------------------------------------------------------------------
Swatter::~Swatter()
{
} // ~Swatter
//-----------------------------------------------------------------------------
/** Updates an armed swatter: it checks for any karts that are close enough
* and not invulnerable, it swats the kart.
* \param dt Time step size.
* \return True if the attachment should be discarded.
*/
bool Swatter::updateAndTestFinished(float dt)
{
m_rotation += m_rot_per_sec * dt;
switch(m_animation_phase)
{
case SWATTER_AIMING:
aimSwatter();
break;
case SWATTER_TO_KART:
if(fabsf(m_rotation.Z)>=90)
{
checkForHitKart(m_rotation.Z>0);
m_rot_per_sec *= -1.0f;
m_animation_phase = SWATTER_BACK_FROM_KART;
}
break;
case SWATTER_BACK_FROM_KART:
if (m_rotation.Z>0)
{
m_rotation = core::vector3df(0,0,0);
m_rot_per_sec = core::vector3df(0,0,0);
m_animation_phase = SWATTER_AIMING;
m_animation_target = NULL;
}
break;
case SWATTER_ITEM_1: // swatter going to the left
if(m_rotation.Z>SWAT_ANGLE)
{
m_animation_phase = SWATTER_ITEM_2;
m_rot_per_sec *= -1.0f;
}
break;
case SWATTER_ITEM_2: // swatter going all the way to the right
if(m_rotation.Z<-SWAT_ANGLE)
{
m_animation_phase = SWATTER_ITEM_3;
m_rot_per_sec *= -1.0f;
}
break;
case SWATTER_ITEM_3: // swatter going back to rest position.
if(m_rotation.Z>0)
{
m_rotation = core::vector3df(0,0,0);
m_rot_per_sec = core::vector3df(0,0,0);
m_animation_phase = SWATTER_AIMING;
}
break;
} // switch m_animation_phase
// If the swatter is used up, trigger cleaning up
return (m_count==0);
} // updateAndTestFinished
//-----------------------------------------------------------------------------
/** Returns true if the point xyz is to the left of the kart.
* \param xyz Point to determine the direction
*/
bool Swatter::isLeftSideOfKart(const Vec3 &xyz)
{
Vec3 forw_vec = m_kart->getTrans().getBasis().getColumn(2);
const Vec3& k1 = m_kart->getXYZ();
const Vec3 k2 = k1+forw_vec;
return xyz.sideOfLine2D(k1, k2)>0;
} // isLeftSideOfKart
//-----------------------------------------------------------------------------
/** This function is called when the swatter reaches the hit angle (i.e. it
* is furthest down). Check all karts if any one is hit, i.e. is at the right
* side and at the right angle and distance.
* \param isWattingLeft True if the swatter is aiming to the left side
* of the kart.
*/
void Swatter::checkForHitKart(bool isSwattingLeft)
{
// Square of the minimum distance
const KartProperties *kp = m_kart->getKartProperties();
float min_dist2 = kp->getSwatterDistance2();
Kart *hit_kart = NULL;
Vec3 forw_vec = m_kart->getTrans().getBasis().getColumn(2);
const World *world = World::getWorld();
for(unsigned int i=0; i<world->getNumKarts(); i++)
{
Kart *kart = world->getKart(i);
if(kart->isEliminated() || kart==m_kart || kart->isSquashed())
continue;
float f = (kart->getXYZ()-m_kart->getXYZ()).length2();
// Distance is too great, ignore this kart.
if(f>min_dist2) continue;
// Check if the kart is at the right side.
const bool left = isLeftSideOfKart(kart->getXYZ());
if(left!=isSwattingLeft)
{
//printf("%s wrong side: %d %d\n",
// kart->getIdent().c_str(), left, isSwattingLeft);
continue;
}
Vec3 kart_vec = m_kart->getXYZ()-kart->getXYZ();
// cos alpha = a*b/||a||/||b||
// Since forw_vec is a unit vector, we only have to divide by
// the length of the vector to the kart.
float cos_angle = kart_vec.dot(forw_vec)/kart_vec.length();
float angle = acosf(cos_angle)*180/M_PI;
if(angle<45 || angle>135)
{
//printf("%s angle %f\n", kart->getIdent().c_str(), angle);
continue;
}
kart->setSquash(kp->getSquashDuration(),
kp->getSquashSlowdown());
// It is assumed that only one kart is within reach of the swatter,
// so we can stop testing karts here.
return;
} // for i < num_karts
} // angleToKart
//-----------------------------------------------------------------------------
/** Checks for any kart that is not already squashed that is close enough.
* If a kart is found, it changes the state of the swatter to be
* SWATTER_TARGET and starts the animation.
*/
void Swatter::aimSwatter()
{
const World *world = World::getWorld();
Kart *min_kart = NULL;
// Square of the minimum distance
float min_dist2 = m_kart->getKartProperties()->getSwatterDistance2();
for(unsigned int i=0; i<world->getNumKarts(); i++)
{
Kart *kart = world->getKart(i);
if(kart->isEliminated() || kart==m_kart || kart->isSquashed())
continue;
float f = (kart->getXYZ()-m_kart->getXYZ()).length2();
if(f<min_dist2)
{
min_dist2 = f;
min_kart = kart;
}
}
// No kart close enough, nothing to do.
if(!min_kart) return;
m_count --;
m_animation_phase = SWATTER_TO_KART;
m_animation_target = min_kart;
if(UserConfigParams::logMisc())
printf("[swatter] %s aiming at %s.\n",
m_kart->getIdent().c_str(), min_kart->getIdent().c_str());
const KartProperties *kp = m_kart->getKartProperties();
m_animation_timer = kp->getSwatterAnimationTime();
const bool left = isLeftSideOfKart(min_kart->getXYZ());
m_rot_per_sec = core::vector3df(0, 0,
left ?90.0f:-90.0f) / m_animation_timer;
} // aimSwatter
//-----------------------------------------------------------------------------
/** Starts a (smaller) and faster swatting movement to be played
* when the kart is hit by an item.
*/
void Swatter::swatItem()
{
if(UserConfigParams::logMisc())
printf("[swatter] %s swatting item.\n",
m_kart->getIdent().c_str());
assert(m_animation_target==NULL);
m_animation_phase = SWATTER_ITEM_1;
m_animation_timer =
m_kart->getKartProperties()->getSwatterItemAnimationTime();
m_count--;
m_rot_per_sec = core::vector3df(0, 0, SWAT_ANGLE) / m_animation_timer;
} // swatItem

86
src/items/swatter.hpp Normal file
View File

@ -0,0 +1,86 @@
// $Id$
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2011 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_SWATTER_HPP
#define HEADER_SWATTER_HPP
#include <vector3d.h>
#include "config/stk_config.hpp"
#include "items/attachment_plugin.hpp"
#include "utils/no_copy.hpp"
#include "utils/random_generator.hpp"
class Kart;
class Item;
class Attachment;
/**
* \ingroup items
*/
class Swatter : public NoCopy, public AttachmentPlugin
{
private:
/** Kart the attachment is attached to. */
Kart *m_kart;
/** How often an attachment can be used (e.g. swatter). */
int m_count;
/** State of a swatter animation. The swatter is either aiming (looking
* for a kart and/or swatting an incoming item), moving towards or back
* from a kart, or swatting left and right to hit an item - which has
* three phases: going left to an angle a (phae 1), then going to -a
* (phase 2), then going back to 0. */
enum {SWATTER_AIMING, SWATTER_TO_KART,
SWATTER_BACK_FROM_KART,
SWATTER_ITEM_1, SWATTER_ITEM_2, SWATTER_ITEM_3,
SWATTER_BACK_FROM_ITEM} m_animation_phase;
/** Timer for swatter animation. */
float m_animation_timer;
/** The kart the swatter is aiming at. */
Kart *m_animation_target;
/** Rotation per second so that the swatter will hit the kart. */
core::vector3df m_rot_per_sec;
void aimSwatter();
bool isLeftSideOfKart(const Vec3 &xyz);
void checkForHitKart(bool isSwattingToLeft);
public:
Swatter(Attachment *attachment, Kart *kart);
~Swatter();
bool updateAndTestFinished(float dt);
void updateSwatter(float dt);
void swatItem();
// ------------------------------------------------------------------------
/** Returns if the swatter is currently aiming, i.e. can be used to
* swat an incoming projectile. */
bool isSwatterReady() const {
return m_animation_phase == SWATTER_AIMING;
} // isSwatterReady
// ------------------------------------------------------------------------
}; // Swatter
#endif