Completely revamps slipstreaming

This commit is contained in:
Alayan-stk-2 2018-04-13 08:40:03 +02:00 committed by GitHub
parent b2bdd49931
commit f41b537477
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -36,17 +36,21 @@
#include "utils/constants.hpp"
#include "utils/mini_glm.hpp"
/** Creates the slip stream object using a moving texture.
/** Creates the slip stream object
* \param kart Pointer to the kart to which the slip stream
* belongs to.
*/
SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
SlipStream::SlipStream(AbstractKart* kart)
{
m_node = NULL;
m_kart = kart;
#ifndef SERVER_ONLY
if (CVS->isGLSL())
{
m_moving = new MovingTexture(0.0f, 0.0f);
m_moving_fast = new MovingTexture(0.0f, 0.0f);
Material* material =
material_manager->getMaterialSPM("slipstream.png", "");
SP::SPMesh* mesh = createMesh(material);
@ -59,23 +63,42 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
m_node->setVisible(false);
SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(m_node);
assert(spmn);
setSPTM(spmn->getTextureMatrix(0).data());
m_moving->setSPTM(spmn->getTextureMatrix(0).data());
material = material_manager->getMaterialSPM("slipstream2.png", "");
mesh = createMesh(material);
m_node_fast = irr_driver->addMesh(mesh, "slipstream2");
mesh->drop();
debug_name = m_kart->getIdent()+" (slip-stream2)";
m_node_fast->setName(debug_name.c_str());
m_node_fast->setPosition(core::vector3df(0, 0 * 0.25f + 2.5f,
m_kart->getKartLength()));
m_node_fast->setVisible(false);
spmn = dynamic_cast<SP::SPMeshNode*>(m_node_fast);
assert(spmn);
m_moving_fast->setSPTM(spmn->getTextureMatrix(0).data());
}
#endif
m_slipstream_time = 0.0f;
float length = m_kart->getKartProperties()->getSlipstreamLength();
//The kart starts at 0 speed anyway
float length = 0.0f;
float kw = m_kart->getKartWidth();
float ew = m_kart->getKartProperties()->getSlipstreamWidth();
float ew = 0.0f;
float kl = m_kart->getKartLength();
//making the slipstream quad start at the kart front
//allows better results when the kart turns
Vec3 p[4];
p[0]=Vec3(-kw*0.5f, 0, -kl*0.5f );
p[0]=Vec3(-kw*0.5f, 0, kl*0.5f );
p[1]=Vec3(-ew*0.5f, 0, -kl*0.5f-length);
p[2]=Vec3( ew*0.5f, 0, -kl*0.5f-length);
p[3]=Vec3( kw*0.5f, 0, -kl*0.5f );
p[3]=Vec3( kw*0.5f, 0, kl*0.5f );
m_slipstream_quad = new Quad(p[0], p[1], p[2], p[3]);
//The position will be corrected in the update anyway
m_slipstream_inner_quad = new Quad(p[0], p[1], p[2], p[3]);
#ifndef SERVER_ONLY
if (UserConfigParams::m_slipstream_debug)
{
@ -97,6 +120,22 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
m_debug_dc->recalculateBoundingBox();
m_debug_dc->setParent(m_kart->getNode());
SP::addDynamicDrawCall(m_debug_dc);
m_debug_dc2 = std::make_shared<SP::SPDynamicDrawCall>
(scene::EPT_TRIANGLE_STRIP,
SP::SPShaderManager::get()->getSPShader("additive"),
material_manager->getDefaultSPMaterial("additive"));
m_debug_dc2->getVerticesVector().resize(4);
v = m_debug_dc2->getVerticesVector().data();
for (unsigned i = 0; i < 4; i++)
{
v[i].m_position = p[idx[i]].toIrrVector();
v[i].m_normal = 0x1FF << 10;
v[i].m_color = red;
}
m_debug_dc2->recalculateBoundingBox();
m_debug_dc2->setParent(m_kart->getNode());
SP::addDynamicDrawCall(m_debug_dc2);
}
#endif
} // SlipStream
@ -110,11 +149,22 @@ SlipStream::~SlipStream()
{
irr_driver->removeNode(m_node);
}
if (m_node_fast)
{
irr_driver->removeNode(m_node_fast);
}
if (m_debug_dc)
{
m_debug_dc->removeFromSP();
}
if (m_debug_dc2)
{
m_debug_dc2->removeFromSP();
}
delete m_slipstream_quad;
delete m_slipstream_inner_quad;
delete m_moving;
delete m_moving_fast;
} // ~SlipStream
@ -246,41 +296,56 @@ SP::SPMesh* SlipStream::createMesh(Material* material)
/** Sets the animation intensity (or speed).
* \param f Intensity: 0 = no slip stream,
* 1 = collecting
* 2 = using slip stream bonus
* 2 = bonus can be used
*/
void SlipStream::setIntensity(float f, const AbstractKart *kart)
{
if (!kart || !m_node)
if (!kart || !m_node || !m_node_fast)
{
if (m_node)
{
m_node->setVisible(false);
}
if (m_node_fast)
{
m_node_fast->setVisible(false);
}
return;
}
m_node->setVisible(true);
float ktf = m_kart->getKartProperties()->getSlipstreamCollectTime();
const float above_terrain = 0.2f;
core::vector3df my_pos = m_kart->getNode()->getPosition();
my_pos.Y = m_kart->getHoT()+above_terrain;
m_node->setPosition(my_pos);
core::vector3df other_pos = kart->getNode()->getPosition();
other_pos.Y = kart->getHoT()+above_terrain;
core::vector3df diff = other_pos - my_pos;
core::vector3df rotation = diff.getHorizontalAngle();
m_node->setRotation(rotation);
float fs = diff.getLength()/m_length;
m_node->setPosition(my_pos);
m_node->setRotation(rotation);
m_node->setScale(core::vector3df(1, 1, fs));
// For real testing in game: this needs some tuning!
m_node->setVisible(f!=0);
MovingTexture::setSpeed(f, 0);
m_node_fast->setPosition(my_pos);
m_node_fast->setRotation(rotation);
m_node_fast->setScale(core::vector3df(1, 1, fs));
m_node->setVisible(f>0.0f && f<ktf);
m_node_fast->setVisible(f>=ktf);
//specify the texture speed movement
if (f > 8.0f) f = 8.0f;
f = f/2;
m_moving->setSpeed(f, 0);
m_moving_fast->setSpeed(f, 0);
return;
// For debugging: make the slip stream effect visible all the time
m_node->setVisible(true);
MovingTexture::setSpeed(1.0f, 0.0f);
m_moving->setSpeed(1.0f, 0.0f);
} // setIntensity
//-----------------------------------------------------------------------------
@ -302,8 +367,7 @@ void SlipStream::updateSlipstreamPower()
// See if we are currently using accumulated slipstream credits:
// -------------------------------------------------------------
if(m_slipstream_mode==SS_USE)
{
setIntensity(2.0f, NULL);
{
const KartProperties *kp = m_kart->getKartProperties();
m_kart->increaseMaxSpeed(MaxSpeed::MS_INCREASE_SLIPSTREAM,
kp->getSlipstreamMaxSpeedIncrease(),
@ -320,23 +384,160 @@ void SlipStream::updateSlipstreamPower()
* black: kart too slow
* red: not inside of slipstream area
* green: slipstream is being accumulated.
* \param inner : bool to know if we apply the color to the inner quad or to the main one
*/
void SlipStream::setDebugColor(const video::SColor &color)
void SlipStream::setDebugColor(const video::SColor &color, bool inner)
{
if (!m_debug_dc)
if (!inner)
{
return;
}
if (!m_debug_dc)
{
return;
}
video::S3DVertexSkinnedMesh* v = m_debug_dc->getVerticesVector().data();
for (unsigned i = 0; i < 4; i++)
video::S3DVertexSkinnedMesh* v = m_debug_dc->getVerticesVector().data();
for (unsigned i = 0; i < 4; i++)
{
v[i].m_color = color;
}
m_debug_dc->setUpdateOffset(0);
}
else
{
v[i].m_color = color;
}
m_debug_dc->setUpdateOffset(0);
if (!m_debug_dc2)
{
return;
}
video::S3DVertexSkinnedMesh* v = m_debug_dc2->getVerticesVector().data();
for (unsigned i = 0; i < 4; i++)
{
v[i].m_color = color;
}
m_debug_dc2->setUpdateOffset(0);
}
} // setDebugColor
//-----------------------------------------------------------------------------
/** UpdateQuad
*/
void SlipStream::updateQuad()
{
//Change the quad form to counteract the mismatch between
//kart orientation and real direction
//Computations are contrieved by the fact we have several
//different 3D vector, one for each library.
Vec3 moving_xyz = m_kart->getPreviousXYZ() - m_kart->getXYZ();
//retrieve a vector rotated to kart direction
btScalar bx,by,bz;//a btScalar is a float or a double
bx = 1.0f;
by = bz = 0.0f;
btVector3 rotated_base;
rotated_base.setValue(bx,by,bz);
btQuaternion rotation = m_kart->getRotation();
rotated_base = quatRotate(rotation,rotated_base);
Vec3 direction_vector;
//Z and X need to be inverted and X multiplied by -1 to match moving_xyz
direction_vector = Vec3(rotated_base.getZ(), rotated_base.getY(), -rotated_base.getX());
//normalize the moving vector
float vec_length = moving_xyz.x()*moving_xyz.x()
+ moving_xyz.y()*moving_xyz.y()
+ moving_xyz.z()*moving_xyz.z();
if (vec_length != 0)
{
vec_length = core::reciprocal_squareroot(vec_length);
float x,y,z;
x = moving_xyz.x() * vec_length;
y = moving_xyz.y() * vec_length;
z = moving_xyz.z() * vec_length;
moving_xyz = Vec3(x,y,z);
}
//This vector gives us the change to apply in absolute coordinates
Vec3 noffset = moving_xyz - direction_vector;
//But the quad position is in the kart coordinate space
//So we rotate it back
rotated_base.setValue(-noffset.z(),noffset.y(),noffset.x());
rotation = rotation.inverse();
rotated_base = quatRotate(rotation,rotated_base);
noffset = Vec3(rotated_base.getZ(), rotated_base.getY(), -rotated_base.getX());
float speed_factor = m_kart->getSpeed()/m_kart->getKartProperties()->getSlipstreamBaseSpeed();
float length = m_kart->getKartProperties()->getSlipstreamLength()*speed_factor;
float kw = m_kart->getKartWidth();
float ew = m_kart->getKartProperties()->getSlipstreamWidth()*speed_factor;
float kl = m_kart->getKartLength();
float offx = (kl*0.5f+length)*noffset.x();
float offz = (kl*0.5f+length)*noffset.z();
//making the slipstream quad start at the kart front
//allows better results when the kart turns
Vec3 p[4];
p[0]=Vec3(-kw*0.5f, 0, kl*0.5f );
p[1]=Vec3(-ew*0.5f+offx, 0, -kl*0.5f-length+offz);
p[2]=Vec3( ew*0.5f+offx, 0, -kl*0.5f-length+offz);
p[3]=Vec3( kw*0.5f, 0, kl*0.5f );
//Update the slipstreaming quad
m_slipstream_quad->setQuad(p[0], p[1], p[2], p[3]);
#ifndef SERVER_ONLY
//recalculate quad position for debug drawing
if (UserConfigParams::m_slipstream_debug)
{
video::S3DVertexSkinnedMesh* v =
m_debug_dc->getVerticesVector().data();
unsigned idx[] = { 0, 3, 1, 2 };
for (unsigned i = 0; i < 4; i++)
{
v[i].m_position = p[idx[i]].toIrrVector();
}
m_debug_dc->recalculateBoundingBox();
m_debug_dc->setParent(m_kart->getNode());
SP::addDynamicDrawCall(m_debug_dc);
}
#endif
float inner_factor = m_kart->getKartProperties()->getSlipstreamInnerFactor()*sqrt(speed_factor);
length = length*inner_factor;
ew = ew*inner_factor;
if (ew > 0.5f) ew -= 0.5f;
else ew = 0;
offx = (kl*0.5f+length)*noffset.x();
offz = (kl*0.5f+length)*noffset.z();
p[0]=Vec3(-kw*0.5f, 0, kl*0.5f );
p[1]=Vec3(-ew*0.5f+offx, 0, -kl*0.5f-length+offz);
p[2]=Vec3( ew*0.5f+offx, 0, -kl*0.5f-length+offz);
p[3]=Vec3( kw*0.5f, 0, kl*0.5f );
//Update the slipstreaming inner quad
m_slipstream_inner_quad->setQuad(p[0], p[1], p[2], p[3]);
#ifndef SERVER_ONLY
//recalculate inner quad position for debug drawing
if (UserConfigParams::m_slipstream_debug)
{
video::S3DVertexSkinnedMesh* v =
m_debug_dc2->getVerticesVector().data();
unsigned idx[] = { 0, 3, 1, 2 };
for (unsigned i = 0; i < 4; i++)
{
v[i].m_position = p[idx[i]].toIrrVector();
}
m_debug_dc2->recalculateBoundingBox();
m_debug_dc2->setParent(m_kart->getNode());
SP::addDynamicDrawCall(m_debug_dc2);
}
#endif
} //updateQuad
//-----------------------------------------------------------------------------
/** Update, called once per timestep.
* \param dt Time step size.
@ -350,38 +551,53 @@ void SlipStream::update(float dt)
|| m_kart->isGhostKart())
return;
MovingTexture::update(dt);
//there is no slipstreaming at low speed
//and the quad may do weird things if going in reverse
if(m_kart->getSpeed() > 1.0f)
{
updateQuad();
}
m_moving->update(dt);
m_moving_fast->update(dt);
if(m_slipstream_mode==SS_USE)
{
m_slipstream_time -= dt;
m_slipstream_time -= dt;//This makes slipstream_time decrease twice faster
if(m_slipstream_time<0) m_slipstream_mode=SS_NONE;
}
updateSlipstreamPower();
// If this kart is too slow for slipstreaming taking effect, do nothing
// Use a margin because what really matters is the target's speed
// If this kart is much slower than the minSpeed, then either its
// targets are slower too, or it won't stay long enough behind them
// --------------------------------------------------------------------
// Define this to get slipstream effect shown even when the karts are
// not moving. This is useful for debugging the graphics of SS-ing.
//#define DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
if(m_kart->getSpeed() < kp->getSlipstreamMinSpeed())
if(m_kart->getSpeed() < kp->getSlipstreamMinSpeed() - 2.0f)
{
setIntensity(0, NULL);
m_slipstream_mode = SS_NONE;
if(UserConfigParams::m_slipstream_debug)
setDebugColor(video::SColor(255, 0, 0, 0));
{
setDebugColor(video::SColor(255, 0, 0, 0),false);
setDebugColor(video::SColor(255, 0, 0, 0),true);
}
return;
}
#endif
// Then test if this kart is in the slipstream range of another kart:
// ------------------------------------------------------------------
World *world = World::getWorld();
unsigned int num_karts = world->getNumKarts();
bool is_sstreaming = false;
m_target_kart = NULL;
World *world = World::getWorld();
unsigned int num_karts = world->getNumKarts();
bool is_sstreaming = false;
bool is_inner_sstreaming = false;
m_target_kart = NULL;
// Note that this loop can not be simply replaced with a shorter loop
// using only the karts with a better position - since a kart might
@ -389,6 +605,7 @@ void SlipStream::update(float dt)
for(unsigned int i=0; i<num_karts; i++)
{
m_target_kart= world->getKart(i);
// Don't test for slipstream with itself, a kart that is being
// rescued or exploding, a ghost kart or an eliminated kart
if(m_target_kart==m_kart ||
@ -396,6 +613,8 @@ void SlipStream::update(float dt)
m_target_kart->isGhostKart() ||
m_target_kart->isEliminated() ) continue;
const KartProperties *kp_target = m_target_kart->getKartProperties();
// Transform this kart location into target kart point of view
Vec3 lc = m_target_kart->getTrans().inverse()(m_kart->getXYZ());
@ -404,37 +623,51 @@ void SlipStream::update(float dt)
if (fabsf(lc.y()) > 6.0f) continue;
// If the kart we are testing against is too slow, no need to test
// slipstreaming. Note: We compare the speed of the other kart
// against the minimum slipstream speed kart of this kart - not
// entirely sure if this makes sense, but it makes it easier to
// give karts different slipstream properties.
// slipstreaming.
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
if (m_target_kart->getSpeed() < kp->getSlipstreamMinSpeed())
if (m_target_kart->getSpeed() < kp_target->getSlipstreamMinSpeed())
{
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
{
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 0, 0, 0));
->setDebugColor(video::SColor(255, 0, 0, 0), false);
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 0, 0, 0), true);
}
continue;
}
#endif
// Quick test: the kart must be not more than
// slipstream length+0.5*kart_length()+0.5*target_kart_length
// slipstream length+0.5*kart_length()+target_kart_length
// away from the other kart
// (additional target_kart_length because that kart's center
// is not the center of rotation of the slipstreaming quad)
Vec3 delta = m_kart->getXYZ() - m_target_kart->getXYZ();
float l = kp->getSlipstreamLength()
+ 0.5f*( m_target_kart->getKartLength()
+m_kart->getKartLength() );
float l = kp_target->getSlipstreamLength();
float speed_factor = m_target_kart->getSpeed()
/kp_target->getSlipstreamBaseSpeed();
l = l*speed_factor + m_target_kart->getKartLength()
+ 0.5f*m_kart->getKartLength();
if(delta.length2() > l*l)
{
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 0, 0, 128));
continue;
}
// Real test: if in slipstream quad of other kart
// Real test 1: if in inner slipstream quad of other kart
if(m_target_kart->getSlipstream()->m_slipstream_inner_quad
->pointInside(lc))
{
is_inner_sstreaming = true;
is_sstreaming = true;
break;
}
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 0, 0, 255),true);
// Real test2: if in slipstream quad of other kart
if(m_target_kart->getSlipstream()->m_slipstream_quad
->pointInside(lc))
{
@ -444,26 +677,36 @@ void SlipStream::update(float dt)
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 0, 0, 255));
->setDebugColor(video::SColor(255, 0, 0, 255),false);
} // for i < num_karts
if(!is_sstreaming)
{
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
{
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 255, 0, 0));
->setDebugColor(video::SColor(255, 255, 0, 0),false);
m_target_kart->getSlipstream()
->setDebugColor(video::SColor(255, 0, 255, 0),true);
}
if(isSlipstreamReady())
{
// The first time slipstream is ready after collecting
// and you are leaving the slipstream area, you get a
// zipper bonus.
// and you are leaving the slipstream area, you get an
// instant speed_increase
if(m_slipstream_mode==SS_COLLECT)
{
m_slipstream_mode = SS_USE;
m_kart->handleZipper();
m_slipstream_time = kp->getSlipstreamCollectTime();
m_kart->instantSpeedIncrease(MaxSpeed::MS_INCREASE_SLIPSTREAM,
kp->getSlipstreamMaxSpeedIncrease(),
kp->getSlipstreamMaxSpeedIncrease(),
kp->getSlipstreamAddPower(),
kp->getSlipstreamDuration(),
kp->getSlipstreamFadeOutTime());
return;
}
}
@ -475,17 +718,30 @@ void SlipStream::update(float dt)
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
m_target_kart->getSlipstream()->setDebugColor(video::SColor(255, 0, 255, 0));
m_target_kart->getSlipstream()->setDebugColor(video::SColor(255, 128, 255, 0),false);
// Accumulate slipstream credits now
m_slipstream_time = m_slipstream_mode==SS_NONE ? dt
: m_slipstream_time+dt;
//Twice as fast in the inner quad
if (is_inner_sstreaming)
{
m_slipstream_time = m_slipstream_mode==SS_NONE ? 2*dt : m_slipstream_time+2*dt;
if(UserConfigParams::m_slipstream_debug &&
m_kart->getController()->isLocalPlayerController())
m_target_kart->getSlipstream()->setDebugColor(video::SColor(255, 0, 255, 128),true);
}
else
{
m_slipstream_time = m_slipstream_mode==SS_NONE ? dt : m_slipstream_time+dt;
}
//Cap the possible credits. Keep this similar to the animation speed cap.
if (m_slipstream_time > 8.0f)
m_slipstream_time = 8.0f;
if(isSlipstreamReady())
m_kart->setSlipstreamEffect(9.0f);
setIntensity(m_slipstream_time, m_target_kart);
m_slipstream_mode = SS_COLLECT;
if (m_slipstream_time > kp->getSlipstreamCollectTime())
{
setIntensity(1.0f, m_target_kart);
}
} // update