Refactoring: flyable and hit effects now call

updateAndDelete instead of update. The return
value indicates if the flyable/hit effect needs
to be deleted. That removes callbacks to the
projectile manager to indicate that something
needs to be deleted.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9619 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-08-25 00:06:33 +00:00
parent 8d8601655d
commit 771cf47339
15 changed files with 167 additions and 122 deletions

View File

@ -85,11 +85,11 @@ Explosion::~Explosion()
* \param dt Time step size.
* \return true If the explosion is finished.
*/
bool Explosion::update(float dt)
bool Explosion::updateAndDelete(float dt)
{
// The explosion sfx is shorter than the particle effect,
// so no need to save the result of the update call.
HitSFX::update(dt);
HitSFX::updateAndDelete(dt);
m_remaining_time -= dt;
@ -133,4 +133,4 @@ bool Explosion::update(float dt)
}
return false; // not finished
} // update
} // updateAndDelete

View File

@ -46,7 +46,7 @@ private:
public:
Explosion(const Vec3& coord, const char* explosion_sound);
~Explosion();
bool update (float delta_t);
bool updateAndDelete(float delta_t);
bool hasEnded () { return m_remaining_time <= -explosion_time; }
} ;

View File

@ -44,7 +44,7 @@ public:
/** Updates a hit effect. Called once per frame.
* \param dt Time step size.
* \return True if the hit effect is finished and can be removed. */
virtual bool update (float dt) = 0;
virtual bool updateAndDelete(float dt) = 0;
// ------------------------------------------------------------------------
/** Sets that this SFX affects a player kart, which can be used to

View File

@ -61,11 +61,12 @@ void HitSFX::setPlayerKartHit()
} // setPlayerKartHit
//-----------------------------------------------------------------------------
/** Updates the hit sfx, called one per time step.
/** Updates the hit sfx, called one per time step. If this function returns
* true, the effect will be deleted.
* \param dt Time step size.
* \return true If the explosion is finished.
*/
bool HitSFX::update(float dt)
bool HitSFX::updateAndDelete(float dt)
{
return m_sfx->getStatus() != SFXManager::SFX_PLAYING;
} // update
} // updateAndDelete

View File

@ -36,7 +36,7 @@ private:
public:
HitSFX(const Vec3& coord, const char* explosion_sound);
~HitSFX();
virtual bool update (float dt);
virtual bool updateAndDelete(float dt);
virtual void setPlayerKartHit();
}; // HitSFX

View File

@ -90,9 +90,17 @@ void Bowling::init(const XMLNode &node, scene::IMesh *bowling)
} // init
// -----------------------------------------------------------------------------
void Bowling::update(float dt)
/** Updates the bowling ball ineach frame. If this function returns true, the
* object will be removed by the projectile manager.
* \param dt Time step size.
* \returns True of this object should be removed.
*/
bool Bowling::updateAndDelete(float dt)
{
Flyable::update(dt);
bool can_be_deleted = Flyable::updateAndDelete(dt);
if(can_be_deleted)
return true;
const Kart *kart=0;
Vec3 direction;
float minDistance;
@ -121,7 +129,7 @@ void Bowling::update(float dt)
if(!material || material->isDriveReset())
{
hit(NULL);
return;
return true;
}
}
btVector3 v = m_body->getLinearVelocity();
@ -131,13 +139,17 @@ void Bowling::update(float dt)
if(vlen<0.8*m_speed*m_speed)
{ // bowling lost energy (less than 80%), i.e. it's too slow - speed it up:
if(vlen==0.0f) {
v = btVector3(.5f, .0, 0.5f); // avoid 0 div.
v = btVector3(.5f, .0, 0.5f); // avoid 0 div.
}
m_body->setLinearVelocity(v*m_speed/sqrt(vlen));
} // vlen < 0.8*m_speed*m_speed
} // hat< m_max_height
if(vlen<0.1)
{
hit(NULL);
} // update
return true;
}
return false;
} // updateAndDelete
// -----------------------------------------------------------------------------

View File

@ -43,7 +43,7 @@ private:
public:
Bowling(Kart* kart);
static void init(const XMLNode &node, scene::IMesh *bowling);
virtual void update(float dt);
virtual bool updateAndDelete(float dt);
const char* getExplosionSound() const { return "strike"; }

View File

