Add cannon for flyable in network

This commit is contained in:
Benau 2019-02-26 16:07:22 +08:00
parent cfbbc7c6dd
commit d00472f868
12 changed files with 203 additions and 76 deletions

View File

@ -36,6 +36,7 @@
#include "io/xml_node.hpp"
#include "items/projectile_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/cannon_animation.hpp"
#include "karts/controller/controller.hpp"
#include "karts/explosion_animation.hpp"
#include "modes/linear_world.hpp"
@ -204,6 +205,11 @@ void Flyable::init(const XMLNode &node, scene::IMesh *model,
Flyable::~Flyable()
{
removePhysics();
if (m_animation)
{
m_animation->handleResetRace();
delete m_animation;
}
} // ~Flyable
//-----------------------------------------------------------------------------
@ -377,13 +383,13 @@ void Flyable::setAnimation(AbstractKartAnimation *animation)
if (animation)
{
assert(m_animation == NULL);
Physics::getInstance()->removeBody(getBody());
// add or removeBody currently breaks animation rewind
moveToInfinity(/*set_moveable_trans*/false);
}
else // animation = NULL
{
assert(m_animation != NULL);
m_body->setWorldTransform(getTrans());
Physics::getInstance()->addBody(getBody());
}
m_animation = animation;
} // addAnimation
@ -414,11 +420,16 @@ bool Flyable::updateAndDelete(int ticks)
{
m_animation->update(ticks);
Moveable::update(ticks);
// Move the physical body to infinity so it doesn't interact with
// game objects (for easier rewind)
moveToInfinity(/*set_moveable_trans*/false);
return false;
} // if animation
m_ticks_since_thrown += ticks;
if(m_max_lifespan > -1 && m_ticks_since_thrown > m_max_lifespan)
// 32767 for max m_ticks_since_thrown so the last bit for animation save
if (m_ticks_since_thrown < 32767)
m_ticks_since_thrown += ticks;
if(m_max_lifespan > -1 && (int)m_ticks_since_thrown > m_max_lifespan)
hit(NULL);
if(m_has_hit_something) return true;
@ -510,7 +521,7 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
{
return m_owner_has_temporary_immunity &&
kart_hit == m_owner &&
m_ticks_since_thrown < stk_config->time2Ticks(2.0f);
(int)m_ticks_since_thrown < stk_config->time2Ticks(2.0f);
} // isOwnerImmunity
// ----------------------------------------------------------------------------
@ -522,7 +533,7 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const
*/
bool Flyable::hit(AbstractKart *kart_hit, PhysicalObject* object)
{
if (!m_has_server_state)
if (!m_has_server_state || hasAnimation())
return false;
// the owner of this flyable should not be hit by his own flyable
if(isOwnerImmunity(kart_hit)) return false;
@ -633,26 +644,56 @@ BareNetworkString* Flyable::saveState(std::vector<std::string>* ru)
return NULL;
ru->push_back(getUniqueIdentity());
BareNetworkString *buffer = new BareNetworkString();
CompressNetworkBody::compress(m_body->getWorldTransform(),
m_body->getLinearVelocity(), m_body->getAngularVelocity(), buffer,
m_body.get(), m_motion_state.get());
buffer->addUInt16(m_ticks_since_thrown);
BareNetworkString* buffer = new BareNetworkString();
uint16_t ticks_since_thrown_animation = (m_ticks_since_thrown & 32767) |
(hasAnimation() ? 32768 : 0);
buffer->addUInt16(ticks_since_thrown_animation);
if (hasAnimation())
m_animation->saveState(buffer);
else
{
CompressNetworkBody::compress(m_body->getWorldTransform(),
m_body->getLinearVelocity(), m_body->getAngularVelocity(), buffer,
m_body.get(), m_motion_state.get());
}
return buffer;
} // saveState
// ----------------------------------------------------------------------------
void Flyable::restoreState(BareNetworkString *buffer, int count)
{
btTransform t;
Vec3 lv, av;
CompressNetworkBody::decompress(buffer, &t, &lv, &av);
uint16_t ticks_since_thrown_animation = buffer->getUInt16();
bool has_animation_in_state =
(ticks_since_thrown_animation >> 15 & 1) == 1;
m_body->setLinearVelocity(lv);
m_body->setAngularVelocity(av);
m_body->proceedToTransform(t);
setTrans(t);
m_ticks_since_thrown = buffer->getUInt16();
if (has_animation_in_state)
{
// At the moment we only have cannon animation for rubber ball
if (!m_animation)
setAnimation(new CannonAnimation(this, buffer));
else
m_animation->restoreState(buffer);
}
else
{
if (hasAnimation())
{
// Delete unconfirmed animation, destructor of cannon animation
// will set m_animation to null
delete m_animation;
}
btTransform t;
Vec3 lv, av;
CompressNetworkBody::decompress(buffer, &t, &lv, &av);
m_body->setLinearVelocity(lv);
m_body->setAngularVelocity(av);
m_body->proceedToTransform(t);
setTrans(t);
}
m_ticks_since_thrown = ticks_since_thrown_animation & 32767;
m_has_server_state = true;
m_has_hit_something = false;
} // restoreState
@ -697,6 +738,13 @@ void Flyable::computeError()
* projectile_manager. */
void Flyable::onFireFlyable()
{
if (m_animation)
{
m_animation->handleResetRace();
delete m_animation;
m_animation = NULL;
}
m_ticks_since_thrown = 0;
m_has_hit_something = false;
m_has_server_state = true;

View File

@ -106,7 +106,7 @@ protected:
/** Time since thrown. used so a kart can't hit himself when trying
* something, and also to put some time limit to some collectibles */
int16_t m_ticks_since_thrown;
uint16_t m_ticks_since_thrown;
/* True if this flyable exists in server, and will trigger a rewind.
* For each local state it will reset it to false and call moveToInfinity,

View File

@ -72,13 +72,13 @@ RubberBall::RubberBall(AbstractKart *kart)
m_target = NULL;
m_ping_sfx = SFXManager::get()->createSoundSource("ball_bounce");
CheckManager::get()->addFlyableToCannons(this);
} // RubberBall
// ----------------------------------------------------------------------------
void RubberBall::onFireFlyable()
{
Flyable::onFireFlyable();
CheckManager::get()->addFlyableToCannons(this);
// Don't let Flyable update the terrain information, since this object
// has to do it earlier than that.
setDoTerrainInfo(false);
@ -840,6 +840,9 @@ void RubberBall::updateDistanceToTarget()
*/
bool RubberBall::hit(AbstractKart* kart, PhysicalObject* object)
{
// When moved to infinity during cannon animation do nothing
if (hasAnimation())
return false;
#ifdef PRINT_BALL_REMOVE_INFO
if(kart)
Log::debug("[RuberBall]", "ball %d hit kart.", m_id);

View File

@ -42,7 +42,7 @@
* value can be queried, the AbstractkartAnimation constructor
* resets the value to 0, so it needs to be passed in.
*/
CannonAnimation::CannonAnimation(AbstractKart *kart, CheckCannon* cc,
CannonAnimation::CannonAnimation(AbstractKart* kart, CheckCannon* cc,
float skid_rot)
: AbstractKartAnimation(kart, "CannonAnimation")
{
@ -70,7 +70,7 @@ CannonAnimation::CannonAnimation(AbstractKart* kart, BareNetworkString* buffer)
// ----------------------------------------------------------------------------
/** Constructor for a flyable. It sets the kart data to NULL.
*/
CannonAnimation::CannonAnimation(Flyable *flyable, CheckCannon* cc)
CannonAnimation::CannonAnimation(Flyable* flyable, CheckCannon* cc)
: AbstractKartAnimation(NULL, "CannonAnimation")
{
m_flyable = flyable;
@ -80,6 +80,19 @@ CannonAnimation::CannonAnimation(Flyable *flyable, CheckCannon* cc)
cc->getTargetLeft(), cc->getTargetRight(), /*skid_rot*/0);
} // CannonAnimation(Flyable*...)
// ----------------------------------------------------------------------------
/** The constructor for the cannon animation for flyable during rewind.
*/
CannonAnimation::CannonAnimation(Flyable* flyable, BareNetworkString* buffer)
: AbstractKartAnimation(NULL, "CannonAnimation")
{
m_flyable = flyable;
restoreBasicState(buffer);
m_check_cannon = NULL;
m_skid_rot = 0;
restoreData(buffer);
} // CannonAnimation
// ----------------------------------------------------------------------------
/** Common initialisation for kart-based and flyable-based animations.
* \param ipo The IPO (blender interpolation curve) which the kart
@ -226,7 +239,7 @@ CannonAnimation::~CannonAnimation()
m_kart->setVelocity(pos.getBasis()*v);
m_kart->getBody()->setAngularVelocity(btVector3(0,0,0));
}
else
else if (m_end_ticks != std::numeric_limits<int>::max())
{
m_flyable->setAnimation(NULL);
}
@ -337,9 +350,15 @@ void CannonAnimation::update(int ticks)
void CannonAnimation::saveState(BareNetworkString* buffer)
{
AbstractKartAnimation::saveState(buffer);
buffer->addUInt8((uint8_t)m_check_cannon->getIndex())
.addFloat(m_skid_rot).addFloat(m_fraction_of_line)
buffer->addUInt8((uint8_t)m_check_cannon->getIndex());
// Flyable only use Y in m_delta
if (m_kart)
{
buffer->addFloat(m_skid_rot).addFloat(m_fraction_of_line)
.add(m_current_rotation);
}
else
buffer->addFloat(m_delta.y());
} // saveState
// ----------------------------------------------------------------------------
@ -353,6 +372,11 @@ void CannonAnimation::restoreState(BareNetworkString* buffer)
void CannonAnimation::restoreData(BareNetworkString* buffer)
{
int cc_idx = buffer->getInt8();
if ((unsigned)cc_idx > CheckManager::get()->getCheckStructureCount())
{
throw std::invalid_argument(
"Server has different check structure size.");
}
CheckCannon* cc = dynamic_cast<CheckCannon*>
(CheckManager::get()->getCheckStructure(cc_idx));
if (!cc)
@ -360,9 +384,18 @@ void CannonAnimation::restoreData(BareNetworkString* buffer)
throw std::invalid_argument(
"Server has different check cannon index.");
}
float skid_rot = buffer->getFloat();
float fraction_of_line = buffer->getFloat();
btQuaternion current_rotation = buffer->getQuat();
float skid_rot = 0.0f;
float fraction_of_line = 0.0f;
btQuaternion current_rotation = btQuaternion(0, 0, 0, 1);
float delta = 0.0f;
if (m_kart)
{
skid_rot = buffer->getFloat();
fraction_of_line = buffer->getFloat();
current_rotation = buffer->getQuat();
}
else
delta = buffer->getFloat();
if (m_check_cannon != cc || skid_rot != m_skid_rot)
{
// Re-init if different or undoing the destruction of check cannon
@ -372,6 +405,11 @@ void CannonAnimation::restoreData(BareNetworkString* buffer)
m_check_cannon = cc;
m_skid_rot = skid_rot;
}
m_fraction_of_line = fraction_of_line;
m_current_rotation = current_rotation;
if (m_kart)
{
m_fraction_of_line = fraction_of_line;
m_current_rotation = current_rotation;
}
else
m_delta.setY(delta);
} // restoreData

View File

@ -40,8 +40,12 @@ class CannonAnimation: public AbstractKartAnimation
{
protected:
friend class KartRewinder;
friend class Flyable;
// ------------------------------------------------------------------------
CannonAnimation(AbstractKart* kart, BareNetworkString* buffer);
// ------------------------------------------------------------------------
CannonAnimation(Flyable* flyable, BareNetworkString* buffer);
// ------------------------------------------------------------------------
void init(Ipo *ipo, const Vec3 &start_left, const Vec3 &start_right,
const Vec3 &end_left, const Vec3 &end_right, float skid_rot);
// ------------------------------------------------------------------------

View File

@ -356,8 +356,7 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks,
}
// Update check line, so the cannon animation can be replayed correctly
for (unsigned i = 0; i < world->getNumKarts(); i++)
CheckManager::get()->resetAfterKartMove(world->getKart(i));
CheckManager::get()->resetAfterRewind();
// Now go forward through the list of rewind infos till we reach 'now':
while (world->getTicksSinceStart() < now_ticks)

View File

@ -128,51 +128,37 @@ void CheckCannon::changeDebugColor(bool is_active)
/** Adds a flyable to be tested for crossing a cannon checkline.
* \param flyable The flyable to be tested.
*/
void CheckCannon::addFlyable(Flyable *flyable)
void CheckCannon::addFlyable(Flyable* flyable)
{
m_all_flyables.push_back(flyable);
m_flyable_previous_position.push_back(flyable->getXYZ());
m_all_flyables_previous_position[flyable] = flyable->getXYZ();
} // addFlyable
// ----------------------------------------------------------------------------
/** Removes a flyable from the tests if it crosses a checkline. Used when
* the flyable is removed (e.g. explodes).
*/
void CheckCannon::removeFlyable(Flyable *flyable)
{
std::vector<Flyable*>::iterator i = std::find(m_all_flyables.begin(),
m_all_flyables.end(),
flyable);
assert(i != m_all_flyables.end());
size_t index = i - m_all_flyables.begin(); // get the index
m_all_flyables.erase(i);
m_flyable_previous_position.erase(m_flyable_previous_position.begin() + index);
} // removeFlyable
// ----------------------------------------------------------------------------
/** Overriden to also check all flyables registered with the cannon.
*/
void CheckCannon::update(float dt)
{
CheckLine::update(dt);
for (unsigned int i = 0; i < m_all_flyables.size(); i++)
for (auto& f : m_all_flyables_previous_position)
{
if (!m_all_flyables[i]->hasServerState() ||
m_all_flyables[i]->hasAnimation())
Flyable* flyable = f.first;
if (!flyable->hasServerState() || flyable->hasAnimation())
continue;
const Vec3& previous_position = f.second;
const Vec3 current_position = flyable->getXYZ();
setIgnoreHeight(true);
bool triggered = isTriggered(m_flyable_previous_position[i],
m_all_flyables[i]->getXYZ(),
/*kart index - ignore*/ -1 );
bool triggered = isTriggered(previous_position, current_position,
/*kart index - ignore*/ -1);
setIgnoreHeight(false);
m_flyable_previous_position[i] = m_all_flyables[i]->getXYZ();
if(!triggered) continue;
f.second = current_position;
if (!triggered) continue;
// Cross the checkline - add the cannon animation
//CannonAnimation* animation = new CannonAnimation(m_all_flyables[i],
// m_curve->clone(), getLeftPoint(), getRightPoint(),
// m_target_left, m_target_right);
//m_all_flyables[i]->setAnimation(animation);
CannonAnimation* animation = new CannonAnimation(flyable,
this);
flyable->setAnimation(animation);
} // for i in all flyables
} // update
@ -192,4 +178,17 @@ void CheckCannon::trigger(unsigned int kart_index)
// rotation and pass it to the CannonAnimation.
float skid_rot = kart->getSkidding()->getVisualSkidRotation();
new CannonAnimation(kart, this, skid_rot);
} // CheckCannon
} // trigger
// ----------------------------------------------------------------------------
void CheckCannon::resetAfterRewind(unsigned int kart_index)
{
CheckLine::resetAfterRewind(kart_index);
for (auto& f : m_all_flyables_previous_position)
{
Flyable* flyable = f.first;
if (!flyable->hasServerState() || flyable->hasAnimation())
continue;
f.second = flyable->getXYZ();
}
} // resetAfterRewind

View File

@ -23,6 +23,8 @@
#include "tracks/check_line.hpp"
#include "utils/cpp2011.hpp"
#include <map>
class CheckManager;
class Flyable;
class Ipo;
@ -35,8 +37,8 @@ namespace SP
}
/**
* \brief Implements a simple checkline that will cause a kart to be
* shot to a specified point.
* \brief Implements a simple checkline that will cause a kart or flyable to
* be shot to a specified point.
*
* \ingroup tracks
*/
@ -58,22 +60,37 @@ private:
/** Used to display debug information about checklines. */
std::shared_ptr<SP::SPDynamicDrawCall> m_debug_target_dy_dc;
#endif
std::vector<Flyable*> m_all_flyables;
std::vector<Vec3> m_flyable_previous_position;
std::map<Flyable*, Vec3> m_all_flyables_previous_position;
public:
CheckCannon(const XMLNode &node, unsigned int index);
// ------------------------------------------------------------------------
virtual ~CheckCannon();
// ------------------------------------------------------------------------
virtual void trigger(unsigned int kart_index) OVERRIDE;
// ------------------------------------------------------------------------
virtual void changeDebugColor(bool is_active) OVERRIDE;
// ------------------------------------------------------------------------
virtual void update(float dt) OVERRIDE;
virtual bool triggeringCheckline() const OVERRIDE { return false; }
void addFlyable(Flyable *flyable);
void removeFlyable(Flyable *flyable);
const Vec3& getTargetLeft() const { return m_target_left; }
const Vec3& getTargetRight() const { return m_target_right; }
Ipo* getIpo() const { return m_curve; }
}; // CheckLine
// ------------------------------------------------------------------------
virtual bool triggeringCheckline() const OVERRIDE { return false; }
// ------------------------------------------------------------------------
virtual void resetAfterRewind(unsigned int kart_index) OVERRIDE;
// ------------------------------------------------------------------------
void addFlyable(Flyable* flyable);
// ------------------------------------------------------------------------
/** Removes a flyable from the tests if it crosses a checkline. Used when
* the flyable is removed (e.g. explodes).
*/
void removeFlyable(Flyable* flyable)
{ m_all_flyables_previous_position.erase(flyable); }
// ------------------------------------------------------------------------
const Vec3& getTargetLeft() const { return m_target_left; }
// ------------------------------------------------------------------------
const Vec3& getTargetRight() const { return m_target_right; }
// ------------------------------------------------------------------------
Ipo* getIpo() const { return m_curve; }
}; // CheckCannon
#endif

