Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [SOLVED] Setting bullets position to a weapon sprite that changes its rotation  (Read 4091 times)

0 Members and 1 Guest are viewing this topic.

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
I'm making my first sfml game, where so far i have a player that can move and shoot from the weapon that changes rotation so it always points towards mouse position.

My weapon sprites dimensions are 32x16 so i set the origin to 0,8 so the weapon rotates from the stock.
There is one problem.

When i set my bullets position to my weapon sprite, naturally it spawns the bullets at its origin which means that the weapon shoots from the stock which i definitely don't want.

I want my bullets to shoot from the barrel instead, but im struggling to put the math together in my mind.

It could be simple, and maybe im just dumb, but basically i want my bullets to spawn at the weapons sprite position with the origin of 32,8 instead of 0,8 without changing the origin, because obviously it would change the point of my rotation which i don't want.

Im thinking that probably something with trigonometry would bring me the desired result, but i can't get the idea how to do that.

Here is the part of the code:


[void Weapons::Shoot(float deltaTime, const sf::Vector2f& weaponPos, const sf::Vector2f& target)
{
    //updates weapon sprites position to the players position
    weaponSpr.setPosition(Player::sprite.getPosition());

   //an angle for the weapon rotation
    gunAngle = (atan2(target.y - weaponSpr.getPosition().y, target.x - weaponSpr.getPosition().x));
   
   
    weaponSpr.setRotation(gunAngle * 180 / M_PI);


    //flipping the weapon sprite if mouse points to the left side of the player which fixes visual bug

    if (target.x < weaponSpr.getPosition().x && weaponSpr.getScale().y > 0)
    {
        weaponSpr.setScale(weaponSpr.getScale().x, -weaponSpr.getScale().y);
       
    }
    if (target.x > weaponSpr.getPosition().x && weaponSpr.getScale().y < 0)
    {
        weaponSpr.setScale(weaponSpr.getScale().x, -weaponSpr.getScale().y);

    }


//generating bullets
if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) && clock.getElapsedTime().asSeconds() > fireRate)
{
    bullet.setPosition(weaponSpr.getPosition());
    bullets.push_back(bullet);
   
    //bullet direction
    angles.push_back(atan2(target.y - weaponSpr.getPosition().y, target.x - weaponSpr.getPosition().x));

    //rotation for the bullet so it points towards mouse
    rotation.push_back(atan2(target.y - bullets.back().getPosition().y, target.x - bullets.back().getPosition().x) * 180 / M_PI)
   
    clock.restart();
}


//moving the bullets
for (int i = 0; i <= bullets.size() - 1 && bullets.empty() == false; i++)
{
   
        bullets[i].move(cos(angles[i]) * bulletSpeed * deltaTime, sin(angles[i]) * bulletSpeed * deltaTime);
        bullets[i].setRotation(rotation[i]);
        ...
]
 
« Last Edit: June 23, 2024, 07:01:06 pm by Rogl »

Me-Myself-And-I

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
I'm not sure if this works right but you might be able to simply multiply the difference between the two origins against the sin() and tan().
Example:    newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle)),sprite.getPosition().y);

EDIT: My mistake. I guess that doesn't work right. I think i'm close tho.
« Last Edit: June 20, 2024, 04:44:54 am by Me-Myself-And-I »

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
I'm not sure if this works right but you might be able to simply multiply the difference between the two origins against the sin() and tan().
Example:    newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle)),sprite.getPosition().y);

EDIT: My mistake. I guess that doesn't work right. I think i'm close tho.
If you add cos on the x, then you need to add sin on the y.
newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle)),sprite.getPosition().y+(32*sin(angle)));

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
I'm not sure if this works right but you might be able to simply multiply the difference between the two origins against the sin() and tan().
Example:    newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle)),sprite.getPosition().y);

EDIT: My mistake. I guess that doesn't work right. I think i'm close tho.
If you add cos on the x, then you need to add sin on the y.
newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle)),sprite.getPosition().y+(32*sin(angle)));


If i do:
bullet.setPosition(weaponSpr.getPosition().x + (76 * cos(gunAngle)), weaponSpr.getPosition().y + (76 * sin(gunAngle)));

