// ----------------------------------------------------------------------------- void Plunger::update(float dt) { // In keep-alive mode, just update the rubber band if(m_keep_alive >= 0) { m_keep_alive -= dt; if(m_keep_alive<=0) { setHasHit(); projectile_manager->notifyRemove(); } if(m_rubber_band != NULL) m_rubber_band->update(dt); return; } // Else: update the flyable and rubber band Flyable::update(dt); if(m_rubber_band != NULL) m_rubber_band->update(dt); if(getHoT()==Track::NOHIT) return; } // update
/** 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) { bool can_be_deleted = Flyable::updateAndDelete(dt); if(can_be_deleted) return true; const AbstractKart *kart=0; Vec3 direction; float minDistance; getClosestKart(&kart, &minDistance, &direction); if(kart && minDistance<m_st_max_distance_squared) // move bowling towards kart { // limit angle, so that the bowling ball does not turn // around to hit a kart behind if(fabs(m_body->getLinearVelocity().angle(direction)) < 1.3) { direction*=1/direction.length()*m_st_force_to_target; m_body->applyCentralForce(direction); } } // Bowling balls lose energy (e.g. when hitting the track), so increase // the speed if the ball is too slow, but only if it's not too high (if // the ball is too high, it is 'pushed down', which can reduce the // speed, which causes the speed to increase, which in turn causes // the ball to fly higher and higher. //btTransform trans = getTrans(); float hat = getXYZ().getY()-getHoT(); if(hat-0.5f*m_extend.getY()<0.01f) { const Material *material = getMaterial(); if(!material || material->isDriveReset()) { hit(NULL); return true; } } btVector3 v = m_body->getLinearVelocity(); float vlen = v.length2(); if (hat<= m_max_height) { 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. } // 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); return true; } if (m_roll_sfx->getStatus()==SFXBase::SFX_PLAYING) m_roll_sfx->setPosition(getXYZ()); return false; } // updateAndDelete
/** Updates the rubber ball. * \param dt Time step size. * \returns True if the rubber ball should be removed. */ bool RubberBall::updateAndDelete(float dt) { LinearWorld *world = dynamic_cast<LinearWorld*>(World::getWorld()); // FIXME: what does the rubber ball do in case of battle mode?? if(!world) return true; if(m_delete_timer>0) { m_delete_timer -= dt; if(m_delete_timer<=0) { hit(NULL); #ifdef PRINT_BALL_REMOVE_INFO Log::debug("RubberBall", "ball %d deleted.", m_id); #endif return true; } } // Update the target in case that the first kart was overtaken (or has // finished the race). computeTarget(); updateDistanceToTarget(); // Determine the new position. This new position is only temporary, // since it still needs to be adjusted for the height of the terrain. Vec3 next_xyz; if(m_aiming_at_target) moveTowardsTarget(&next_xyz, dt); else interpolate(&next_xyz, dt); // If the ball is close to the ground, we have to start the raycast // slightly higher (to avoid that the ball tunnels through the floor). // But if the ball is close to the ceiling of a tunnel and we would // start the raycast slightly higher, the ball might end up on top // of the ceiling. // The ball is considered close to the ground if the height above the // terrain is less than half the current maximum height. bool close_to_ground = 2.0*m_previous_height < m_current_max_height; float vertical_offset = close_to_ground ? 4.0f : 2.0f; // Note that at this stage getHoT still reports the height at // the previous location (since TerrainInfo wasn't updated). On // the other hand, we can't update TerrainInfo without having // at least a good estimation of the height. next_xyz.setY(getHoT() + vertical_offset); // Update height of terrain (which isn't done as part of // Flyable::update for rubber balls. TerrainInfo::update(next_xyz); m_height_timer += dt; float height = updateHeight()+m_extend.getY()*0.5f; float new_y = getHoT()+height; if(UserConfigParams::logFlyable()) printf("ball %d: %f %f %f height %f new_y %f gethot %f ", m_id, next_xyz.getX(), next_xyz.getY(), next_xyz.getZ(), height, new_y, getHoT()); // No need to check for terrain height if the ball is low to the ground if(height > 0.5f) { float terrain_height = getMaxTerrainHeight(vertical_offset) - m_extend.getY(); if(new_y>terrain_height) new_y = terrain_height; } if(UserConfigParams::logFlyable()) Log::verbose("RubberBall", "newy2 %f gmth %f", new_y, getMaxTerrainHeight(vertical_offset)); next_xyz.setY(new_y); m_previous_xyz = getXYZ(); m_previous_height = next_xyz.getY()-getHoT(); setXYZ(next_xyz); if(checkTunneling()) return true; // Determine new distance along track TrackSector::update(next_xyz); // Ball squashing: // =============== if(height<1.5f*m_extend.getY()) m_node->setScale(core::vector3df(1.0f, height/m_extend.getY(),1.0f)); else m_node->setScale(core::vector3df(1.0f, 1.0f, 1.0f)); return Flyable::updateAndDelete(dt); } // updateAndDelete
/** 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_has_hit_something) return true; //Vec3 xyz=getBody()->getWorldTransform().getOrigin(); const Vec3 &xyz=getXYZ(); // Check if the flyable is outside of the track. If so, explode it. const Vec3 *min, *max; World::getWorld()->getTrack()->getAABB(&min, &max); // I have seen that the bullet AABB can be slightly different from the // one computed here - I assume due to minor floating point errors // (e.g. 308.25842 instead of 308.25845). To avoid a crash with a bullet // assertion (see bug 3058932) I add an epsilon here - but admittedly // that does not really explain the bullet crash, since bullet tests // against its own AABB, and should therefore not cause the assertion. // But since we couldn't reproduce the problem, and the epsilon used // here does not hurt, I'll leave it in. float eps = 0.1f; assert(!isnan(xyz.getX())); assert(!isnan(xyz.getY())); assert(!isnan(xyz.getZ())); if(xyz[0]<(*min)[0]+eps || xyz[2]<(*min)[2]+eps || xyz[1]<(*min)[1]+eps || xyz[0]>(*max)[0]-eps || xyz[2]>(*max)[2]-eps || xyz[1]>(*max)[1]-eps ) { hit(NULL); // flyable out of track boundary return true; } // Add the position offset so that the flyable can adjust its position // (usually to do the raycast from a slightly higher position to avoid // problems finding the terrain in steep uphill sections). if(m_do_terrain_info) TerrainInfo::update(xyz+m_position_offset); if(m_adjust_up_velocity) { float hat = xyz.getY()-getHoT(); // Use the Height Above Terrain to set the Z velocity. // 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); Vec3 v = getVelocity(); assert(!isnan(v.getX())); assert(!isnan(v.getX())); assert(!isnan(v.getX())); float heading = atan2f(v.getX(), v.getZ()); assert(!isnan(heading)); float pitch = getTerrainPitch(heading); float vel_up = m_force_updown*(delta); if (hat < m_max_height) // take into account pitch of surface vel_up += v.length_2d()*tanf(pitch); assert(!isnan(vel_up)); v.setY(vel_up); setVelocity(v); } // if m_adjust_up_velocity Moveable::update(dt); return false; } // updateAndDelete