From aabb379d84afab3679acc6dc4472d886dae88f39 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Mon, 14 Oct 2013 20:33:50 +0000 Subject: Separated autopilot from AI code, added basic formation flying. --- src/game/base/npc.cc | 75 +++++--------------------- src/game/base/ship.cc | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/game/base/ship.h | 12 +++++ 3 files changed, 168 insertions(+), 61 deletions(-) diff --git a/src/game/base/npc.cc b/src/game/base/npc.cc index bb4c180..dba7929 100644 --- a/src/game/base/npc.cc +++ b/src/game/base/npc.cc @@ -71,11 +71,8 @@ void NPC::frame(const unsigned long elapsed) } } else { - - // FIXME verify the leader is still alive - - // TODO pilot magic and mood witchcraft + // TODO pilot magic and mood witchcraft if (leader()) { // verify leader still exists @@ -87,66 +84,22 @@ void NPC::frame(const unsigned long elapsed) } else if (leader()->zone() == zone()) { - // rotate towards leader: direction - math::Vector3f d(leader()->location() - location()); - float distance = d.length(); - - d.normalize(); - - float direction_angle = math::dotproduct(axis().forward(), d); - float direction_sign = math::sgnf(math::dotproduct(axis().left(), d)); - - if (direction_sign < 0 ) { - target_direction = direction_sign; - } else if (direction_angle + MIN_DELTA < 1.0f ) { - target_direction = direction_sign * direction_angle; - } else { - target_direction = 0.0f; - } - - // rotate towards leader: pitch - direction_angle = math::dotproduct(axis().forward(), d); - direction_sign = math::sgnf(math::dotproduct(axis().up(), d)); - - if (direction_sign < 0 ) { - target_pitch = direction_sign; - } else if (direction_angle + MIN_DELTA < 1.0f ) { - target_pitch = direction_sign * direction_angle; - } else { - target_pitch = 0.0f; - } - - const float r = 2.0f * (radius() + leader()->radius()); - - if (distance > 2.0f * r + 50.0f) { - if (state() == core::Entity::Normal) { - // enable impulse drive - func_impulse(); - } - } else { - if (state() == core::Entity::Impulse) { - - if (leader()->state() != core::Entity::Impulse) { - // disbable impulse drive - func_impulse(); - } - - } else if (state() == core::Entity::Normal) { - - if ((leader()->state() == core::Entity::Impulse) || (leader()->state() == core::Entity::ImpulseInitiate)) { - // enable impulse drive - func_impulse(); - } + if (leader()->state() == Docked) { + + // TODO dock where the leader is docked + if (leader()->dock()) { + frame_autopilot_goto(elapsed, leader()->dock()); } - } - - if (distance > 2.0f * r) { - target_thrust = 1.0f; - } else if (distance > r) { - target_thrust = (distance - r ) / r; } else { - target_thrust = 0.0f; + + if (math::distance(location(), leader()->location()) > 4.0f * ( radius() + leader()->radius())) { + // goto the leader + frame_autopilot_goto(elapsed, leader()); + } else { + // formatian flying + frame_autopilot_formation(elapsed, leader()); + } } } else { diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc index 6c5598e..23baa5d 100644 --- a/src/game/base/ship.cc +++ b/src/game/base/ship.cc @@ -990,4 +990,146 @@ void Ship::frame(const unsigned long elapsed) } +void Ship::frame_autopilot_goto(const unsigned long elapsed, const core::Entity *target) +{ + // reference radius used in calculations + const float r = radius() + target->radius(); + + // desired direction + math::Vector3f direction(target->location() - location()); + const float distance = direction.length(); + direction.normalize(); + + // transform direction from world coordinates to local entity coordinates + direction = axis().transpose() * direction; + + if (direction.x() < 0) { + // target is behind the ship + target_direction = math::sgnf(direction.y()); + target_pitch = 0.0f; + + } else if (direction.x() + MIN_DELTA < 1.0f) { + // target is in front of the ship + target_direction = direction.y(); + target_pitch = direction.z(); + } else { + target_direction = 0.0f; + target_pitch = 0.0f; + } + + target_roll = 0.0f; + + // impulse or thruster + if (distance > r + 50.0f) { + + if (state() == core::Entity::Normal) { + // enable impulse drive + func_impulse(); + } + + } else { + + if (target->type() == core::Entity::Controlable) { + + const core::EntityControlable *controlable = static_cast(target); + + if (state() == core::Entity::Impulse) { + + if (controlable->state() != core::Entity::Impulse) { + // disbable impulse drive + func_impulse(); + } + + } else if (state() == core::Entity::Normal) { + + if ((controlable->state() == core::Entity::Impulse) || (controlable->state() == core::Entity::ImpulseInitiate)) { + // enable impulse drive + func_impulse(); + } + } + + } else { + + if (state() == core::Entity::Impulse) { + func_impulse(); + } + } + } + + // thruster + if (distance > 4.0f * r) { + target_thrust = 1.0f; + + } else if (distance > 2.0f * r ) { + target_thrust = (distance - 2.0f * r ) / 2.0f * r; + + } else { + target_thrust = 0.0f; + + // TODO autolevel + } +} + +void Ship::frame_autopilot_formation(const unsigned long elapsed, const core::Entity *target) +{ + // transform the target's axis into local coordinates + const math::Axis reference(axis().transpose() * target->axis()); + + //const float distance = math::distance(location(), target->location()); + //const float r = radius() + target->radius(); + + if (reference.forward().x() < 0) { + // target is behind the ship + target_direction = math::sgnf(reference.forward().y()); + target_pitch = 0.0f; + target_roll = 0.0f; + + } else if (reference.forward().x() + MIN_DELTA < 1.0f) { + // target is in front of the ship + target_direction = reference.forward().y(); + target_pitch = reference.forward().z(); + target_roll = 0.0f; + + } else { + target_direction = 0.0f; + target_pitch = 0.0f; + + if (reference.up().z() < 0) { + // upward-down + target_roll = math::sgnf(reference.up().y()); + } else { + target_roll = reference.up().y(); + } + } + + if (target->type() == core::Entity::Controlable) { + + const core::EntityControlable *controlable = static_cast(target); + + target_thrust = controlable->thrust(); + + if (state() == core::Entity::Impulse) { + + if (controlable->state() != core::Entity::Impulse) { + // disbable impulse drive + func_impulse(); + } + + } else if (state() == core::Entity::Normal) { + + if ((controlable->state() == core::Entity::Impulse) || (controlable->state() == core::Entity::ImpulseInitiate)) { + // enable impulse drive + func_impulse(); + } + } + + } else { + if (state() == core::Entity::Impulse) { + // disable impulse drive + func_impulse(); + } + } + +} + } // namespace game diff --git a/src/game/base/ship.h b/src/game/base/ship.h index 1de208d..ad2c71b 100644 --- a/src/game/base/ship.h +++ b/src/game/base/ship.h @@ -181,6 +181,18 @@ public: void set_spawn(core::Entity *spawn); +protected: + + /** + * @brief autopilot goto target + * */ + void frame_autopilot_goto(const unsigned long elapsed, const core::Entity *target); + + /** + * @brief autopilot formation flying + * */ + void frame_autopilot_formation(const unsigned long elapsed, const core::Entity *target); + private: JumpPoint *find_closest_jumppoint(); -- cgit v1.2.3