2
\$\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 Answer 1

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\$
4
  • \$\begingroup\$ Thank you so much! This worked perfectly. Also, you fixed my reversed angle issue. Thank you so much! \$\endgroup\$
    – Aquaphor
    Commented Sep 25, 2019 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
    Commented Sep 26, 2019 at 18:08
  • \$\begingroup\$ Also would be cool if you could +1 my answer to give me that juicy reputation \$\endgroup\$
    – Bartimaeus
    Commented Sep 26, 2019 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
    Commented Sep 26, 2019 at 21:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .