Fix swatter issue

This commit is contained in:
Benau 2015-12-08 16:47:42 +08:00
parent c789b1a8df
commit 140a229f71
4 changed files with 137 additions and 194 deletions

View File

@ -59,7 +59,10 @@ Swatter::Swatter(AbstractKart *kart, bool was_bomb,
: AttachmentPlugin(kart) : AttachmentPlugin(kart)
{ {
m_animation_phase = SWATTER_AIMING; m_animation_phase = SWATTER_AIMING;
m_discard_now = false;
m_discard_timeout = 0.0f;
m_target = NULL; m_target = NULL;
m_closest_kart = NULL;
m_removing_bomb = was_bomb; m_removing_bomb = was_bomb;
m_bomb_scene_node = bomb_scene_node; m_bomb_scene_node = bomb_scene_node;
m_swat_bomb_frame = 0.0f; m_swat_bomb_frame = 0.0f;
@ -112,7 +115,8 @@ Swatter::~Swatter()
*/ */
bool Swatter::updateAndTestFinished(float dt) bool Swatter::updateAndTestFinished(float dt)
{ {
bool discard_now = false; if (!m_discard_now)
{
if (m_removing_bomb) if (m_removing_bomb)
{ {
m_swat_bomb_frame += dt*25.0f; m_swat_bomb_frame += dt*25.0f;
@ -122,10 +126,10 @@ bool Swatter::updateAndTestFinished(float dt)
if (m_swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL) if (m_swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL)
{ {
m_bomb_scene_node->setPosition(m_bomb_scene_node->getPosition() + m_bomb_scene_node->setPosition(m_bomb_scene_node
core::vector3df(-dt*15.0f, 0.0f, 0.0f) ); ->getPosition() + core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
m_bomb_scene_node->setRotation(m_bomb_scene_node->getRotation() + m_bomb_scene_node->setRotation(m_bomb_scene_node
core::vector3df(-dt*15.0f, 0.0f, 0.0f) ); ->getRotation() + core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
} }
if (m_swat_bomb_frame >= m_scene_node->getEndFrame()) if (m_swat_bomb_frame >= m_scene_node->getEndFrame())
@ -150,15 +154,20 @@ bool Swatter::updateAndTestFinished(float dt)
{ {
chooseTarget(); chooseTarget();
pointToTarget(); pointToTarget();
if(!m_target) break; if(!m_target || !m_closest_kart) break;
// Is the target too near? // Get the node corresponding to the joint at the center of the
float dist_to_target2 = // swatter (by swatter, I mean the thing hold in the hand, not
(m_target->getXYZ()- Vec3(m_scene_node->getAbsolutePosition())) // the whole thing)
.length2(); scene::ISceneNode* swatter_node =
m_scene_node->getJointNode("Swatter");
assert(swatter_node);
Vec3 swatter_pos = swatter_node->getAbsolutePosition();
float dist2 = (m_closest_kart->getXYZ()-swatter_pos).length2();
float min_dist2 float min_dist2
= m_kart->getKartProperties()->getSwatterDistance(); = m_kart->getKartProperties()->getSwatterDistance();
if(dist_to_target2 < min_dist2)
if(dist2 < min_dist2)
{ {
// Start squashing // Start squashing
m_animation_phase = SWATTER_TO_TARGET; m_animation_phase = SWATTER_TO_TARGET;
@ -167,13 +176,16 @@ bool Swatter::updateAndTestFinished(float dt)
m_scene_node->setCurrentFrame(0.0f); m_scene_node->setCurrentFrame(0.0f);
m_scene_node->setLoopMode(false); m_scene_node->setLoopMode(false);
m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED); m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED);
// Play swat sound
m_swat_sound->setPosition(swatter_pos);
m_swat_sound->play();
} }
} }
break; break;
case SWATTER_TO_TARGET: case SWATTER_TO_TARGET:
{ {
pointToTarget(); pointToTarget();
const float middle_frame = m_scene_node->getEndFrame()/2.0f; const float middle_frame = m_scene_node->getEndFrame()/2.0f;
float current_frame = m_scene_node->getFrameNr(); float current_frame = m_scene_node->getFrameNr();
@ -182,13 +194,15 @@ bool Swatter::updateAndTestFinished(float dt)
{ {
// Squash the karts and items around and // Squash the karts and items around and
// change the current phase // change the current phase
if (squashThingsAround() && squashThingsAround();
race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES)
{
//Remove swatter from kart in 3 strikes battle after one successful hit
discard_now = true;
}
m_animation_phase = SWATTER_FROM_TARGET; m_animation_phase = SWATTER_FROM_TARGET;
if (race_manager->getMinorMode()==
RaceManager::MINOR_MODE_3_STRIKES)
{
// Remove swatter from kart in 3 strikes battle
// after one successful hit
m_discard_now = true;
}
} }
} }
break; break;
@ -196,11 +210,11 @@ bool Swatter::updateAndTestFinished(float dt)
case SWATTER_FROM_TARGET: case SWATTER_FROM_TARGET:
break; break;
} }
}
else
m_discard_timeout += dt;
// If the swatter is used up, trigger cleaning up return (m_discard_now && m_discard_timeout > 0.5f ? true : false);
// TODO: use a timeout
// TODO: how does it work currently...?
return (discard_now ? true : false);
} // updateAndTestFinished } // updateAndTestFinished
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -240,6 +254,7 @@ void Swatter::chooseTarget()
} }
} }
m_target = closest_kart; // may be NULL m_target = closest_kart; // may be NULL
m_closest_kart = closest_kart;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -267,42 +282,13 @@ void Swatter::pointToTarget()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Squash karts or items that are around the end position (determined using /** Squash karts or items that are around the end position (determined using
* a joint) of the swatter. * a joint) of the swatter.
* \return True if target kart is hit.
*/ */
bool Swatter::squashThingsAround() void Swatter::squashThingsAround()
{ {
const KartProperties *kp = m_kart->getKartProperties(); const KartProperties *kp = m_kart->getKartProperties();
// Square of the minimum distance
float min_dist2 = kp->getSwatterDistance();
const World* world = World::getWorld();
// Get the node corresponding to the joint at the center of the swatter m_closest_kart->setSquash(kp->getSwatterSquashDuration(),
// (by swatter, I mean the thing hold in the hand, not the whole thing) kp->getSwatterSquashSlowdown());
scene::ISceneNode* swatter_node = m_scene_node->getJointNode("Swatter");
assert(swatter_node);
Vec3 swatter_pos = swatter_node->getAbsolutePosition();
m_swat_sound->setPosition(swatter_pos);
m_swat_sound->play();
bool target_is_hit = false;
// Squash karts around
for(unsigned int i = 0; i < world->getNumKarts(); i++)
{
AbstractKart *kart = world->getKart(i);
// TODO: isSwatterReady()
if(kart->isEliminated() || kart==m_kart)
continue;
// don't swat an already hurt kart
if (kart->isInvulnerable() || kart->isSquashed())
continue;
float dist2 = (kart->getXYZ()-swatter_pos).length2();
if(dist2 >= min_dist2) continue; // too far away, ignore this kart
kart->setSquash(kp->getSwatterSquashDuration(), kp->getSwatterSquashSlowdown());
target_is_hit = true;
//Handle achievement if the swatter is used by the current player //Handle achievement if the swatter is used by the current player
const StateManager::ActivePlayer *const ap = m_kart->getController() const StateManager::ActivePlayer *const ap = m_kart->getController()
@ -313,18 +299,16 @@ bool Swatter::squashThingsAround()
"swatter", 1); "swatter", 1);
} }
if (kart->getAttachment()->getType()==Attachment::ATTACH_BOMB) if (m_closest_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB)
{ // make bomb explode { // make bomb explode
kart->getAttachment()->update(10000); m_closest_kart->getAttachment()->update(10000);
HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion.xml"); HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion.xml");
if(m_kart->getController()->isPlayerController()) if(m_kart->getController()->isPlayerController())
he->setPlayerKartHit(); he->setPlayerKartHit();
projectile_manager->addHitEffect(he); projectile_manager->addHitEffect(he);
ExplosionAnimation::create(kart); ExplosionAnimation::create(m_closest_kart);
} // if kart has bomb attached } // if kart has bomb attached
World::getWorld()->kartHit(kart->getWorldKartId()); World::getWorld()->kartHit(m_closest_kart->getWorldKartId());
} // for i < num_kartrs
return target_is_hit;
// TODO: squash items // TODO: squash items
} // squashThingsAround } // squashThingsAround