It works and its cool, but the bullets spawn a bit below the barrel which is very noticable.

I did 76 because it makes the bullets spawn exactly at the end of the barrel, i'm not sure why since i improvised and put the desired weapon sprite x origin which is 32, multiplied it by 2 and then added the bullets x origin.

Can somebody explain why i needed to put 76 instead of 32 (which is the right side of my sprite since my image is 32x16) + weapon x origin?

Also it seems like if i put a different number for the sin calculation, the positioning is off.

Since the bullets spawn a little bit below the barrel, i thought i'd just change the sin calculation like:
bullet.setPosition(weaponSpr.getPosition().x + (76 * cos(gunAngle)), weaponSpr.getPosition().y + (20 * sin(gunAngle)));


which is the same formula as i did for x (put the desired y origin which is 8, multiplied it by 2 and then added the bullets x origin)

Im clearly very, very off, and i'm just taking blind guesses because i don't even know why i needed to apply the calculations in that formula.

Can somebody break down the formula used {bullet.setPosition(weaponSpr.getPosition().x + (76 * cos(gunAngle)), weaponSpr.getPosition().y + (76 * sin(gunAngle)))} so i can, know how it works?

From what i understand i calculate x and y of my rotation angle by using sin and cos, but why am i multiplying 76 by that x and y to change the origin?

I don't want to just copy paste things and move on, i want to learn!

EDIT: I just understood why i had to multiply my desired origin by 2, im a dummy  :o ;D
I forgot that i changed the scale of my weapon to 2,2 so i had to multiply the origin by that scale.
But still, why when i want my bulltes spawn at the y origin of 8 of my weapon, i can't do 8 x scale + bullets y origin? Why does it have to be 76 like in x, for it to not act weird and spawn the bullets very off?
« Last Edit: June 20, 2024, 10:08:38 am by Rogl »

Me-Myself-And-I

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Quote
But still, why when i want my bulltes spawn at the y origin of 8 of my weapon, i can't do 8 x scale + bullets y origin? Why does it have to be 76 like in x, for it to not act weird and spawn the bullets very off?

Because the sin() and cos() make a ratio, you can't multiply two different numbers against it. A ratio is like a fraction. If you multiplied 5 to the top of 2/4ths and 10 to the bottom of 2/4ths you would no longer have the same fraction. You would have 10/40ths ,which simplifies to  1/4ths instead of 2/4ths.

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
Because the sin() and cos() make a ratio, you can't multiply two different numbers against it. A ratio is like a fraction. If you multiplied 5 to the top of 2/4ths and 10 to the bottom of 2/4ths you would no longer have the same fraction. You would have 10/40ths ,which simplifies to  1/4ths instead of 2/4ths.
So is there any way i can change the y axis?
From what i understood, this formula used to change the origin, applies only to the x axis.
There has to be a similar one for the y axis right?
« Last Edit: June 21, 2024, 12:55:14 pm by eXpl0it3r »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
To move globally in the direction of its local y axis as well as its x axis, you can add the sin/cos for each angle of the axis together.

Also, depending on how your doing collision, you might also consider moving the bullets origin "left" so that it would appear in the correct place automatically. e.g. to move the bullet 32 on its x axis (after rotation), subtract 32 from its origin's x.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Tigre Pablito

  • Full Member
  • ***
  • Posts: 226
    • View Profile
    • Email
Hi Rogl

Always it is a bit complicated to deal with trigonometry. I made a little sample of your game for you, which I attach. I hope you can translate from C#(C Sharp) to C++(C plus plus).  :)

Here's a video of me playing your game. It's missing to add the enemies, I leave that to you!  ;)



Regards
Pablo

EDIT: You say your player image is size (32, 16) and you set origin to (0, 8); Why not to (16, 8)? Wouldn't that be causing problems?
« Last Edit: June 22, 2024, 09:19:09 pm by Tigre Pablito »

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
Quote
EDIT: You say your player image is size (32, 16) and you set origin to (0, 8); Why not to (16, 8)? Wouldn't that be causing problems?