@ -254,8 +254,8 @@ void Flyable::getClosestKart(const Kart **minKart, float *minDistSquared,
Vec3 *minDelta, const Kart* inFrontOf,
const bool backwards) const
{
btTransform tProjectile = (inFrontOf != NULL ? inFrontOf->getTrans()
: getTrans());
btTransform trans_projectile = (inFrontOf != NULL ? inFrontOf->getTrans()
: getTrans());
*minDistSquared = 999999.9f;
*minKart = NULL;
@ -271,9 +271,11 @@ void Flyable::getClosestKart(const Kart **minKart, float *minDistSquared,
kart->playingEmergencyAnimation() ) continue;
btTransform t=kart->getTrans();
Vec3 delta = t.getOrigin()-tProjectile.getOrigin();
// the Y distance is added again because karts above or below should not be prioritized when aiming
float distance2 = delta.length2() + abs(t.getOrigin().getY() - tProjectile.getOrigin().getY())*2;
Vec3 delta = t.getOrigin()-trans_projectile.getOrigin();
// the Y distance is added again because karts above or below should//
// not be prioritized when aiming
float distance2 = delta.length2() + abs(t.getOrigin().getY()
- trans_projectile.getOrigin().getY())*2;
if(inFrontOf != NULL)
{
@ -338,19 +340,25 @@ void Flyable::getLinearKartItemIntersection (const Vec3 &origin,
float gy = target_direction.getY();
//Projected onto X-Z plane
float target_kart_speed = target_direction.length_2d() * target_kart->getSpeed();
float target_kart_speed = target_direction.length_2d()
* target_kart->getSpeed();
float target_kart_heading = target_kart->getHeading();
float dist = -(target_kart_speed / item_XZ_speed) * (dx * cosf(target_kart_heading) -
dz * sinf(target_kart_heading));
float dist = -(target_kart_speed / item_XZ_speed)
* (dx * cosf(target_kart_heading) -
dz * sinf(target_kart_heading) );
float fire_th = (dx*dist - dz * sqrtf(dx*dx + dz*dz - dist*dist)) / (dx*dx + dz*dz);
fire_th = (((dist - dx*fire_th) / dz > 0) ? -acosf(fire_th): acosf(fire_th));
float fire_th = (dx*dist - dz * sqrtf(dx*dx + dz*dz - dist*dist))
/ (dx*dx + dz*dz);
fire_th = (((dist - dx*fire_th) / dz > 0) ? -acosf(fire_th)
: acosf(fire_th));
float time = 0.0f;
float a = item_XZ_speed * sinf (fire_th) + target_kart_speed * sinf (target_kart_heading);
float b = item_XZ_speed * cosf (fire_th) + target_kart_speed * cosf (target_kart_heading);
float a = item_XZ_speed * sinf (fire_th)
+ target_kart_speed * sinf (target_kart_heading);
float b = item_XZ_speed * cosf (fire_th)
+ target_kart_speed * cosf (target_kart_heading);
if (fabsf(a) > fabsf(b)) time = fabsf (dx / a);
else if (b != 0.0f) time = fabsf(dz / b);
@ -364,16 +372,23 @@ void Flyable::getLinearKartItemIntersection (const Vec3 &origin,
time -= forw_offset / sqrt(a*a+b*b);
*fire_angle = fire_th;
*up_velocity = (0.5f * time * gravity) + (dy / time) + (gy * target_kart->getSpeed());
*up_velocity = (0.5f * time * gravity) + (dy / time)
+ (gy * target_kart->getSpeed());
} // getLinearKartItemIntersection
//-----------------------------------------------------------------------------
void Flyable::update(float dt)
/** Updates this flyable. It calls Moveable::update. If this function returns
* true, the flyable will be deleted by the projectile manager.
* \param dt Time step size.
* \returns True if this object can be deleted.
*/
bool Flyable::updateAndDelete(float dt)
{
m_time_since_thrown += dt;
if(m_max_lifespan > -1 && m_time_since_thrown > m_max_lifespan) hit(NULL);
if(m_max_lifespan > -1 && m_time_since_thrown > m_max_lifespan)
hit(NULL);
if(m_exploded) return;
if(m_exploded) return true;
Vec3 xyz=getBody()->getWorldTransform().getOrigin();
// Check if the flyable is outside of the track. If so, explode it.
@ -396,7 +411,7 @@ void Flyable::update(float dt)
xyz[0]>(*max)[0]-eps || xyz[2]>(*max)[2]-eps || xyz[1]>(*max)[1]-eps )
{
hit(NULL); // flyable out of track boundary
return;
return true;
}
// Add the position offset so that the flyable can adjust its position
@ -404,6 +419,10 @@ void Flyable::update(float dt)
// problems finding the terrain in steep uphill sections).
TerrainInfo::update(xyz+m_position_offset);
// Remove flyable if its
if(TerrainInfo::getMaterial()==NULL)
return true;
if(m_adjust_up_velocity)
{
float hat = xyz.getY()-getHoT();
@ -412,7 +431,8 @@ void Flyable::update(float dt)
// HAT is clamped by min/max height. This might be somewhat
// unphysical, but feels right in the game.
float delta = m_average_height - std::max(std::min(hat, m_max_height), m_min_height);
float delta = m_average_height - std::max(std::min(hat, m_max_height),
m_min_height);
Vec3 v = getVelocity();
assert(!isnan(v.getX()));
assert(!isnan(v.getX()));
@ -429,9 +449,11 @@ void Flyable::update(float dt)
} // if m_adjust_up_velocity
Moveable::update(dt);
} // update
// -----------------------------------------------------------------------------
return false;
} // updateAmdDelete
// ----------------------------------------------------------------------------
/** Updates the position of a projectile based on information received frmo the
* server.
*/
@ -445,7 +467,7 @@ void Flyable::updateFromServer(const FlyableInfo &f, float dt)
Moveable::update(dt);
} // updateFromServer
// -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
/** Returns true if the item hit the kart who shot it (to avoid that an item
* that's too close to the shoter hits the shoter).
* \param kart Kart who was hit.
@ -457,8 +479,8 @@ bool Flyable::isOwnerImmunity(const Kart* kart_hit) const
m_time_since_thrown < 2.0f;
} // isOwnerImmunity
// -----------------------------------------------------------------------------
/** Callback from the phycis in case that a kart or object is hit.
// ----------------------------------------------------------------------------
/** Callback from the phycis in case that a kart or physical object is hit.
* kart The kart hit (NULL if no kart was hit).
* object The object that was hit (NULL if none).
*/
@ -475,10 +497,11 @@ void Flyable::hit(Kart *kart_hit, PhysicalObject* object)
{
case PowerupManager::POWERUP_CAKE:
{
hit_message += StringUtils::insertValues(getCakeString(),
core::stringw(kart_hit->getName()),
core::stringw(m_owner->getName())
).c_str();
hit_message =
StringUtils::insertValues(getCakeString(),
core::stringw(kart_hit->getName()),
core::stringw(m_owner->getName())
).c_str();
}
break;
case PowerupManager::POWERUP_PLUNGER:
@ -490,16 +513,18 @@ void Flyable::hit(Kart *kart_hit, PhysicalObject* object)
{
if (kart_hit == m_owner)
{
hit_message += StringUtils::insertValues(getSelfBowlingString(),
core::stringw(m_owner->getName())
).c_str();
hit_message =
StringUtils::insertValues(getSelfBowlingString(),
core::stringw(m_owner->getName())
).c_str();
}
else
{
hit_message += StringUtils::insertValues(getBowlingString(),
core::stringw(kart_hit->getName()),
core::stringw(m_owner->getName())
).c_str();
hit_message =
StringUtils::insertValues(getBowlingString(),
core::stringw(kart_hit->getName()),
core::stringw(m_owner->getName())
).c_str();
}
}
break;
@ -507,18 +532,29 @@ void Flyable::hit(Kart *kart_hit, PhysicalObject* object)
printf("Failed message for %i\n", m_type);
assert(false);
}
gui->addMessage(translations->fribidize(hit_message), NULL, 3.0f, 40, video::SColor(255, 255, 255, 255), false);
gui->addMessage(translations->fribidize(hit_message), NULL, 3.0f, 40,
video::SColor(255, 255, 255, 255), false);
}
m_has_hit_something=true;
// Notify the projectile manager that this rocket has hit something.
// The manager will create the appropriate explosion object.
projectile_manager->notifyRemove();
m_exploded=true;
if(!needsExplosion()) return;
if(needsExplosion())
explode(kart_hit, object);
return;
} // hit
// ----------------------------------------------------------------------------
/** Creates the explosion physical effect, i.e. pushes the karts and ph
* appropriately. The corresponding visual/sfx needs to be added manually!
*/
void Flyable::explode(Kart *kart_hit, PhysicalObject *object)
{
// Apply explosion effect
// ----------------------
World *world = World::getWorld();

View File

@ -154,11 +154,12 @@ public:
virtual ~Flyable ();
static void init (const XMLNode &node, scene::IMesh *model,
PowerupManager::PowerupType type);
virtual void update (float);
virtual bool updateAndDelete(float);
virtual HitEffect *getHitEffect() const;
void updateFromServer(const FlyableInfo &f, float dt);
HitEffect *getHitEffect() const;
bool isOwnerImmunity(const Kart *kart_hit) const;
virtual void hit (Kart* kart, PhysicalObject* obj=NULL);
void explode(Kart* kart, PhysicalObject* obj=NULL);
// ------------------------------------------------------------------------
/** If true the up velocity of the flyable will be adjust so that the
* flyable stays at a height close to the average height.
@ -173,11 +174,6 @@ public:
/** Called when this flyable hits the track. */
virtual void hitTrack () {};
// ------------------------------------------------------------------------
/** Called when this flyable hit a kart or physical object.
* \param kart Pointer to the kart hit (NULL if no kart was hit).
* \param obj Pointer to the object hit (NULL if no object was hit). */
virtual void hit (Kart* kart, PhysicalObject* obj=NULL);
// ------------------------------------------------------------------------
/** Enables/disables adjusting ov velocity depending on height above
* terrain. Missiles can 'follow the terrain' with this adjustment,
* but gravity will basically be disabled. */
@ -197,9 +193,8 @@ public:
/** Returns the sfx that should be played in case of an explosion. */
virtual const char* getExplosionSound() const { return "explosion"; }
// ------------------------------------------------------------------------
/** Indicates if an explosion needs to be added if this flyable
* is removed. */
virtual bool needsExplosion() const {return true;}
/** Default is that each flyable needs an explosion effect. */
virtual bool needsExplosion() const { return true; }
}; // Flyable
#endif