View File

@ -89,6 +89,8 @@ public:
int indx) OVERRIDE;
virtual void reset(const Track &track) OVERRIDE;
virtual void resetAfterKartMove(unsigned int kart_index) OVERRIDE;
virtual void resetAfterRewind(unsigned int kart_index) OVERRIDE
{ resetAfterKartMove(kart_index); }
virtual void changeDebugColor(bool is_active) OVERRIDE;
virtual bool triggeringCheckline() const OVERRIDE { return true; }
// ------------------------------------------------------------------------

View File

@ -23,6 +23,7 @@
#include "io/xml_node.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "tracks/check_cannon.hpp"
#include "tracks/check_goal.hpp"
#include "tracks/check_lap.hpp"
@ -131,6 +132,20 @@ void CheckManager::resetAfterKartMove(AbstractKart *kart)
(*i)->resetAfterKartMove(kart->getWorldKartId());
} // resetAfterKartMove
// ----------------------------------------------------------------------------
/* After restoreState in rewind this is called to reset all positions of
* \ref CheckStructure to old position (for example check line).
*/
void CheckManager::resetAfterRewind()
{
World* w = World::getWorld();
for (unsigned i = 0; i < w->getNumKarts(); i++)
{
for (unsigned j = 0; j < m_all_checks.size(); j++)
m_all_checks[j]->resetAfterRewind(w->getKart(i)->getWorldKartId());
}
} // resetAfterRewind
// ----------------------------------------------------------------------------
/** Adds a flyable object to be tested against cannons. This will allow
* bowling- and rubber-balls to fly in a cannon.

View File

@ -53,6 +53,7 @@ public:
void update(float dt);
void reset(const Track &track);
void resetAfterKartMove(AbstractKart *kart);
void resetAfterRewind();
unsigned int getLapLineIndex() const;
int getChecklineTriggering(const Vec3 &from, const Vec3 &to) const;
// ------------------------------------------------------------------------

View File

@ -106,7 +106,8 @@ public:
CheckStructure(const XMLNode &node, unsigned int index);
virtual ~CheckStructure() {};
virtual void update(float dt);
virtual void resetAfterKartMove(unsigned int kart_index) {};
virtual void resetAfterKartMove(unsigned int kart_index) {}
virtual void resetAfterRewind(unsigned int kart_index) {}
virtual void changeDebugColor(bool is_active) {}
/** True if going from old_pos to new_pos crosses this checkline. This function
* is called from update (of the checkline structure).