Hey Pablo!
First off i want to thank You for Your awesome engagement in this post, i really appreciate that!

The 32, 16 are the dimensions of my weapon sprite.
My player's sprite dimensions are 128, 128.
The answer to why i set my weapon sprite's origin to 0,8 instead of 16,8 is because i want my weapon's point of rotation to be its stock (which is on the left (x), middle (y) side of the image), so i had to set it like that. Its just a preference thing.

My goal for now is to make, my weapon's movement something similar to how this guy made in the beggining of this video:
But i want to make an invisible circle shape which is little bit bigger than my player's sprite, and make it so the weapon can only move if its within that circle.
So that invisible circle is basically a boundary in which the weapon can move freely, but the weapon can't escape the circle, creating this cool movement effect i pictured in my head.

I linked my project below as an attachment, so You can know the point at which my code is at the moment, and maybe You could give me a little hint!

PS. I had to stop working on my project (i know its small but its my first SFML project ever) because of the struggles with understanding trigonometry in programming, and now im trying my hardest to picture all those triangles in my head and learn how certain formulas work. Its hard without any visualization. If You know anything about the formula that i asked about in the previous replies:
 
bullet.setPosition(weaponSpr.getPosition().x + (76 * cos(gunAngle)), weaponSpr.getPosition().y + (76 * sin(gunAngle)));

, then it would be really cool if You could share some knowledge!
I still don't know how to change the y axis like i changed the x axis by applying that formula, which really bothers me, i want to learn...

Me-Myself-And-I

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
I'm sorry. I didn't know this was your first sfml project. I would like to make a suggestion. Take it easy.
Start with something simple and gradually get more complex projects. As you make projects you will gain experience that you can build new projects on. Coding math isn't exactly easy. You can make lots of projects without using any complex math. Or if you prefer starting with trigonometry thats ok. You decide where you want to start. I suggest you take a course on trigonometry though. Honestly I didn't understand why trigonometry worked in code till I had to learn it in school. Here is a good course that will tell you the "why"s of trigonometry.
I suggest skipping to lesson 77.
https://allinonehighschool.com/geometry-2023/










And this might help too. But I think the other course will help more than the video.
Hope that helps. :)

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Setting bullets position to a weapon sprite that changes its rotation
« Reply #10 on: June 23, 2024, 12:03:52 pm »
Quote
Here is a good course that will tell you the "why"s of trigonometry.
I suggest skipping to lesson 77.
https://allinonehighschool.com/geometry-2023/


And this might help too. But I think the other course will help more than the video.
Hope that helps. :)

Thank you very much for this beutiful advice and encouragement at the same time!
People on this forum are way, way nicer than anybody on stack overflow.
Im thankful for that  ;D

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Setting bullets position to a weapon sprite that changes its rotation
« Reply #11 on: June 23, 2024, 06:55:28 pm »
Quote
If You know anything about the formula that i asked about in the previous replies:
 
bullet.setPosition(weaponSpr.getPosition().x + (76 * cos(gunAngle)), weaponSpr.getPosition().y + (76 * sin(gunAngle)));

, then it would be really cool if You could share some knowledge!
I still don't know how to change the y axis like i changed the x axis by applying that formula, which really bothers me, i want to learn...

So after almost 3 days, it finally clicked.
The formula is so understandable and easy, but for some reason my mind rejected that string of numbers and resisted comprehending it for that long.
The solution for the bullets spawning below the barrel is just as easy.
all i had to do is to add "+0,-4" at the end of the set position xd

The final and correct solution for my problem is:
bullet.setPosition(weaponSpr.getPosition().x + (76 * cos(gunAngle)), weaponSpr.getPosition().y + (76 * sin(gunAngle)) + (0, -4));

Case closed.
Thanks to everybody that took their time to help selflessly!

Me-Myself-And-I

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Now i'm confused. How does this work? It doesn't work for me. Sure it stays close to the barrel but it gets shifted from one side of the barrel to the other as the rotation occurs. When you say x-axis and y-axis I assume your talking about the difference based on what you consider the vertical and horizontal position of the sprite. Rotations don't act this way. Your x and y axis positions change continually because as the rotation occurs the canvas coordinate system stays the same. You have to think in terms of angle and distance from the circle center.