View File

@ -118,21 +118,21 @@ Plunger::Plunger(Kart *kart) : Flyable(kart, PowerupManager::POWERUP_PLUNGER)
m_keep_alive = -1;
} // Plunger
// -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
Plunger::~Plunger()
{
if(m_rubber_band)
delete m_rubber_band;
} // ~Plunger
// -----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void Plunger::init(const XMLNode &node, scene::IMesh *plunger_model)
{
Flyable::init(node, plunger_model, PowerupManager::POWERUP_PLUNGER);
} // init
// -----------------------------------------------------------------------------
void Plunger::update(float dt)
// ----------------------------------------------------------------------------
bool Plunger::updateAndDelete(float dt)
{
// In keep-alive mode, just update the rubber band
if(m_keep_alive >= 0)
@ -141,18 +141,19 @@ void Plunger::update(float dt)
if(m_keep_alive<=0)
{
setHasHit();
projectile_manager->notifyRemove();
return true;
}
if(m_rubber_band != NULL) m_rubber_band->update(dt);
return;
return false;
}
// Else: update the flyable and rubber band
Flyable::update(dt);
bool ret = Flyable::updateAndDelete(dt);
if(m_rubber_band != NULL) m_rubber_band->update(dt);
if(getHoT()==Track::NOHIT) return;
} // update
return ret;
} // updateAndDelete
// -----------------------------------------------------------------------------
/** Virtual function called when the plunger hits something.

View File

@ -47,16 +47,21 @@ public:
Plunger(Kart *kart);
~Plunger();
static void init(const XMLNode &node, scene::IMesh* missile);
virtual bool updateAndDelete(float dt);
virtual void hitTrack ();
virtual void hit (Kart *kart, PhysicalObject *obj=NULL);
// ------------------------------------------------------------------------
/** Sets the keep-alive value. Setting it to 0 will remove the plunger
* at the next update - which is used if the rubber band snaps.
*/
void setKeepAlive(float t) {m_keep_alive = t;}
virtual void update (float dt);
virtual void hitTrack ();
virtual void hit (Kart *kart, PhysicalObject *obj=NULL);
/** A plunger does not explode if it is removed. */
virtual bool needsExplosion() const {return false;}
// ------------------------------------------------------------------------
/** No hit effect when it ends. */
virtual HitEffect *getHitEffect() const {return NULL; }
// ------------------------------------------------------------------------
/** Plunger does not need an explosion effect. */
virtual bool needsExplosion() const { return false; }
}; // Plunger
#endif

