Implement dynamic basket ball speed, fix #2783

This commit is contained in:
Alayan 2018-11-25 02:29:19 +01:00
parent 6f50c234a3
commit 073708c97e
10 changed files with 175 additions and 15 deletions

View File

@ -87,6 +87,9 @@
power: The power of the kart (the engine power needed to accelerate
at a given pace is proportional to mass)
max-speed: The base maximum speed of the kart in m/s
generic-max-speed: Must have the same value as max-speed. This
is the max speed independently of kart type and
of handicap, which is used by basket balls.
brake-factor: Value used when braking.
brake-time-increase: The brake force is multiplied by
(1 + brake_time) * brake_time_increase - i.e. the longer the
@ -94,7 +97,7 @@
max-speed-reverse-ratio is the percentage of max speed for reverse
gear.
-->
<engine power="950" max-speed="25" brake-factor="15"
<engine power="950" max-speed="25" generic-max-speed="25" brake-factor="15"
brake-time-increase="6" max-speed-reverse-ratio="0.65" />
<!-- Simulated gears
@ -342,15 +345,15 @@
<!-- The different difficulties (like easy, medium, hard) -->
<difficulties>
<characteristic name="easy">
<engine power="*0.7" max-speed="*0.6" />
<engine power="*0.7" max-speed="*0.6" generic-max-speed="*0.6" />
<plunger in-face-time="3" />
</characteristic>
<characteristic name="medium">
<engine power="*0.83" max-speed="*0.8" />
<engine power="*0.83" max-speed="*0.8" generic-max-speed="*0.8" />
<plunger in-face-time="4" />
</characteristic>
<characteristic name="hard">
<engine power="*0.92" max-speed="*0.92" />
<engine power="*0.92" max-speed="*0.92" generic-max-speed="*0.92" />
</characteristic>
<!-- This doesn't need to be changed because the most fast/heavy/extreme
values should also be the default ones. -->

View File