View File

@ -49,9 +49,17 @@ private:
enum {SWATTER_AIMING, SWATTER_TO_TARGET, SWATTER_FROM_TARGET} enum {SWATTER_AIMING, SWATTER_TO_TARGET, SWATTER_FROM_TARGET}
m_animation_phase; m_animation_phase;
/** True if the swatter will be discarded now. */
bool m_discard_now;
/** Require for the sfx to complete. */
float m_discard_timeout;
/** The kart the swatter is aiming at. */ /** The kart the swatter is aiming at. */
Moveable *m_target; Moveable *m_target;
AbstractKart *m_closest_kart;
SFXBase *m_swat_sound; SFXBase *m_swat_sound;
/** True if the swatter is removing an attached bomb. */ /** True if the swatter is removing an attached bomb. */
@ -91,7 +99,7 @@ private:
void pointToTarget(); void pointToTarget();
/** Squash karts or items that are around the end position (determined using a joint) of the swatter */ /** Squash karts or items that are around the end position (determined using a joint) of the swatter */
bool squashThingsAround(); void squashThingsAround();
}; // Swatter }; // Swatter
#endif #endif

View File

@ -98,18 +98,17 @@ void BattleAI::reset()
{ {
m_current_node = BattleGraph::UNKNOWN_POLY; m_current_node = BattleGraph::UNKNOWN_POLY;
m_target_node = BattleGraph::UNKNOWN_POLY; m_target_node = BattleGraph::UNKNOWN_POLY;
m_closest_kart = NULL;
m_closest_kart_node = BattleGraph::UNKNOWN_POLY; m_closest_kart_node = BattleGraph::UNKNOWN_POLY;
m_closest_kart_point = Vec3(0, 0, 0); m_closest_kart_point = Vec3(0, 0, 0);
m_closest_kart_pos_data = {0}; m_closest_kart_pos_data = {0};
m_cur_kart_pos_data = {0}; m_cur_kart_pos_data = {0};
m_is_stuck = false; m_is_stuck = false;
m_is_uturn = false; m_is_uturn = false;
m_is_steering_overridden = false;
m_target_point = Vec3(0, 0, 0); m_target_point = Vec3(0, 0, 0);
m_time_since_last_shot = 0.0f; m_time_since_last_shot = 0.0f;
m_time_since_driving = 0.0f; m_time_since_driving = 0.0f;
m_time_since_reversing = 0.0f; m_time_since_reversing = 0.0f;
m_time_since_steering_overridden = 0.0f;
m_time_since_uturn = 0.0f; m_time_since_uturn = 0.0f;
m_on_node.clear(); m_on_node.clear();
m_path_corners.clear(); m_path_corners.clear();
@ -166,7 +165,6 @@ void BattleAI::update(float dt)
findClosestKart(true); findClosestKart(true);
findTarget(); findTarget();
handleItems(dt); handleItems(dt);
handleSwatter();
if (m_kart->getSpeed() > 15.0f && m_cur_kart_pos_data.angle < 0.2f) if (m_kart->getSpeed() > 15.0f && m_cur_kart_pos_data.angle < 0.2f)
{ {
@ -308,22 +306,17 @@ void BattleAI::findClosestKart(bool difficulty)
} }
if (!difficulty) if (!difficulty)
{
m_closest_kart = m_world->getKart(closest_kart_num);
checkPosition(m_closest_kart_point, &m_closest_kart_pos_data); checkPosition(m_closest_kart_point, &m_closest_kart_pos_data);
}
} // findClosestKart } // findClosestKart
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void BattleAI::findTarget() void BattleAI::findTarget()
{ {
// Don't try to hit a player continuously with swatter for easy and medium
// mode, which make it too aggressive
const bool continuous_swatter =
m_kart->getAttachment()->getType() == Attachment::ATTACH_SWATTER &&
(m_cur_difficulty == RaceManager::DIFFICULTY_HARD ||
m_cur_difficulty == RaceManager::DIFFICULTY_BEST);
// Find a suitable target to drive to, either powerup or kart // Find a suitable target to drive to, either powerup or kart
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING && if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING)
!continuous_swatter)
handleItemCollection(&m_target_point , &m_target_node); handleItemCollection(&m_target_point , &m_target_node);
else else
{ {
@ -389,19 +382,6 @@ void BattleAI::handleSteering(const float dt)
if (m_current_node == BattleGraph::UNKNOWN_POLY || if (m_current_node == BattleGraph::UNKNOWN_POLY ||
m_target_node == BattleGraph::UNKNOWN_POLY) return; m_target_node == BattleGraph::UNKNOWN_POLY) return;
if (m_is_steering_overridden)
{
// Steering is overridden to avoid collision with the target kart
m_time_since_steering_overridden += dt;
setSteering(-1.0f, dt);
if (m_time_since_steering_overridden > 0.5f)
{
m_is_steering_overridden = false;
m_time_since_steering_overridden = 0.0f;
}
return;
}
if (m_target_node == m_current_node) if (m_target_node == m_current_node)
{ {
// Very close to the item, steer directly // Very close to the item, steer directly
@ -452,27 +432,6 @@ void BattleAI::handleSteering(const float dt)
} }
} // handleSteering } // handleSteering
//-----------------------------------------------------------------------------
/** Make AI avoid collison with target as much as possible when attacking with
* swatter.
*/
void BattleAI::handleSwatter()
{
if (m_is_steering_overridden) return;
if (m_kart->getAttachment()->getType() == Attachment::ATTACH_SWATTER)
{
findClosestKart(false);
if (m_closest_kart_pos_data.angle < 0.25f &&
m_closest_kart_pos_data.distance < 5.0f)
{
// Check whether it's straight ahead towards target
m_is_steering_overridden = true;
}
}
} // handleSwatter
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** This function finds the polyon edges(portals) that the AI will cross before /** This function finds the polyon edges(portals) that the AI will cross before
* reaching its destination. We start from the current polygon and call * reaching its destination. We start from the current polygon and call
@ -632,18 +591,6 @@ void BattleAI::handleBraking()
{ {
m_controls->m_brake = false; m_controls->m_brake = false;
if (m_is_steering_overridden && m_kart->getSpeed() > 10.0f)
{
// Hard-brake for too fast
if (m_kart->getSpeed() > 15.0f)
{
m_controls->m_accel = -12.5f;
return;
}
m_controls->m_brake = true;
return;
}
// A kart will not brake when the speed is already slower than this // A kart will not brake when the speed is already slower than this
// value. This prevents a kart from going too slow (or even backwards) // value. This prevents a kart from going too slow (or even backwards)
// in tight curves. // in tight curves.
@ -741,6 +688,9 @@ void BattleAI::handleItems(const float dt)
// Find a closest kart again, this time we ignore difficulty // Find a closest kart again, this time we ignore difficulty
findClosestKart(false); findClosestKart(false);
if (!m_closest_kart) return;
m_time_since_last_shot += dt; m_time_since_last_shot += dt;
float min_bubble_time = 2.0f; float min_bubble_time = 2.0f;
@ -797,7 +747,8 @@ void BattleAI::handleItems(const float dt)
// Leave some time between shots // Leave some time between shots
if (m_time_since_last_shot < 1.0f) break; if (m_time_since_last_shot < 1.0f) break;
if (m_closest_kart_pos_data.distance < 25.0f) if (m_closest_kart_pos_data.distance < 25.0f &&
!m_closest_kart->isInvulnerable())
{ {
m_controls->m_fire = true; m_controls->m_fire = true;
m_controls->m_look_back = fire_behind; m_controls->m_look_back = fire_behind;
@ -829,11 +780,15 @@ void BattleAI::handleItems(const float dt)
case PowerupManager::POWERUP_SWATTER: case PowerupManager::POWERUP_SWATTER:
{ {
// Squared distance for which the swatter works
float d2 = m_kart->getKartProperties()->getSwatterDistance();
// if the kart has a shield, do not break it by using a swatter. // if the kart has a shield, do not break it by using a swatter.
if (m_kart->getShieldTime() > min_bubble_time) if (m_kart->getShieldTime() > min_bubble_time)
break; break;
if (m_closest_kart_pos_data.distance < 7.0f) if (!m_closest_kart->isSquashed() &&
m_closest_kart_pos_data.distance < d2 &&
m_closest_kart->getSpeed() < m_kart->getSpeed())
{ {
m_controls->m_fire = true; m_controls->m_fire = true;
m_controls->m_look_back = false; m_controls->m_look_back = false;

View File

@ -61,6 +61,9 @@ private:
int m_closest_kart_node; int m_closest_kart_node;
Vec3 m_closest_kart_point; Vec3 m_closest_kart_point;
/** Pointer to the closest kart around this kart. */
AbstractKart *m_closest_kart;
posData m_closest_kart_pos_data; posData m_closest_kart_pos_data;
posData m_cur_kart_pos_data; posData m_cur_kart_pos_data;
@ -71,10 +74,6 @@ private:
* counting down. */ * counting down. */
bool m_is_stuck; bool m_is_stuck;
/** Indicates that the steering of kart is overridden, and
* m_time_since_steering_overridden is counting down. */
bool m_is_steering_overridden;
/** Indicates that the kart need a uturn to reach a node behind, and /** Indicates that the kart need a uturn to reach a node behind, and
* m_time_since_uturn is counting down. */ * m_time_since_uturn is counting down. */
bool m_is_uturn; bool m_is_uturn;
@ -108,9 +107,6 @@ private:
/** This is a timer that counts down when the kart is starting to drive. */ /** This is a timer that counts down when the kart is starting to drive. */
float m_time_since_driving; float m_time_since_driving;
/** This is a timer that counts down when the steering of kart is overridden. */
float m_time_since_steering_overridden;
/** This is a timer that counts down when the kart is doing u-turn. */ /** This is a timer that counts down when the kart is doing u-turn. */
float m_time_since_uturn; float m_time_since_uturn;