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:
parent
487a45eb17
commit
9ff4fdd2ef
@ -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 \
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
62
src/items/attachment_plugin.hpp
Normal file
62
src/items/attachment_plugin.hpp
Normal 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
230
src/items/swatter.cpp
Normal 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
86
src/items/swatter.hpp
Normal 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
|
Loading…
Reference in New Issue
Block a user