From 9ff4fdd2ef1fa28a87b0c2ce09d0be4384405086 Mon Sep 17 00:00:00 2001 From: hikerstk Date: Sun, 3 Jul 2011 11:54:41 +0000 Subject: [PATCH] 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 --- src/Makefile.am | 3 + src/ide/vc9/supertuxkart.vcproj | 12 ++ src/items/attachment.cpp | 258 ++++++++------------------------ src/items/attachment.hpp | 52 +++---- src/items/attachment_plugin.hpp | 62 ++++++++ src/items/swatter.cpp | 230 ++++++++++++++++++++++++++++ src/items/swatter.hpp | 86 +++++++++++ 7 files changed, 471 insertions(+), 232 deletions(-) create mode 100644 src/items/attachment_plugin.hpp create mode 100644 src/items/swatter.cpp create mode 100644 src/items/swatter.hpp diff --git a/src/Makefile.am b/src/Makefile.am index f4c223b71..698345cb3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/ide/vc9/supertuxkart.vcproj b/src/ide/vc9/supertuxkart.vcproj index 9e806c298..a514fac5e 100644 --- a/src/ide/vc9/supertuxkart.vcproj +++ b/src/ide/vc9/supertuxkart.vcproj @@ -574,6 +574,10 @@ RelativePath="..\..\items\rubber_band.cpp" > + + + + @@ -1616,6 +1624,10 @@ RelativePath="..\..\items\rubber_band.hpp" > + + 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; igetNumKarts(); 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; igetNumKarts(); i++) - { - Kart *kart = world->getKart(i); - if(kart->isEliminated() || kart==m_kart || kart->isSquashed()) - continue; - float f = (kart->getXYZ()-m_kart->getXYZ()).length2(); - if(fgetIdent().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 diff --git a/src/items/attachment.hpp b/src/items/attachment.hpp index 00671f5ba..352dee21a 100644 --- a/src/items/attachment.hpp +++ b/src/items/attachment.hpp @@ -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 diff --git a/src/items/attachment_plugin.hpp b/src/items/attachment_plugin.hpp new file mode 100644 index 000000000..2fbc8fa16 --- /dev/null +++ b/src/items/attachment_plugin.hpp @@ -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 diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp new file mode 100644 index 000000000..90ed03c1e --- /dev/null +++ b/src/items/swatter.cpp @@ -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; igetNumKarts(); 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; igetNumKarts(); i++) + { + Kart *kart = world->getKart(i); + if(kart->isEliminated() || kart==m_kart || kart->isSquashed()) + continue; + float f = (kart->getXYZ()-m_kart->getXYZ()).length2(); + if(fgetIdent().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 diff --git a/src/items/swatter.hpp b/src/items/swatter.hpp new file mode 100644 index 000000000..e5207f9b6 --- /dev/null +++ b/src/items/swatter.hpp @@ -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 + +#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