Fixed #879: avoid too many basket balls at the same time by introducing

a minimum amount of time (atm 15 seconds) before the next basket ball
can be found. Thanks to nixt for the patch.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12722 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2013-05-03 06:48:47 +00:00
parent 81378440ba
commit 7ab65aee16
6 changed files with 84 additions and 43 deletions

View File

@ -26,6 +26,8 @@
target-max-angle: Once the ball is aiming for its
target, it can at most change the angle
this much per second(!).
time-between-balls: Reduces the frequency with which rubber
balls are found to 1 every 'timer' seconds.
min-interpolation-distance: how far the control
points (which are center of squads)
must be from each other. A large value
@ -61,6 +63,7 @@
early-target-factor="1"
target-distance="15" target-max-angle = "90"
min-interpolation-distance="5"
time-between-balls="15"
squash-slowdown="0.5" squash-duration="2"
delete-time="5.0" max-height-difference="10" />
<item name="parachute" icon="parachute-icon.png"

View File

@ -25,6 +25,7 @@
#include "items/attachment.hpp"
#include "items/item_manager.hpp"
#include "items/projectile_manager.hpp"
#include "items/rubber_ball.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/kart_properties.hpp"
@ -408,9 +409,27 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
int position = m_owner->getPosition();
unsigned int n=1;
PowerupManager::PowerupType new_powerup =
powerup_manager->getRandomPowerup(position, &n);
PowerupManager::PowerupType new_powerup;
// Check if rubber ball is the current power up held by the kart. If so,
// reset the bBallCollectTime to 0 before giving new powerup.
if(m_type == PowerupManager::POWERUP_RUBBERBALL)
powerup_manager->setBallCollectTime(0);
// Check if two bouncing balls are collected less than getRubberBallTimer()
//seconds apart. If yes, then call getRandomPowerup again. If no, then break.
for(int i=0; i<20; i++)
{
new_powerup = powerup_manager->getRandomPowerup(position, &n);
if(new_powerup != PowerupManager::POWERUP_RUBBERBALL ||
( World::getWorld()->getTime() - powerup_manager->getBallCollectTime()) >
RubberBall::getTimeBetweenRubberBalls() )
break;
}
if(new_powerup == PowerupManager::POWERUP_RUBBERBALL)
powerup_manager->setBallCollectTime(World::getWorld()->getTime());
// Always add a new powerup in ITEM_MODE_NEW (or if the kart
// doesn't have a powerup atm).
if(m_type == PowerupManager::POWERUP_NOTHING ||

View File

@ -112,6 +112,9 @@ private:
/** Maximum turn angle for steering of homing powerups. */
float m_all_max_turn_angle[POWERUP_MAX];
/** Last time the bouncing ball was collected */
float m_rubber_ball_collect_time;
/** The mesh for each model (if the powerup has a model), e.g. a switch
has none. */
irr::scene::IMesh *m_all_meshes[POWERUP_MAX];
@ -160,6 +163,8 @@ public:
float getMaxTurnAngle (int type) const {return m_all_max_turn_angle[type];}
const btVector3&
getExtend (int type) const {return m_all_extends[type];}
float getBallCollectTime() const {return m_rubber_ball_collect_time;}
void setBallCollectTime(float time) {m_rubber_ball_collect_time=time;}
};

View File

