From 12119ea685cf36188da9fd84080d7bb92a839ba7 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sun, 21 Aug 2016 15:59:17 +0200 Subject: Added aim lead to platform and station weapons. --- src/game/base/platform.cc | 66 +++++++++++++++++++++++++++++++---------------- src/game/base/weapon.cc | 3 ++- 2 files changed, 46 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/game/base/platform.cc b/src/game/base/platform.cc index b5e92dc..4f18330 100644 --- a/src/game/base/platform.cc +++ b/src/game/base/platform.cc @@ -110,53 +110,74 @@ void Platform::frame(const unsigned long elapsed) continue; } - // find a target for this slot - Ship *current_enemy = 0; - float current_distance = 0.0f; - - math::Vector3f projectile_location(location() + (axis() * slot->location())); + // target location in world coordinates + Ship *current_enemy = 0; // The enemy ship the slot will be targetting + float current_distance = 0.0f; // Distance to the target location + math::Vector3f current_aim; // Location to aim at + + // slot and projectile location in world coordinates + const math::Vector3f projectile_location(location() + (axis() * slot->location())); math::Vector3f projectile_direction; math::Axis projectile_axis(axis() * slot->axis()); - - math::Vector3f aim_location; // we only need half the cone angle for the cosine calculation const float conecos = cosf(slot->cone() * 0.5f); - for (std::list::const_iterator enemy_it = enemylist.begin(); enemy_it != enemylist.end(); enemy_it++) { + for (std::list::const_iterator enemy_it = enemylist.begin(); enemy_it != enemylist.end(); enemy_it++) + { + // apply aim correction + // see https://www.reddit.com/r/gamedev/comments/16ceki/turret_aiming_formula/c7vbu2j + + const math::Vector3f v((*enemy_it)->axis().forward() * (*enemy_it)->speed()); + const math::Vector3f w((*enemy_it)->location() - projectile_location); + + const float a = v.lengthsquared() - weapon->projectile_speed() * weapon->projectile_speed(); + const float b = 2.0f * math::dotproduct(v, w); + const float c = w.lengthsquared(); - const float d = math::distance((*enemy_it)->location(), projectile_location); + const float D = b * b - 4.0f * a * c; + if (D < 0.0f) + { + continue; + } + const float t = math::min(sqrtf(D) - b , -sqrtf(D) - b) / (2.0f * a); + const math::Vector3f hitpoint((*enemy_it)->location() + v * t); - if (d > weapon->projectile_range() + (*enemy_it)->radius()) { + // verify the hitpoint is within weapon's range + const float d = math::distance(hitpoint, projectile_location); + if (d > weapon->projectile_range() + (*enemy_it)->radius()) + { continue; } - if ((current_distance > 0) && (d > current_distance)) { + if ((current_distance > 0.0f) && (d > current_distance)) + { continue; } - - aim_location.assign((*enemy_it)->location() + (*enemy_it)->axis().forward() * ( (*enemy_it)->radius() * 0.25f)); - projectile_direction.assign(aim_location - projectile_location); + + projectile_direction.assign(hitpoint - projectile_location); projectile_direction.normalize(); + // verify the hitpoint is in the slot's cone-of-fire const float cosa = math::dotproduct(projectile_direction, projectile_axis.forward()); - - // check if the ship is in the slot's cone if fire - if (cosa >= conecos) { + if (cosa >= conecos) + { current_distance = d; current_enemy = (*enemy_it); + current_aim.assign(hitpoint); } } - if (current_enemy) { - aim_location.assign(current_enemy->location() + current_enemy->axis().forward() * (current_enemy->radius() * 0.25f)); - projectile_direction.assign(aim_location - projectile_location); + if (current_enemy) + { + projectile_direction.assign(current_aim - projectile_location); projectile_direction.normalize(); const float cosa = math::dotproduct(projectile_direction, projectile_axis.forward()); // point the projectile into the fire direction math::Vector3f normal(math::crossproduct(projectile_direction, projectile_axis.forward())); - if (normal.length() > MIN_DELTA) { + if (normal.length() > MIN_DELTA) + { float sina = sqrt(1.0f - cosa * cosa); normal.normalize(); @@ -184,4 +205,5 @@ void Platform::frame(const unsigned long elapsed) } } -} +} // namespace game + diff --git a/src/game/base/weapon.cc b/src/game/base/weapon.cc index 28a7ae3..c4c8ef2 100644 --- a/src/game/base/weapon.cc +++ b/src/game/base/weapon.cc @@ -169,7 +169,7 @@ bool Weapon::init() if (weapon) { if (inifile.got_key_float("speed", f)) { - // convert speed from meters/second to game units/second + // convert speed from meters/second to game units/second weapon->set_projectile_speed(f * 0.01f); continue; @@ -184,6 +184,7 @@ bool Weapon::init() } else if (inifile.got_key_float("range", f)) { // range in meters, one game unit is 100 meters + // lifespan is in milliseconds, projectile speed in game units/second if (weapon->projectile_speed() == 0) { inifile.unknown_error("cannot set range if projectile speed is 0!"); } else { -- cgit v1.2.3