/** Returns information on the parameters needed to hit a target kart moving * at constant velocity and direction for a given speed in the XZ-plane. * \param origin Location of the kart shooting the item. * \param target_kart Which kart to target. * \param item_xz_speed Speed of the item projected in XZ plane. * \param gravity The gravity used for this item. * \param forw_offset How far ahead of the kart the item is shot (so that * the item does not originate inside of the shooting kart. * \param fire_angle Returns the angle to fire the item at. * \param up_velocity Returns the upwards velocity to use for the item. */ void Flyable::getLinearKartItemIntersection (const Vec3 &origin, const AbstractKart *target_kart, float item_XZ_speed, float gravity, float forw_offset, float *fire_angle, float *up_velocity) { Vec3 relative_target_kart_loc = target_kart->getXYZ() - origin; btTransform trans = target_kart->getTrans(); Vec3 target_direction(trans.getBasis().getColumn(2)); float dx = relative_target_kart_loc.getX(); float dy = relative_target_kart_loc.getY(); float dz = relative_target_kart_loc.getZ(); float gy = target_direction.getY(); //Projected onto X-Z plane float target_kart_speed = target_direction.length_2d() * target_kart->getSpeed(); float target_kart_heading = target_kart->getHeading(); float dist = -(target_kart_speed / item_XZ_speed) * (dx * cosf(target_kart_heading) - dz * sinf(target_kart_heading) ); float fire_th = (dx*dist - dz * sqrtf(dx*dx + dz*dz - dist*dist)) / (dx*dx + dz*dz); if(fire_th>1) fire_th = 1.0f; else if (fire_th<-1.0f) fire_th = -1.0f; fire_th = (((dist - dx*fire_th) / dz > 0) ? -acosf(fire_th) : acosf(fire_th)); float time = 0.0f; float a = item_XZ_speed * sinf (fire_th) + target_kart_speed * sinf (target_kart_heading); float b = item_XZ_speed * cosf (fire_th) + target_kart_speed * cosf (target_kart_heading); if (fabsf(a) > fabsf(b)) time = fabsf (dx / a); else if (b != 0.0f) time = fabsf(dz / b); if (fire_th > M_PI) fire_th -= M_PI; else fire_th += M_PI; //createPhysics offset assert(sqrt(a*a+b*b)!=0); time -= forw_offset / sqrt(a*a+b*b); assert(time!=0); *fire_angle = fire_th; *up_velocity = (0.5f * time * gravity) + (dy / time) + (gy * target_kart->getSpeed()); } // getLinearKartItemIntersection
/** Returns information on the parameters needed to hit a target kart moving * at constant velocity and direction for a given speed in the XZ-plane. * \param origin Location of the kart shooting the item. * \param target_kart Which kart to target. * \param item_xz_speed Speed of the item projected in XZ plane. * \param gravity The gravity used for this item. * \param forw_offset How far ahead of the kart the item is shot (so that * the item does not originate inside of the shooting kart. * \param fire_angle Returns the angle to fire the item at. * \param up_velocity Returns the upwards velocity to use for the item. */ void Flyable::getLinearKartItemIntersection (const Vec3 &origin, const AbstractKart *target_kart, float item_XZ_speed, float gravity, float forw_offset, float *fire_angle, float *up_velocity) { // Transform the target into the firing kart's frame of reference btTransform inv_trans = m_owner->getTrans().inverse(); Vec3 relative_target_kart_loc = inv_trans(target_kart->getXYZ()); // Find the direction target is moving in btTransform trans = target_kart->getTrans(); Vec3 target_direction(trans.getBasis().getColumn(2)); // Now rotate it to the firing kart's frame of reference btQuaternion inv_rotate = inv_trans.getRotation(); target_direction = target_direction.rotate(inv_rotate.getAxis(), inv_rotate.getAngle()); // Now we try to find the angle to aim at to hit the target. // Warning : Funky math stuff going on below. To understand, see answer by // Jeffrey Hantin here : // http://stackoverflow.com/questions/2248876/2d-game-fire-at-a-moving-target-by-predicting-intersection-of-projectile-and-u float target_x_speed = target_direction.getX()*target_kart->getSpeed(); float target_z_speed = target_direction.getZ()*target_kart->getSpeed(); float target_y_speed = target_direction.getY()*target_kart->getSpeed(); float a = (target_x_speed*target_x_speed) + (target_z_speed*target_z_speed) - (item_XZ_speed*item_XZ_speed); float b = 2 * (target_x_speed * (relative_target_kart_loc.getX()) + target_z_speed * (relative_target_kart_loc.getZ())); float c = relative_target_kart_loc.getX()*relative_target_kart_loc.getX() + relative_target_kart_loc.getZ()*relative_target_kart_loc.getZ(); float discriminant = b*b - 4 * a*c; if (discriminant < 0) discriminant = 0; float t1 = (-b + sqrt(discriminant)) / (2 * a); float t2 = (-b - sqrt(discriminant)) / (2 * a); float time; if (t1 >= 0 && t1<t2) time = t1; else time = t2; //createPhysics offset time -= forw_offset / item_XZ_speed; float aimX = time*target_x_speed + relative_target_kart_loc.getX(); float aimZ = time*target_z_speed + relative_target_kart_loc.getZ(); assert(time!=0); float angle = atan2f(aimX, aimZ); *fire_angle = angle; // Now find the up_velocity. This is an application of newton's equation. *up_velocity = (0.5f * time * gravity) + (relative_target_kart_loc.getY() / time) + ( target_y_speed); } // getLinearKartItemIntersection