1
\$\begingroup\$

I've been trying to work for a few days, on a little weapon system where you can aim with your mouse and shoot bullets in the direction you're aiming. This is all in 2D to be clear.

Right now, I can calculate the spawn point of the bullet at the tip of the gun quite well and the angle of the sprite is correct and pointing at the mouse however, I believe I am actually calculating the angle somehow inversely and because of this, I can't find a good way to give the bullets; when spawned; the correct starting velocity to fire in the correct direction as well as the correct sprite rotation.

Attached here is an image of what I mean by the inverse aiming angle

I am calculating and setting the angle of the sprite to the angle given between the mouse position and the character position like so: (Following code is in the Vector2 class)

double
Vector2::AngleRad(Vector2* other) {
    return atan2(other->y - y, other->x - x);
}

double
Vector2::AngleDeg(Vector2* other) {
    return radiansToDegrees(AngleRad(other));
}

and calculating the bullets spawn point (which works right now with the given angle, even though it's reversed) like so: (Following code is in the weapon class)

void
Weapon::CalculateBulletExit()
{
    double centerX = GetPos()->x + GetCollisionBox()->W() / 2;
    double centerY = GetPos()->y + GetCollisionBox()->H() / 2;
    double radius = GetCollisionBox()->W() / 2;

    double radiansDeg = degreesToRadians(entityAngle);

    pointOfExit->x = (centerX + radius * cos(radiansDeg));
    pointOfExit->y = (centerY + radius * sin(radiansDeg));
}

So now I want to spawn a bullet at the correct position (the tip of the gun) with the right sprite rotation, and the the correct object velocity. Right now this is how I am doing that: (Following code is in the bullet class)

bool 
Bullet::Spawn(double heading, Vector2* spawnPoint, double bulletSpeed)
{
    if (mat->dead) {
        //Make the bullet alive and then return true that the bullet has been spawned
        mat->dead = false;

        //Set position and initial velocity
        double xGoPos = spawnPoint->x - GetCollisionBox()->W() / 2;
        double yGoPos = spawnPoint->y - GetCollisionBox()->H() / 2;

        entityBox->X(xGoPos);
        entityBox->Y(yGoPos);

        linearVelocity->x = xGoPos + cos(degreesToRadians(heading)) * bulletSpeed;
        linearVelocity->y = yGoPos + sin(degreesToRadians(heading)) * bulletSpeed;

        entityAngle = heading;

        return true;
    }
    else {
        return false;
    }
}

But this is spawning the bullet with a sprite rotation facing 180° backwards, and a velocity weirdly pointing downwards and away. Plus the velocity seems to always towards the right even when I am aiming left.

What is the easiest and fastest way of giving a bullet a velocity in the direction of the mouse (aiming direction) and am I actually calculating the angle correctly or horrifically wrong? :P

From what I've researched and read, there's heaps of ways of getting the angle between two vectors but all I am able to precisely know is the character's bounding box as x, y, w, h. The weapon bounding box as x, y, w, h. And the mouse position as an x, y vector2 class I made. Thanks for any suggestions and help that I get!

\$\endgroup\$
1
\$\begingroup\$

To inverse the spawn point and other useful methods:

// renamed
double Vector2::AngleRadOther(Vector2 other)
{
    return atan2(y - other->y, x - other->x);
}

// renamed
double Vector2::AngleDegOther(Vector2* other)
{
    return radiansToDegrees(AngleRadOther(other));
}

double Vector2::AngleRad()
{
    return atan2(y, x);
}

double Vector2::AngleDeg()
{
    return radiansToDegrees(AngleRad());
}

double Vector2::GetLength()
{
    return sqrt(x * x + y * y);
}

void Vector2::Normalize()
{
    double length = GetLength();
    x /= length;
    y /= length;
}

Fix for velocity:

bool Bullet::Spawn(Vector2* headingVec, Vector2* spawnPoint, double bulletSpeed)
{
    if (mat->dead)
    {
        double headingDeg = headingVec->AngleDeg();

        //Make the bullet alive and then return true that the bullet has been spawned
        mat->dead = false;
        //Set position and initial velocity 
        double xGoPos = spawnPoint->x - GetCollisionBox()->W() / 2;
        double yGoPos = spawnPoint->y - GetCollisionBox()->H() / 2;
        entityBox->X(xGoPos); entityBox->Y(yGoPos);

        // Normalize vector so that its length is 1
        headingVec->Normalize();

        linearVelocity->x = headingVec->x * bulletSpeed;
        linearVelocity->y = headingVec->y * bulletSpeed;

        //linearVelocity->x = xGoPos + cos(degreesToRadians(heading)) * bulletSpeed;
        //linearVelocity->y = yGoPos + sin(degreesToRadians(heading)) * bulletSpeed;

        entityAngle = headingDeg;
        return true;
    }
    else
    {
        return false;
    }
}

You didn't post the code that calls Spawn but the Vector2 headingVec argument should be mousePosition - entityPosition entityPosition beeing the position of the entity from which the projectile is launched.

My c++ skills are very lacking so watchout for syntax errors!

\$\endgroup\$
  • \$\begingroup\$ Thank you so much! This worked perfectly. Also, you fixed my reversed angle issue. Thank you so much! \$\endgroup\$ – Aquaphor Sep 25 at 23:28
  • \$\begingroup\$ @Aquaphor You are welcome! But watchout I just edited my answer because there was a small bugg in the Vector2.Normalize method! (I divided x by length twice instead of dividing x and y by length once each) \$\endgroup\$ – Bartimaeus Sep 26 at 18:08
  • \$\begingroup\$ Also would be cool if you could +1 my answer to give me that juicy reputation \$\endgroup\$ – Bartimaeus Sep 26 at 18:31
  • \$\begingroup\$ I noticed that area and made sure to write it correctly in my code but thanks heaps. And np, upvoted \$\endgroup\$ – Aquaphor Sep 26 at 21:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.