[SOLVED] Top down shooter - position of the bullet after rotating the player

Hi Everyone!

I am struggling with trigonometry. :slightly_smiling: In my top down shooter game, I am trying to set the position of the bullet when the player shoots, but I cannot find the working solution and it drives me crazy. I am really bad in trigonometry (that’s my Sin…bad joke, I know :D), so if anyone could help me fixing my code that would be very good.

Here is my problem with a screenshot:

As you can see the bullet is always a bit above the gun (it is always on the top of the Origin of the texture).
The full source code is here:
Dropbox link

I was following different tutorials, and the best what I found calculates the angle and the position like this:

MouseState mouse = Mouse.GetState();

Vector2 mousePosition = new Vector2(mouse.Position.X, mouse.Position.Y);
//This is the player on the picture.           
Vector2 survivorPosition = new Vector2(RectangleSurvivorDestination.X, RectangleSurvivorDestination.Y);

Vector2 vector = (mousePosition - survivorPosition);

if(vector != Vector2.Zero)

AngleSurvivor = (float)Math.Atan2(vector.Y, vector.X);
AngleBullet = AngleSurvivor;

//So far so good, the player and even the bullet is rotating properly.

//The player texture width is 77px, height is 33px. I used hard-coded values
//for better readability.
//(77.0f / 2.0f) - this is because the Origin is the center of the image and I
//wanted the bullet to come from out of the barrel of the gun.
//(33.0f / 1.0f) - the gun is not at the center of the image, so I wanted to
//shift the bullet down to the barrel. Maybe this is wrong.
Vector2 bulletPosition = new Vector2(
   (float)(survivorPosition.X + (77.0f / 2.0f) * Math.Cos(AngleSurvivor)),
   (float)(survivorPosition.Y + (33.0f / 1.0f) * Math.Sin(AngleSurvivor)));
   RectangleBulletDestination = new Rectangle(
   (int)bulletPosition.X, (int)bulletPosition.Y,
   RectangleBulletDestination.Width, RectangleBulletDestination.Height);

Any ideas? :slightly_smiling: Thank you in advance!

Looks like a simple alignment problem, from your pictures…
The bullet looks like its off by the same amount in all the pics, so you could probably value-tweak your way out… Would be my guess…

But I think you should have this:

First find by how much the muzzle is different from the player. I store this in a vector2… differenceVector = new Vector2( gunLength, body width/2)…

This “difference” vector can now be used to determine the position of the muzzle, using the rotation of the player…

I always use some variance of this:

public static Vector2 RotateVector2(Vector2 point, float radians, Vector2 pivot)
float cosRadians = (float)Math.Cos(radians);
float sinRadians = (float)Math.Sin(radians);

        Vector2 translatedPoint = new Vector2();
        translatedPoint.X = point.X - pivot.X;
        translatedPoint.Y = point.Y - pivot.Y;

        Vector2 rotatedPoint = new Vector2();
        rotatedPoint.X = translatedPoint.X * cosRadians - translatedPoint.Y * sinRadians + pivot.X;
        rotatedPoint.Y = translatedPoint.X * sinRadians + translatedPoint.Y * cosRadians + pivot.Y;

        return rotatedPoint;

Its a method that takes the point you want spun, the amount you want it spun, and the position you want it spun around, and returns a new position…
In your case that would be something like:

MuzzlePos = playerPos + diffenceVector;
muzzlePos = RotateVector2(muzzlePos, playerRotation, playerPos)

you can even change the differenceVector to allow for recoil very easily…

Having a muzzle pos is also usefull for smoke and flash effects…

Then of course you spawn your bullet on the muzzle pos…

You are a god, no less! :slightly_smiling: Thank you very much! One day I will re-learn all these trigonometry things…

lol, I’m gonna tell my mom, she’ll be pleased…

I use that method and a few other ones in a “common methods/functions” static class in my games…

I also have one for “is the point above or below the line”…

-They return values from overloads only, so I have no trouble with them being global…

1 Like

Yes, obviously I also put this into a static class and it serves me well since then! :slightly_smiling: The solution I attached was just a pure test app, without my so-called “engine” and without any proper project/code architecture.