   Rotating a turret to shoot a target
  Edit: Poo, this was meant to go in Game Programming.Carrying on from this thread which GD won't let me post in, I still haven't figured out how to get this working.This is my code:void Human_Controller::Update_Structure_Turrets(structure_map::value_type& structure_pair, float delta){    structure_ptr structure(structure_pair.second);    turret_vec& turrets(structure->Get_Turrets());    for(size_t turret_index = 0; turret_index < turrets.size(); ++turret_index)    {   Turret& turret(turrets[turret_index]);   turret.Get_Fire_Delay_Timer().Update(delta);   if(turret.Get_Attack_Position() != PointI(-1, -1))   {  float rotate_speed = GET_TURRET_DATA(turret.Get_Type_ID()).Get_Rotate_Speed();  float angle = Maths::rotate_towards_target(turret.Get_Y_Angle(), rotate_speed, turret.Get_Absolute_Position(*structure), to_point_type<int, float>(turret.Get_Attack_Position()));  if(turret.Get_Y_Angle() >= angle - 1 && turret.Get_Y_Angle() <= angle + 1)  { // Within range of target. if(turret.Get_Fire_Delay_Timer().Finished()) {Fire_Projectile(*structure, turret_index);turret.Get_Fire_Delay_Timer().Start(); }  }  else  { //float move_by = turret.Get_Y_Angle() > angle ? -delta : delta; turret.Set_Y_Angle(turret.Get_Y_Angle() + /*move_by*/ delta * rotate_speed * angle);  }  std::cout << "turret angle: " << turret.Get_Y_Angle() << " movement angle: " << angle << std::endl;   }    }}This is basically Sirisian's code that he linked to, I've just changed a few names around:float Maths::rotate_towards_target(float object_angle, float rotate_speed, PointF object_pos, PointF target_pos){    // Making an object rotate to face a target    // Vector is a mathematical vector representing two components like: (x, y)    // This is pseudo-code and the coordinate system is such that x is going positive to the right and y is going positive down    // The current direction of the object    PointF object_dir(cos(object_angle), -sin(object_angle));    // or just use a vector if you have one already. It doesn't have to be a unit vector.    // This represents a vector going from the object to the target. Basically we're creating a local position for the target    // relative to the object. (This means that the object is essentially the origin point (0, 0) which is useful later).    PointF object_to_target(target_pos.x - object_pos.x, target_pos.y - object_pos.y);    // How much the object should rotate.    float adj_rotate_speed = Maths::deg_to_rad(rotate_speed);    PointF temp; // temporary vector    // This next step uses the dot product. One of its properties is that it can tell you if two vectors face the same general direction// even using vectors that aren't unit vectors.    // The dot product can be stated here as A.x * B.x + A.y * B.y, where A and B are any vectors    // Test this out on paper by creating two vectors and notice that when the vectors are facing the same basic direction    // meaning plus or minus 90 degrees that the value is positive. (1, 1) and (2, 1) for instance give 1 * 2 + 1 * 1 = 3.    // For any vectors that face away from one another you'll get a negative value.    // Use the perpendicular of the object_dir vector. (y, -x). This is also known as the left hand normal in this coordinate system.// (The right would be (-y, x))    // To see why we use the perpendicular vector of the direction draw out a scenario.    // We are deciding which side of the object direction vector the target lies on. If it's on the left side we rotate left and vice versa    // for the right side. If the dot product result is zero then the two vectors are perpendicular and the direction is pointing at the target.// Dot(LeftHandNormal(object_dir), object_to_target)    float perpObjectDirectionDotObjectToTarget = object_dir.y * object_to_target.x - object_dir.x * object_to_target.y;    if (perpObjectDirectionDotObjectToTarget > 0) // target is on our left side    {    // Turn counter-clockwise aka left    // This is just a rotation matrix expanded. If you have matrices you can use those instead.    // object_dir = Matrix.Rotate(turningRate) * object_dir;    temp.x = cos(adj_rotate_speed) * object_dir.x - sin(adj_rotate_speed) * object_dir.y;    temp.y = cos(adj_rotate_speed) * object_dir.y + sin(adj_rotate_speed) * object_dir.x;    object_dir.x = temp.x;    object_dir.y = temp.y;    // Did we rotate past the target so that it's on our right side? If so just snap so that we're facing the target.    if (object_dir.y * object_to_target.x - object_dir.x * object_to_target.y < 0)    {  object_to_target.Normalise(); // Make the object_to_target vector a unit-vector. Not necessary, but keeps things clean    object_dir.x = object_to_target.x;    object_dir.y = object_to_target.y;    }    }    else if (perpObjectDirectionDotObjectToTarget < 0) // target is on our right side    {    // Turn clockwise aka right    temp.x = cos(-adj_rotate_speed) * object_dir.x - sin(-adj_rotate_speed) * object_dir.y;    temp.y = cos(-adj_rotate_speed) * object_dir.y + sin(-adj_rotate_speed) * object_dir.x;    object_dir.x = temp.x;    object_dir.y = temp.y;    if (object_dir.y * object_to_target.x - object_dir.x * object_to_target.y > 0)    {    object_to_target.Normalise();    object_dir.x = object_to_target.x;    object_dir.y = object_to_target.y;    }    }    // If you need the angle back from the object_dir just use Atan2(object_dir.y, object_dir.x)    return atan2(object_dir.y, object_dir.x);}The console output shows that it's not exactly doing what I want it to:I had a search around again and found this thread, but it wasn't correct when I tried it. The angle was way off.Can anyone see what is wrong with this code?Cheers.   
  Bump. I've simplified it to the code below: What am I doing wrong there?PointF source(turret.Get_Absolute_Position(*structure));  PointF target(to_point_type<int, float>(turret.Get_Attack_Position()));   float x = target.x - source.x;   float y = target.y - source.y;  float angle = Maths::rad_to_deg(atan2(y, x));I know that I'm getting close to getting it working but it still fires all over the place. Cooincidentally, on certain angles, the turret will fire at an angle directly opposite to the target (mouse).I've looked at the Extreme Carnage game that is in Your Announcements and it uses this code to update the fire direction:void TowerManager::RefreshFireDir(TSPCell::TwIt& tower){Vector2i start = tower->rect.GetCenter();Vector2i dest= tower->currentTarget->rect.GetCenter();// si la tourelle envoie des projectiles a progression lente, ce n'est pas si simple// if faut utiliser un point de tir qui projettera la position de la cible// dans le futur quand le projectile interceptera sa course.int twwid = towerKinds[ tower->towerKind ].weaponId;float prspeed = ChiefManager::GetWeaponManager()->GetProjectileSpeed(twwid);if (prspeed > 0.f)  // si les projectiles sont lents{float targetSpeed = tower->currentTarget->speed;float trgtdist = sqrt((float)(dest - start).LenghtSq());float time2trgt = trgtdist / prspeed;// nouvelle destination de tir, devant l'ennemi ciblé :dest = dest + tower->currentTarget->direction * (SPEED_MULTIPLIER * targetSpeed * time2trgt);}tower->direction = Normalize(dest - start);float x = dest.x - start.x;float y = dest.y - start.y;tower->angle = -1.57f - atan2(y, x);}They've used a direction vector and an angle... so I figure that Sirisian's code that I posted in my first post must be right (since it converts the direction vector to an angle), but it just won't work.Cheers.   ;  How far off is it? just pointing the exact opposite way, or rotating the opposite way, or just randomly?Haven't really gone through your code, but try:atan2(y, x) * 180 / PI;Check to make sure you're in Degrees or Radians;   ;  At some points it's pointing the opposite way, then I'll swing the mouse around in a circle and it'll start going off again, then it will start pointing the opposite way again, etc.I convert the angle into degrees with this line:float angle = Maths::rad_to_deg(atan2(y, x));;  Here's a ">video of it in action.   ;  I'm doing a similar thing in my game.I didn't read your code. Here's what I do(and it works).First, you must understand the velocity of the bullet is a vector.The bullet has a constant velocity, let's name it BULLET_VELOCITY. Depending on your mouse position, Vx and Vy change so that sqrt(sqr(Vx)+sqr(Vy)) = BULLET_VELOCITY (V).It needs some math here.x1,y1 = Position of the turretx2,y2 = Mouse positionconst float cos_a = (y2-y1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float sin_a = (x2-x1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float vX = BULLET_VELOCITY * sin_a;const float vY = BULLET_VELOCITY * cos_a;// x = v * tbullet->x(Vx * dt);bullet->y(Vy * dt);If your bullet moves with Vx speed in X axis and Vy speed in Y axis it will go straight to the position of the mouse.[Edited by - sheep19 on April 3, 2010 11:01:09 AM];Quote:Original post by sheep19I'm doing a similar thing in my game.I didn't read your code. Here's what I do(and it works).First, you must understand the velocity of the bullet is a vector.The bullet has a constant velocity, let's name it BULLET_VELOCITY. Depending on your mouse position, Vx and Vy change so that sqrt(sqr(Vx)+sqr(Vy)) = BULLET_VELOCITY (V).It needs some math here.x1,y1 = Position of the turretx2,y2 = Mouse positionconst float cos_a = (y2-y1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float sin_a = (x2-x1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float vX = BULLET_VELOCITY * sin_a;const float vY = BULLET_VELOCITY * cos_a;// x = v * tbullet->x(Vx * dt);bullet->y(Vy * dt);If your bullet moves with Vx speed in X axis and Vy speed in Y axis it will go straight to the position of the mouse.Hey. Thanks for the reply.I have a few questions:Is sqr supposed to be sqrt here?const float cos_a = (y2-y1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float sin_a = (x2-x1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );You say that BULLET_VELOCITY is constant and that it is determined by V, right? I don't understand that part. I understand speed as how fast the object moves and velocity as the rate at which that object changes position, but here they seem to have reversed roles.Would your code sample be run every update loop for the projectile? If it's a bullet and not something like a homing missile, isn't there a way to leave out the position of the mouse and have the projectile move by a constant velocity vector?How would I rotate the actual turret using your code?Cheers.   ;  Ok, it's sort of working: the projectile lands right at the mouse which is great, but it only does it within a 90 degree range. I've uploaded another video to show you what I mean:">Video.My code:float proj_speed = GET_PROJECTILE_DATA(*projectile).Get_Speed();PointF target(projectile->Get_Target());PointF source(projectile->Get_Position());const float cos_a = (target.y-source.y) / sqrt( sqrt(target.x-source.x) + sqrt(target.y-source.y) );const float sin_a = (target.x-source.x) / sqrt( sqrt(target.x-source.x) + sqrt(target.y-source.y) );PointF movement(proj_speed * sin_a, proj_speed * cos_a);projectile->Set_Position(projectile->Get_Position() + movement * delta);projectile->Set_Dist_Travelled(projectile->Get_Dist_Travelled() + delta * proj_speed)I debugged the code and it seems that any angle outside that certain range will mean that cos_a and sin_a are equal to -1.#IND000. I'm not sure what this means.Also, the projectile slows down as it reaches the target - is there any way to stop it from slowing down?Cheers.   ;Quote:Original post by MybowlcutQuote:Original post by sheep19I'm doing a similar thing in my game.I didn't read your code. Here's what I do(and it works).First, you must understand the velocity of the bullet is a vector.The bullet has a constant velocity, let's name it BULLET_VELOCITY. Depending on your mouse position, Vx and Vy change so that sqrt(sqr(Vx)+sqr(Vy)) = BULLET_VELOCITY (V).It needs some math here.x1,y1 = Position of the turretx2,y2 = Mouse positionconst float cos_a = (y2-y1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float sin_a = (x2-x1) / sqrt( sqr(x2-x1) + sqr(y2-y1) );const float vX = BULLET_VELOCITY * sin_a;const float vY = BULLET_VELOCITY * cos_a;// x = v * tbullet->x(Vx * dt);bullet->y(Vy * dt);If your bullet moves with Vx speed in X axis and Vy speed in Y axis it will go straight to the position of the mouse.Hey. Thanks for the reply.I have a few questions:Is sqr supposed to be sqrt here?*** Source Snippet Removed ***You say that BULLET_VELOCITY is constant and that it is determined by V, right? I don't understand that part. I understand speed as how fast the object moves and velocity as the rate at which that object changes position, but here they seem to have reversed roles.Would your code sample be run every update loop for the projectile? If it's a bullet and not something like a homing missile, isn't there a way to leave out the position of the mouse and have the projectile move by a constant velocity vector?How would I rotate the actual turret using your code?Cheers.1) No, sqr(x) is x*x. I defined a macro to save typing. You can do it like this:#define sqr(x) (x) * (x)2) Think that speed and velocity are the same thing.3) No, my code is just before the bullet is fired. It calculates Vx and Vy so that the bullet goes at the position of the mouse.The position of the mouse is needed because Vx and Vy are based on it. See sin_a and cos_a.If you use the code in every frame, you can make a bullet that follows the mouse after it is fired, like a rocket that follows something :p4) Just by looking at the code, try setting its angle to sin_a or cos_a and see if it goes well.---So change those wrong sqrt in the code and it will work.   ;Quote:Original post by sheep191) No, sqr(x) is x*x. I defined a macro to save typing. You can do it like this:#define sqr(x) (x) * (x)Oh ok.Quote:Original post by sheep192) Think that speed and velocity are the same thing.But they're not though?Quote:Original post by sheep193) No, my code is just before the bullet is fired. It calculates Vx and Vy so that the bullet goes at the position of the mouse.The position of the mouse is needed because Vx and Vy are based on it. See sin_a and cos_a.If you use the code in every frame, you can make a bullet that follows the mouse after it is fired, like a rocket that follows something :pOh ok gotcha. So how do you update the bullet each frame then? E.g. what does your code look like that moves the bullet after it's been fired?Quote:Original post by sheep194) Just by looking at the code, try setting its angle to sin_a or cos_a and see if it goes well.Cool, will try that.Quote:Original post by sheep19So change those wrong sqrt in the code and it will work.It works! :D Thanks so much!   