@ -16,6 +16,22 @@
<item name="switch" icon="swap-icon.png" />
<item name="swatter" icon="swatter-icon.png" />
<!-- interval: How long a single bounce takes.
min-speed-offset: The speed of the ball is calculated
by adding the speed-offset to the difficulty's
max-speed. min-speed-offset is used when the
ball is closer than min-offset-distance
to the target.
max-speed-offset: The additional speed of the ball when
farther than max-offset-distance.
speed : defines the initial speed. Mainly kept for
compatibility with flyable class
min-offset-distance: The distance under which the ball is
at minimal speed.
max-offset-distance: The distance over which the ball is
at maximal speed. If it is not equal to
min-offset-distance, the ball speeds between
both is a weighted average of the min and
max speed.
max-height: The maximum height of a bounce.
min-height: Unused mostly, but defines implicitly
the starting height (as average of
@ -57,7 +73,12 @@
tunneling.
-->
<item name="rubber-ball" icon="rubber_ball-icon.png"
model="rubber_ball.spm" speed="35.0"
model="rubber_ball.spm"
speed="40.0"
min-speed-offset="9.0"
max-speed-offset="29.0"
min-offset-distance="50.0"
max-offset-distance="250.0"
interval="1"
max-height="4.0" min-height="0"
fast-ping-distance="50"

View File

@ -26,6 +26,7 @@
#include "items/attachment.hpp"
#include "items/projectile_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp"
#include "modes/linear_world.hpp"
#include "network/network_string.hpp"
#include "network/rewind_info.hpp"
@ -49,6 +50,10 @@ int RubberBall::m_st_delete_ticks;
float RubberBall::m_st_max_height_difference;
float RubberBall::m_st_fast_ping_distance;
float RubberBall::m_st_early_target_factor;
float RubberBall::m_st_min_speed_offset;
float RubberBall::m_st_max_speed_offset;
float RubberBall::m_st_min_offset_distance;
float RubberBall::m_st_max_offset_distance;
int RubberBall::m_next_id = 0;
@ -305,16 +310,21 @@ void RubberBall::getNextControlPoint()
*/
void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball)
{
m_st_interval = 1.0f;
m_st_squash_duration = 3.0f;
m_st_squash_slowdown = 0.5f;
m_st_min_interpolation_distance = 30.0f;
m_st_target_distance = 50.0f;
m_st_target_max_angle = 25.0f;
m_st_interval = 1.0f;
m_st_squash_duration = 3.0f;
m_st_squash_slowdown = 0.5f;
m_st_min_interpolation_distance = 30.0f;
m_st_target_distance = 50.0f;
m_st_target_max_angle = 25.0f;
m_st_delete_ticks = stk_config->time2Ticks(10.0f);
m_st_max_height_difference = 10.0f;
m_st_fast_ping_distance = 50.0f;
m_st_early_target_factor = 1.0f;
m_st_max_height_difference = 10.0f;
m_st_fast_ping_distance = 50.0f;
m_st_early_target_factor = 1.0f;
m_st_min_speed_offset = 8.0f;
m_st_max_speed_offset = 28.0f;
m_st_min_offset_distance = 50.0f;
m_st_max_offset_distance = 250.0f;
if(!node.get("interval", &m_st_interval))
Log::warn("powerup", "No interval specified for basket ball.");
@ -350,6 +360,28 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball)
if(!node.get("early-target-factor", &m_st_early_target_factor))
Log::warn("powerup",
"No early-target-factor specified for basket ball.");
if(!node.get("min-speed-offset", &m_st_min_speed_offset))
Log::warn("powerup", "No min-speed-offset specified for basket ball.");
if(!node.get("max-speed-offset", &m_st_max_speed_offset))
Log::warn("powerup", "No max-speed-offset specified for basket ball.");
if(!node.get("min-offset-distance", &m_st_min_offset_distance))
Log::warn("powerup", "No min-offset-distance specified for basket ball.");
if(!node.get("max-offset-distance", &m_st_max_offset_distance))
Log::warn("powerup", "No max-offset-distance specified for basket ball.");
//sanity checks
if (m_st_min_speed_offset < 10.0f)
m_st_min_speed_offset = 10.0f;
if (m_st_min_speed_offset > m_st_max_speed_offset)
{
m_st_max_speed_offset = m_st_min_speed_offset;
}
if (m_st_max_offset_distance <= (m_st_min_offset_distance + 10.0f))
{
m_st_max_offset_distance = m_st_min_offset_distance + 10.0f;
}
Flyable::init(node, rubberball, PowerupManager::POWERUP_RUBBERBALL);
} // init
@ -395,6 +427,9 @@ bool RubberBall::updateAndDelete(int ticks)
computeTarget();
updateDistanceToTarget();
//Update the speed
updateWeightedSpeed(ticks);
// 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;
@ -507,6 +542,67 @@ void RubberBall::moveTowardsTarget(Vec3 *next_xyz, int ticks)
} // moveTowardsTarget
// ----------------------------------------------------------------------------
/** Calculates the current speed of the basket ball.
* The base basket ball speed is the target's normal max speed.
* Then an offset is applied.
* If closer than m_st_min_offset_distance ; it is m_st_min_speed_offset
* If farther than m_st_max_offset_distance ; it is m_st_max_speed_offset
* Else, it is a weighted average.
* It takes up to 5 seconds to fully change its speed
* (to avoid sudden big speed changes when the distance change suddenly
* at ball throwing, because of paths, shortcuts, etc.)
* If there is no target, it will keep its current speed
*/
void RubberBall::updateWeightedSpeed(int ticks)
{
// Don't change the speed if there is no target
if (m_delete_ticks >= 10)
{
return;
}
const KartProperties *kp = m_target->getKartProperties();
// Get the speed depending on difficulty but not on kart type/handicap
float targeted_speed = kp->getEngineGenericMaxSpeed();
float dt = stk_config->ticks2Time(ticks);
//Calculate the targeted weighted speed
if (m_distance_to_target <= m_st_min_offset_distance)
{
targeted_speed += m_st_min_speed_offset;
}
else if (m_distance_to_target > m_st_max_offset_distance)
{
targeted_speed += m_st_max_speed_offset;
}
else
{
float weight = 1.0f;
float offset = 0.0f;
weight = (m_st_max_offset_distance - m_distance_to_target)
/(m_st_max_offset_distance - m_st_min_offset_distance);
offset = weight * m_st_min_speed_offset + (1-weight) * m_st_max_speed_offset;
targeted_speed += offset;
}
//Update the real speed
//Always >= 0
float max_change = (m_st_max_speed_offset - m_st_min_speed_offset)*dt/(5.0f);
if (m_speed-targeted_speed <= max_change && m_speed-targeted_speed >= -max_change)
{
m_speed = targeted_speed;
}
else if (m_speed < targeted_speed)
{
m_speed += max_change;
}
else
{
m_speed -= max_change;
}
} // updateWeightedSpeed
// ----------------------------------------------------------------------------
/** Uses Hermite splines (Catmull-Rom) to interpolate the position of the
* ball between the control points. If the next point would be outside of

View File

@ -82,6 +82,20 @@ private:
* ball will be deleted. */
static int m_st_delete_ticks;
/** If the ball is closer to its target than min_offset_distance, the speed
* in addition to the difficulty's default max speed. */
static float m_st_min_speed_offset;
/** If the ball is farther to its target than max_offset_distance, the speed
* in addition to the difficulty's default max speed. */
static float m_st_max_speed_offset;
/** The distance to target under which the ball is the slowest */
static float m_st_min_offset_distance;
/** The distance to target over which the ball is the fastest */
static float m_st_max_offset_distance;
/** 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
@ -195,6 +209,7 @@ private:
float updateHeight();
void interpolate(Vec3 *next_xyz, int ticks);
void moveTowardsTarget(Vec3 *next_xyz, int ticks);
void updateWeightedSpeed(int ticks);
void initializeControlPoints(const Vec3 &xyz);
float getTunnelHeight(const Vec3 &next_xyz,
const float vertical_offset) const;

View File

@ -89,6 +89,8 @@ AbstractCharacteristic::ValueType AbstractCharacteristic::getType(
return TYPE_FLOAT;
case ENGINE_MAX_SPEED:
return TYPE_FLOAT;
case ENGINE_GENERIC_MAX_SPEED:
return TYPE_FLOAT;
case ENGINE_BRAKE_FACTOR:
return TYPE_FLOAT;
case ENGINE_BRAKE_TIME_INCREASE:
@ -727,6 +729,18 @@ float AbstractCharacteristic::getEngineMaxSpeed() const
return result;
} // getEngineMaxSpeed
// ----------------------------------------------------------------------------
float AbstractCharacteristic::getEngineGenericMaxSpeed() const
{
float result;
bool is_set = false;
process(ENGINE_GENERIC_MAX_SPEED, &result, &is_set);
if (!is_set)
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
getName(ENGINE_GENERIC_MAX_SPEED).c_str());
return result;
} // getEngineGenericMaxSpeed
// ----------------------------------------------------------------------------
float AbstractCharacteristic::getEngineBrakeFactor() const
{

View File

@ -95,6 +95,7 @@ public:
// Engine
ENGINE_POWER,
ENGINE_MAX_SPEED,
ENGINE_GENERIC_MAX_SPEED,
ENGINE_BRAKE_FACTOR,
ENGINE_BRAKE_TIME_INCREASE,
ENGINE_MAX_SPEED_REVERSE_RATIO,
@ -282,6 +283,7 @@ public:
float getEnginePower() const;
float getEngineMaxSpeed() const;
float getEngineGenericMaxSpeed() const;
float getEngineBrakeFactor() const;
float getEngineBrakeTimeIncrease() const;
float getEngineMaxSpeedReverseRatio() const;

View File

@ -59,7 +59,7 @@ AbstractKart::AbstractKart(const std::string& ident,
// Technically the mesh in m_kart_model needs to be grab'ed and
// released when the kart is deleted, but since the original
// kart_model is stored in the kart_properties all the time,
// there is no risk of a mesh being deleted to early.
// there is no risk of a mesh being deleted too early.
m_kart_model = m_kart_properties->getKartModelCopy(ri);
m_kart_width = m_kart_model->getWidth();
m_kart_height = m_kart_model->getHeight();

View File

@ -679,6 +679,12 @@ float KartProperties::getEngineMaxSpeed() const
return m_cached_characteristic->getEngineMaxSpeed();
} // getEngineMaxSpeed
// ----------------------------------------------------------------------------
float KartProperties::getEngineGenericMaxSpeed() const
{
return m_cached_characteristic->getEngineGenericMaxSpeed();
} // getEngineMaxSpeed
// ----------------------------------------------------------------------------
float KartProperties::getEngineBrakeFactor() const
{

View File

@ -396,6 +396,7 @@ public:
float getEnginePower() const;
float getEngineMaxSpeed() const;
float getEngineGenericMaxSpeed() const;
float getEngineBrakeFactor() const;
float getEngineBrakeTimeIncrease() const;
float getEngineMaxSpeedReverseRatio() const;

View File

@ -365,6 +365,8 @@ void XmlCharacteristic::load(const XMLNode *node)
&m_values[ENGINE_POWER]);
sub_node->get("max-speed",
&m_values[ENGINE_MAX_SPEED]);
sub_node->get("generic-max-speed",
&m_values[ENGINE_GENERIC_MAX_SPEED]);
sub_node->get("brake-factor",
&m_values[ENGINE_BRAKE_FACTOR]);
sub_node->get("brake-time-increase",