@ -39,6 +39,8 @@ float RubberBall::m_st_max_height_difference;
float RubberBall::m_st_fast_ping_distance;
float RubberBall::m_st_early_target_factor;
int RubberBall::m_next_id = 0;
float RubberBall::m_time_between_balls;
// Debug only, so that we can get a feel on how well balls are aiming etc.
#undef PRINT_BALL_REMOVE_INFO
@ -150,7 +152,8 @@ void RubberBall::computeTarget()
if(m_target==m_owner && m_delete_timer < 0)
{
#ifdef PRINT_BALL_REMOVE_INFO
printf("ball %d removed because owner is target.\n", m_id);
Log::debug("RubberBall",
"ball %d removed because owner is target.", m_id);
#endif
m_delete_timer = m_st_delete_time;
}
@ -162,7 +165,8 @@ void RubberBall::computeTarget()
// aim at the owner (the ball is unlikely to hit it), and
// this will trigger the usage of the delete time in updateAndDelete
#ifdef PRINT_BALL_REMOVE_INFO
printf("ball %d removed because no more active target.\n", m_id);
Log::debug("RubberBall" "ball %d removed because no more active target.",
m_id);
#endif
m_delete_timer = m_st_delete_time;
m_target = m_owner;
@ -232,9 +236,9 @@ void RubberBall::getNextControlPoint()
/** Initialises this object with data from the power.xml file (this is a static
* function).
* \param node XML Node
* \param bowling The bowling ball mesh
* \param rubberball The rubber ball mesh
*/
void RubberBall::init(const XMLNode &node, scene::IMesh *bowling)
void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball)
{
m_st_interval = 1.0f;
m_st_squash_duration = 3.0f;
@ -246,46 +250,44 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *bowling)
m_st_max_height_difference = 10.0f;
m_st_fast_ping_distance = 50.0f;
m_st_early_target_factor = 1.0f;
m_time_between_balls = 15;
if(!node.get("interval", &m_st_interval))
printf("[powerup] Warning: no interval specified for rubber ball.\n");
Log::warn("powerup", "No interval specified for rubber ball.");
if(!node.get("squash-duration", &m_st_squash_duration))
printf(
"[powerup] Warning: no squash-duration specified for rubber ball.\n");
Log::warn("powerup",
"No squash-duration specified for rubber ball.");
if(!node.get("squash-slowdown", &m_st_squash_slowdown))
printf(
"[powerup] Warning: no squash-slowdown specified for rubber ball.\n");
Log::warn("powerup", "No squash-slowdown specified for rubber ball.");
if(!node.get("min-interpolation-distance",
&m_st_min_interpolation_distance))
printf(
"[powerup] Warning: no min-interpolation-distance specified "
"for rubber ball.\n");
Log::warn("powerup", "No min-interpolation-distance specified "
"for rubber ball.");
if(!node.get("target-distance", &m_st_target_distance))
printf(
"[powerup] Warning: no target-distance specified for rubber ball.\n");
Log::warn("powerup",
"No target-distance specified for rubber ball.");
if(!node.get("delete-time", &m_st_delete_time))
printf(
"[powerup] Warning: no delete-time specified for rubber ball.\n");
Log::warn("powerup", "No delete-time specified for rubber ball.");
if(!node.get("target-max-angle", &m_st_target_max_angle))
printf(
"[powerup] Warning: no target-max-angle specified for rubber ball.\n");
Log::warn("powerup", "No target-max-angle specified for rubber ball.");
m_st_target_max_angle *= DEGREE_TO_RAD;
if(!node.get("max-height-difference", &m_st_max_height_difference))
printf(
"[powerup] Warning: no max-height-difference specified for "
"rubber ball.\n");
Log::warn("powerup",
"No max-height-difference specified for rubber ball.");
if(!node.get("fast-ping-distance", &m_st_fast_ping_distance))
printf(
"[powerup] Warning: no fast-ping-distance specified for "
"rubber ball.\n");
Log::warn("powerup",
"No fast-ping-distance specified for rubber ball.");
if(m_st_fast_ping_distance < m_st_target_distance)
printf("Warning: ping-distance is smaller than target distance.\n"
"hat should not happen, but is ignored for now.\n");
Log::warn("powerup",
"Ping-distance is smaller than target distance.\n"
"That should not happen, but is ignored for now.");
if(!node.get("early-target-factor", &m_st_early_target_factor))
printf(
"[powerup] Warning: no early-target-factor specified for "
"rubber ball.\n");
Flyable::init(node, bowling, PowerupManager::POWERUP_RUBBERBALL);
Log::warn("powerup",
"No early-target-factor specified for rubber ball.");
if(!node.get("time-between-balls", &m_time_between_balls))
Log::warn("powerup",
"No time-between-balls specified for rubber ball.");
Flyable::init(node, rubberball, PowerupManager::POWERUP_RUBBERBALL);
} // init
// ----------------------------------------------------------------------------
@ -324,7 +326,7 @@ bool RubberBall::updateAndDelete(float dt)
{
hit(NULL);
#ifdef PRINT_BALL_REMOVE_INFO
printf("ball %d deleted.\n", m_id);
Log::debug("RubberBall", "ball %d deleted.", m_id);
#endif
return true;
}
@ -380,8 +382,8 @@ bool RubberBall::updateAndDelete(float dt)
}
if(UserConfigParams::logFlyable())
printf("newy2 %f gmth %f\n", new_y,
getMaxTerrainHeight(vertical_offset));
Log::verbose("RubberBall", "newy2 %f gmth %f", new_y,
getMaxTerrainHeight(vertical_offset));
next_xyz.setY(new_y);
m_previous_xyz = getXYZ();
@ -504,10 +506,11 @@ bool RubberBall::checkTunneling()
if(m_tunnel_count > 3)
{
#ifdef PRINT_BALL_REMOVE_INFO
printf("Ball %d nearly tunneled at %f %f %f -> %f %f %f\n",
m_id, m_previous_xyz.getX(),m_previous_xyz.getY(),
m_previous_xyz.getZ(),
getXYZ().getX(),getXYZ().getY(),getXYZ().getZ());
Log::debug("RubberBall",
"Ball %d nearly tunneled at %f %f %f -> %f %f %f",
m_id, m_previous_xyz.getX(),m_previous_xyz.getY(),
m_previous_xyz.getZ(),
getXYZ().getX(),getXYZ().getY(),getXYZ().getZ());
#endif
hit(NULL);
return true;
@ -628,7 +631,7 @@ void RubberBall::updateDistanceToTarget()
m_distance_to_target += world->getTrack()->getTrackLength();
}
if(UserConfigParams::logFlyable())
printf("ball %d: target %f %f %f distance_2_target %f \n",
printf("ball %d: target %f %f %f distance_2_target %f",
m_id, m_target->getXYZ().getX(),m_target->getXYZ().getY(),
m_target->getXYZ().getZ(),m_distance_to_target
);
@ -658,7 +661,8 @@ void RubberBall::updateDistanceToTarget()
{
m_delete_timer = m_st_delete_time;
#ifdef PRINT_BALL_REMOVE_INFO
printf("ball %d lost target (overtook?).\n", m_id);
Log::debug("RubberBall", "ball %d lost target (overtook?).",
m_id);
#endif
}
@ -690,7 +694,7 @@ bool RubberBall::hit(AbstractKart* kart, PhysicalObject* object)
{
#ifdef PRINT_BALL_REMOVE_INFO
if(kart)
printf("ball %d hit kart.\n", m_id);
Log::debug("RuberBall", "ball %d hit kart.", m_id);
#endif
if(kart && kart!=m_target)
{

View File

@ -82,6 +82,11 @@ private:
* ball will be deleted. */
static float m_st_delete_time;
/** Timer before another rubber ball can be picked up. This is to ensure
* that there are not too many rubber balls on the track in races with many
* karts. */
static float m_time_between_balls;
/** This factor is used to influence how much the rubber ball should aim
* at its target early. It used the 'distance to center of track' of its
* target, and adjusts the interpolation control points to be more or
@ -199,10 +204,12 @@ private:
public:
RubberBall (AbstractKart* kart);
virtual ~RubberBall();
static void init(const XMLNode &node, scene::IMesh *bowling);
static void init(const XMLNode &node, scene::IMesh *rubberball);
virtual bool updateAndDelete(float dt);
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
virtual const core::stringw getHitString(const AbstractKart *kart) const;
static float getTimeBetweenRubberBalls() {return m_time_between_balls;}
// ------------------------------------------------------------------------
/** This object does not create an explosion, all affects on
* karts are handled by this hit() function. */

View File

@ -243,6 +243,9 @@ void World::reset()
// Reset all data structures that depend on number of karts.
irr_driver->reset();
//Reset the Rubber Ball Collect Time to some negative value.
powerup_manager->setBallCollectTime(-100);
} // reset
//-----------------------------------------------------------------------------