View File

@ -76,30 +76,11 @@ void ProjectileManager::update(float dt)
updateServer(dt);
}
// Then check if any projectile hit something
if(m_something_was_hit)
{
Projectiles::iterator p = m_active_projectiles.begin();
while(p!=m_active_projectiles.end())
{
if(! (*p)->hasHit()) { p++; continue; }
if((*p)->needsExplosion())
{
HitEffect *he = (*p)->getHitEffect();
addHitEffect(he);
}
Flyable *f=*p;
Projectiles::iterator pNext=m_active_projectiles.erase(p); // returns the next element
delete f;
p=pNext;
} // while p!=m_active_projectiles.end()
}
HitEffects::iterator he = m_active_hit_effects.begin();
while(he!=m_active_hit_effects.end())
{
// Update this hit effect. If it can be removed, remove it.
if((*he)->update(dt))
if((*he)->updateAndDelete(dt))
{
delete *he;
HitEffects::iterator next = m_active_hit_effects.erase(he);
@ -119,19 +100,31 @@ void ProjectileManager::updateServer(float dt)
{
race_state->setNumFlyables(m_active_projectiles.size());
}
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); ++i)
Projectiles::iterator p = m_active_projectiles.begin();
while(p!=m_active_projectiles.end())
{
(*i)->update(dt);
// Store the state information on the server
bool can_be_deleted = (*p)->updateAndDelete(dt);
if(network_manager->getMode()!=NetworkManager::NW_NONE)
{
race_state->setFlyableInfo(i-m_active_projectiles.begin(),
FlyableInfo((*i)->getXYZ(),
(*i)->getRotation(),
(*i)->hasHit()) );
race_state->setFlyableInfo(p-m_active_projectiles.begin(),
FlyableInfo((*p)->getXYZ(),
(*p)->getRotation(),
can_be_deleted) );
}
}
if(can_be_deleted)
{
HitEffect *he = (*p)->getHitEffect();
if(he)
addHitEffect(he);
Flyable *f=*p;
Projectiles::iterator p_next=m_active_projectiles.erase(p);
delete f;
p=p_next;
}
else
p++;
} // while p!=m_active_projectiles.end()
} // updateServer
// -----------------------------------------------------------------------------
@ -140,7 +133,6 @@ void ProjectileManager::updateServer(float dt)
* (i.e. position, hit effects etc) */
void ProjectileManager::updateClient(float dt)
{
m_something_was_hit = false;
unsigned int num_projectiles = race_state->getNumFlyables();
if(num_projectiles != m_active_projectiles.size())
fprintf(stderr, "Warning: num_projectiles %d active %d\n",num_projectiles,
@ -154,7 +146,6 @@ void ProjectileManager::updateClient(float dt)
(*i)->updateFromServer(f, dt);
if(f.m_exploded)
{
m_something_was_hit = true;
(*i)->hit(NULL);
}
} // for i in m_active_projectiles

View File

@ -53,14 +53,11 @@ private:
* being shown or have a sfx playing. */
HitEffects m_active_hit_effects;
bool m_something_was_hit;
void updateClient(float dt);
void updateServer(float dt);
public:
ProjectileManager() {m_something_was_hit=false;}
ProjectileManager() {}
~ProjectileManager() {}
/** Notifies the projectile manager that something needs to be removed. */
void notifyRemove () {m_something_was_hit=true; }
void loadData ();
void cleanup ();
void update (float dt);

View File

@ -214,13 +214,15 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *bowling)
Flyable::init(node, bowling, PowerupManager::POWERUP_RUBBERBALL);
} // init
// -----------------------------------------------------------------------------
/** Updates the rubber ball.
// ----------------------------------------------------------------------------
/** Updates the rubber ball.
* \param dt Time step size.
* \returns True if the rubber ball should be removed.
*/
void RubberBall::update(float dt)
bool RubberBall::updateAndDelete(float dt)
{
Flyable::update(dt);
if(Flyable::updateAndDelete(dt))
return true;
// Update the target in case that the first kart was overtaken (or has
// finished the race).
@ -229,7 +231,7 @@ void RubberBall::update(float dt)
if(!m_target) // Remove this item from the game
{
hit(NULL);
return;
return true;
}
checkDistanceToTarget();
@ -271,7 +273,9 @@ void RubberBall::update(float dt)
m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f));
setXYZ(next_xyz);
} // update
return false;
} // updateAndDelete
// ----------------------------------------------------------------------------
/** Uses Hermite splines (Catmull-Rom) to interpolate the position of the
@ -430,7 +434,6 @@ void RubberBall::hit(Kart* kart, PhysicalObject* object)
{
// Else trigger the full explosion animation
kart->handleExplosion(kart->getXYZ(), /*direct hit*/true);
projectile_manager->notifyRemove();
setHasHit();
}
return;

View File

@ -125,11 +125,15 @@ public:
RubberBall (Kart* kart);
virtual ~RubberBall();
static void init(const XMLNode &node, scene::IMesh *bowling);
virtual void update (float dt);
virtual bool updateAndDelete(float dt);
virtual void hit (Kart* kart, PhysicalObject* obj=NULL);
// ------------------------------------------------------------------------
/** This object does not create an explosion, all affects on
* karts are handled by this hit() function. */
virtual bool needsExplosion() const {return false;}
virtual HitEffect *getHitEffect() const {return NULL; }
// ------------------------------------------------------------------------
/** Plunger does not need an explosion effect. */
virtual bool needsExplosion() const { return false; }
}; // RubberBall