Bullets not getting shot out of the gun
Asked Answered
D

1

15

I'm making a little game just for fun and I got stuck making the bullets come out of the gun. In the code below, the direction of the player is a degree angle called rot.

float gunOffsetX = 106, gunOffsetY = 96;
double angle = Math.toRadians(rot); // convert direction of player from degrees to radians for sin and cos
x = getX(); // player X
y = getY(); // player Y

float bulletX = (float) (x + (gunOffsetX * Math.cos(angle) - gunOffsetY * Math.sin(angle)));
float bulletY = (float) (y + (gunOffsetX * Math.sin(angle) + gunOffsetY * Math.cos(angle)));
            
Instances.fire.add(new Fire(bulletX, bulletY, rot, weapon));

Also tried:

bulletX = (float) (x + Math.cos(angle + Math.atan2(gunOffsetX, gunOffsetY)) * Point2D.distance(0, 0, gunOffsetX, gunOffsetY));

But same results

Supposedly the bullets should spawn at the end of the gun but this isn't the case as you can see in the following gif..

enter image description here

Any help appreciated

Decalcomania answered 20/6, 2016 at 16:54 Comment(23)
Can you make the 106 and 96 constants?Cano
What happens when you don't move the playerCano
I assume you are aware that the coord system in java has 0 degrees facing eastwards, 180 facing west, and 270 facing north?Politicize
I suggest some debugging to see what the angle and the results are and were the discrepancy happens. Split out the calculation into several statements.Theall
Is this done in Java2D/Swing?Politicize
Or calculate angle and distance from player center to gun tip upfront - i.e. Math.atan2(106, 96) and Point2D.distance (0, 0, 106, 96). Then when you shoot, bulletX becomes x + Math.cos(angle + precalculated_angle) * precalculated_distance;Abuttals
What tools are you using for this?Nadda
@KevinWallis when I don't move the player it's the same thingDecalcomania
@AshwinGupta yes for both questionsDecalcomania
@Mr.DROPTABLE Java2D and nothing more, just sprites.Decalcomania
@CoderinoJavarino that didn't work and it looks like the bullets are getting shooted just as beforeDecalcomania
@DavidGomes 2 things. 1) How do you calculate the gunOfset variables? (like: 0.5 * w?) 2) Did you mean to add the gunOfsetX to the Math.sin() here (y + (gunOffsetX * Math.sin(angle)?Politicize
@AshwinGupta Well 1) I got the offsets from looking at the picture, 0, 0 was the origin of the picture then the offset is the end of gun; 2) hmm tbh I don't know because I copy pasted the code, I'm really that good at math.Decalcomania
@DavidGomes ok hold on, I'm going to try to work through your math. I just want to be very clear here though: Where is 0,0 in your coordinate system? In the center of the screen? Top left? Bottom right? Also, does y increase as you go south, or decrease as you go south?Politicize
@AshwinGupta Thanks for the help! 0, 0 is the top left, the y increases going south and x increases going eastDecalcomania
@DavidGomes I need to understand the update cycle and stuff. Can you put you full code on git or pastebin and link it?Politicize
@AshwinGupta I have a lot of classes.. what do you need? The draw and mouse aim code?Decalcomania
nice question btw. Could you 1) show the guy in the default image, and hilite where gunoffsetx and y are in that image? 2) where is getX() and getY() mapped to on the man? in the center, show that too? one hopes that getX/Y is the center, and offsetx/y are offsets from the centerHeyward
@DavidGomes preferably all of them. If not, the one that renders, the one with the game loop, and the one with this logic in it are the important ones.Politicize
@Heyward I don't think I need to post a photo, I'll say and if you don't understand I post another image. 1) gunoffsetx and y are the coordinates of the end of the gun 2) the getX/Y is the top left corner of the player imgDecalcomania
i'd think your problems would go away if 1) getX/getY where the center of the image, and 2) offsetX/offsetY where offsets from the center of the imageHeyward
@AshwinGupta Ok I'll put my project in gitDecalcomania
@AshwinGupta sorry for the late, I didn't know how to import eclipse project into git but the link is in the question.Decalcomania
A
13

One big issue (at least in my opinion) is how this game handles anchor points of shapes, like the player.

We can highlight the anchor point by drawing a little red rectangle on its place:

g.setColor(Color.RED);
g.drawRect((int)player.getX() -5, (int)player.getY() -5, 10, 10);

This comes into the Draw#renderGame(Graphics2D) method, so it looks like:

private void renderGame(Graphics2D g) {
    g.rotate(Math.toRadians(player.rot), player.getX()+64, player.getY()+64);
    g.drawImage(player.getCurrentFrame(), (int)player.getX(), (int)player.getY(), player.getWidth(), player.getHeight(), null);
    g.setColor(Color.RED);
    g.drawRect((int)player.getX() -5, (int)player.getY() -5, 10, 10);
    g.rotate(-Math.toRadians(player.rot), player.getX()+64, player.getY()+64);
    //...

then we'll see that the anchor point is not in the center of the image:

image with anchor point

As you can see, the anchor point (the original (0,0) point before the rotation) isn't in the center of the image and the crosshair is related to it, instead of the view of the player.

This happens due to the shifting operation while the player rotation:

g.rotate(Math.toRadians(player.rot), player.getX()+64, player.getY()+64);
//...
g.rotate(-Math.toRadians(player.rot), player.getX()+64, player.getY()+64);

You're shifting the postion with +64. I suggest to remove that and add the shifting to the g.drawImage call instead, so the anchor point is correctly in the center (mind that I avoided the fixed value 64):

g.rotate(Math.toRadians(player.rot), player.getX(), player.getY());
g.drawImage(player.getCurrentFrame(), (int)player.getX() - (player.getWidth() / 2), (int)player.getY() - (player.getHeight() / 2), player.getWidth(), player.getHeight(), null);
g.rotate(-Math.toRadians(player.rot), player.getX(), player.getY());

image with centerd anchor

Then you now fire the gun you'll see that the bullet always "starts" from a certain position from the player. The problem here is the incorrect offset you used. The proper values are:

float gunOffsetX = 35, gunOffsetY = 29;

(I got them by trial and error, so you may adjust them a bit more, if you like)

Now it looks like this:

shot fired, still misplaced

As you can see, the shot is still a bit misplaced, but this happens due to the incorrect rotation of the bullet (like you did it for the player shape):

g.rotate(Math.toRadians(f.rot), f.getX()+f.getWidth()/2, f.getY()+f.getHeight()/2);
g.drawImage(f.img, (int)f.getX(), (int)f.getY(), f.getWidth(), f.getHeight(), null);
g.rotate(-Math.toRadians(f.rot), f.getX()+f.getWidth()/2, f.getY()+f.getHeight()/2);

It should look like this (without any X or Y adjustments):

g.rotate(Math.toRadians(f.rot), f.getX(), f.getY());
g.drawImage(f.img, (int)f.getX(), (int)f.getY(), f.getWidth(), f.getHeight(), null);
g.rotate(-Math.toRadians(f.rot), f.getX(), f.getY());

The end result is:

shot fired, correctly placed

The player now correctly looks at the crosshair and the shots are placed in front of the gun.


If you like to fire directly through the center of the crosshair, you'll only need to adjust the player position and the bullet offset a bit.

Player (in Draw#renderGame(Graphics2D)):

g.drawImage(player.getCurrentFrame(), (int)player.getX() - (player.getWidth() / 2), (int)player.getY() - (player.getHeight() / 2) - 30, player.getWidth(), player.getHeight(), null);

(mind the -30 in (int)player.getY() - (player.getHeight() / 2) - 30)

Bullet:

float gunOffsetX = 35, gunOffsetY = 0;

Now the bullet travels right through the crosshair (mind that the red rectangle is right on the weapon):

shot fired, bullet through crosshair

(I'm a bit too stupid to create proper GIF files, so I can only provide pictures)


Now you have the necessary offset values to get the result you want, but you should definitely try to understand why the values are like they are right now. You need to replace them later with dynamic values, since different weapons need different offsets for the bullet, because the player image differs. It should be helpful to have some kind of class with instances for each weapon type, which contains the images and the coordinates where the weapon barrel is located in the image. Then you can use these coordinates to correctly set the offsets for the bullet image.

Andalusite answered 20/6, 2016 at 20:34 Comment(4)
@DavidGomes You're welcome. Don't forget to read the last paragraph. These constant offset values will cause you trouble if you implement different weapons (which are planned in the Weapon enum), so try to find a way to use dynamic offsets instead (they are in relation to the image size and barrel position in the image).Andalusite
Oh! You're so right! Thanks dude, btw can't I just make the offsets inside the enum and type the offsets in each weapon constructor then when using the offset just make "weapon.offsetX" for instance?Decalcomania
@DavidKenz Yes, that's also possible. Here is an example for user defined variables in an enum: docs.oracle.com/javase/tutorial/java/javaOO/enum.htmlAndalusite
Yea I know that, I did it too for fire interval :p but thanks for the huge help!Decalcomania

© 2022 - 2024 — McMap. All rights reserved.