The distance from the centerpoint is adjusted by multiplying one distance against the ratio.
This essentially changes the radius of the circle, making it farther away from the center.
newbullet.shape.setPosition(weaponSpr.getPosition().x+(32*cos(angle)),weaponSpr.getPosition().y+(32*sin(angle)));
 

Then the angle changes the rotation on that circles edge.

Like so.

                       
newbullet.shape.setPosition(weaponSpr.getPosition().x+(32*cos(angle+45)),weaponSpr.getPosition().y+(32*sin(angle+45)));
 

I'm not sure how to get the right values for it. I think you just have to adjust it by trial and error or figure out the math needed to convert the side height to the angle.
Perhaps i'm wrong. If i'm wrong then someone please say so. I'm just not sure how adding (0,-4) to the starting y position is any different than adding plain -4 to the y position. Which ,as we have seen in the last few posts, does not work because it offsets the angle.
So sorry to ruin your glory.

Rogl

  • Newbie
  • *
  • Posts: 7
    • View Profile
Quote
Now i'm confused. How does this work?

From what i understand, the formula does the following:
adds weapons x axis to 76 * x axis of the angle which is calculated by using cos. Does the same for the y axis.
So basically it adds an offset to the bullets spawning location which in my case is 76.
Since it is a ratio i cant put a different number thats multiplying by sin of the rotation angle which is y.
So what i did is just add 0,-4 to that ratio which doesn't change x, but changes y by -4, so now my bullets spawn on the barrel.

Regarding your problem with shifting of the barrel as the rotation occurs, i have this piece of code in my project that flips the weapon during rotation so it always shoots with its barrel.
Without this code the weapon shoots from its stock when aiming left, and shoots from its barrel when aiming right.
It's a simple fix for this visual bug, but if i understood you wrong let me know.

if (target.x < weaponSpr.getPosition().x && weaponSpr.getScale().y > 0)
{
    weaponSpr.setScale(weaponSpr.getScale().x, -weaponSpr.getScale().y);

}
if (target.x > weaponSpr.getPosition().x && weaponSpr.getScale().y < 0)
{
    weaponSpr.setScale(weaponSpr.getScale().x, -weaponSpr.getScale().y);

}

One thing that leaves a questionmark in my head, is that in that ratio y is also set to 76 which should offset my bullets spawning location way, way below the barrel, but it offsets only so little that when changing the y axis by -4 it spawns right on the barrel, perfectly.

I could've understood everything wrong and fixed it by accident which would be very weird, so let me know if what i said makes any sense.

PS. why 76?
Because its the  changed x origin of my weapon which i wanted to be 32 and since i changed the weapons scale to 2,2 then i had to multiply it by 2. now we have 64 and what is left is to add the bullet x axis of the origin to that number which gives us 76.

EDIT: I shared my weapons texture as an attachment, so you can copy the code, apply it to that specific texture and see for yourself.
« Last Edit: June 24, 2024, 12:57:17 pm by Rogl »

Me-Myself-And-I

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
I guess its a hack solution that works for you in your specific usage. That's fine to do. As long as it works for you that's good. I just wanted to give the solution for anyone who doesn't happen to have their weapon barrel flip like that. Such as when you want the bullet to be offset but not necessarily have a barrel to cover it.This solution that you used doesn't work if the offset happens to be a larger number.

I successfully made the offset without noticing any rotation change.
Here is a snapshot.



The code I used was the following:

                       
Bullet newbullet;
                       
                       
newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle+45)),sprite.getPosition().y+(32*sin(angle+45)));
newbullet.go=Vector2f((cos(angle)),sin(angle));
bullet.push_back(newbullet);

                       
newbullet.shape.setPosition(sprite.getPosition().x+(32*cos(angle-45)),sprite.getPosition().y+(32*sin(angle-45)));
newbullet.go=Vector2f((cos(angle)),sin(angle));
bullet.push_back(newbullet);
 

Since you already have a solution that is good enough i'll just offer this code to others and say to you Have a nice day! :D