diff options
| -rw-r--r-- | src/game/base/platform.cc | 66 | ||||
| -rw-r--r-- | src/game/base/weapon.cc | 3 | 
2 files changed, 46 insertions, 23 deletions
| 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<Ship *>::const_iterator enemy_it = enemylist.begin(); enemy_it != enemylist.end(); enemy_it++) { +				for (std::list<Ship *>::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 { | 
