[Solved] Bullet not shooting in correct direction!

                 Alright, so I made a Mother Ship that can point at an enemy using the Math I'm currently learning in my High School Geometry class, but the bullet that the ship shoots does not go in the direction the ship is shooting unless the ship is pointing at a perfect right angle. 

the bullets get spawned in with a ‘BulletDirection’ variable supplied by the ship that spawned it. In the ship class this is the code used to get the direction, I added 90 to the end to flip it around as they were pointing backwards.

GunDirection = (int) Math.toDegrees(Math.atan2(TargetShip.getPosition().y - Position.y, TargetShip.getPosition().x - Position.x))-90;

then later created in the bulletList

bulletList.add(new Bullet( (int) GunDirection , (int) Position.x + (240/2), (int) Position.y + (240/2), this.Faction, BulletTexture));

and then there’s the bullet class:

public class Bullet {

	private int bulletDirection;
	private float bulletSpeed = 3f;
	private int bulletX, bulletY;
	private int Faction = 0;
	private boolean isAlive;
	private Texture bulletTexture;
	private Rectangle rect;
	
	public Bullet(int bulletDirection, int bulletX, int bulletY, int Faction, Texture bulletTexture){
		this.bulletDirection = bulletDirection;
		this.setBulletX((int) ((bulletX +Math.cos(bulletDirection))));
		this.setBulletY((int) ((bulletY+Math.sin(bulletDirection))));
		this.bulletTexture = bulletTexture;
		this.setFaction(Faction);
		rect = new Rectangle();
		rect.setSize(12,12);
	}
	
	public void render(SpriteBatch batch){
		batch.draw(bulletTexture, bulletX, bulletY);
		
	}
	
	public void update(){
		rect.x = bulletX;
		rect.y = bulletY;
		bulletX += Math.cos(Math.toRadians(bulletDirection + 90) )*bulletSpeed;
		bulletY += Math.sin(Math.toRadians(bulletDirection + 90))*bulletSpeed;
	}

This is what the picture for the gun starts off as:

P.S. Sorry for the barrage of questions this past week, I try my best to keep stuff specific and spent at least a few hours googling and applying before I give up in frustration and end up here. I hope my newbie-ness is not bothering anyone :clue:

You’d have much better luck if you posted an MCVE and stuck with standard naming conventions (variables start with lower-case letters).

Why are you subtracting 90 from GunDirection? Why do you then add 90 to bulletDirection? Why do you add (240/2) to the x and y positions?

An MCVE would make this much easier- it doesn’t even have to be graphical. Just give us a main method with hardcoded variables, the equations you’re putting them through, and the output that you’re getting versus what you’re expecting.

Alright, I’ll try my best to to this.

I subtracted 90 because the guns were looking away from there targets instead of towards them.

I then added 90 to the bullets because if I don’t the bullet direction will go to the right of the gun.

I’m simply trying to spawn a Bullet In the Direction the gun is facing and make the bullet keep going in the direction by:

*Getting the direction of the Gun

GunDirection = (int) Math.toDegrees(Math.atan2(TargetShip.getPosition().y - Position.y, TargetShip.getPosition().x - Position.x)-90);

*Creating the bullet in the Middle of the Gun with the direction its facing

bulletList.add(new Bullet( (int) GunDirection , (int) Position.x + (Width/2), (int) Position.y + (Width/2), this.Faction, BulletTexture));

*Set the Position of the bullet

this.setBulletX((int) ((bulletX +Math.cos(bulletDirection))));
this.setBulletY((int) ((bulletY+Math.sin(bulletDirection))));
  • And making it continuously go in the direction of the gun
bulletX += Math.cos(Math.toRadians(bulletDirection))*bulletSpeed;
		bulletY += Math.sin(Math.toRadians(bulletDirection ))*bulletSpeed;


The code works fine when the gun is pointing directly at a right angle, but the farther away and the farther away the gun is from being 90 degrees the more innacurate it becomes.

I changed the image to be pointing down and I now don’t need the +90 or -90, but the bullets are still inaccurate the farther the gun is from 90 degrees and the farther away the gun is.

Here is a little example program that shoots bullets in the direction of the mouse, from the center of the screen:


import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main extends JPanel{
	
	List<Bullet> bullets = new ArrayList<Bullet>();

	public static void main(String... args) {
		new Main();
	}
	
	public Main(){
		JFrame frame = new JFrame("Bullet Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		frame.add(this);
		
		Timer t = new Timer(33, new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				for(int i = bullets.size()-1; i >= 0; i--){
					bullets.get(i).step();
				}
				repaint();
			}
			
		});
		
		t.start();
		
		addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				shoot(e.getX(), e.getY());
			}
		});
		
		addMouseMotionListener(new MouseAdapter(){
			public void mouseDragged(MouseEvent e){
				shoot(e.getX(), e.getY());
			}
		});
		
		setBackground(Color.BLACK);
		
		frame.setSize(500, 500);
		frame.setVisible(true);
		
	}
	
	public void shoot(double targetX, double targetY) {
		
		double gunX = getWidth()/2;
		double gunY = getHeight()/2;

		
		double speed = 5;
		
		double bulletAngle = Math.toDegrees(Math.atan2(targetY - gunY, targetX - gunX));
		double deltaX = Math.cos(Math.toRadians(bulletAngle))*speed;
		double deltaY = Math.sin(Math.toRadians(bulletAngle ))*speed;
		
		bullets.add(new Bullet(gunX, gunY, deltaX, deltaY));

	}
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		for(int i = bullets.size()-1; i >= 0; i--){
			bullets.get(i).paint(g);
		}
	}
	
	class Bullet{
		
		double x;
		double y;
		double deltaX;
		double deltaY;
		int life = 100;
		
		public Bullet(double x, double y, double deltaX, double deltaY){
			this.x = x;
			this.y = y;
			this.deltaX = deltaX;
			this.deltaY = deltaY;
		}
		
		public void paint(Graphics g){
			g.setColor(Color.WHITE);
			g.fillOval((int)x, (int)y, 10, 10);
		}
		
		public void step(){
			
			x += deltaX;
			y += deltaY;
			life--;
			if(life == 0){
				bullets.remove(this);
			}
		}
		
		
	}
}

Please modify this so it exhibits your unwanted behavior, that way we’re all working from the same code.

Edit: Also keep in mind that you don’t really need to use any trig for this problem. Just use the X and Y distances between the gun and the target to set your initial bullet speed.

I guess my problem is just actually positioning the bullet, not the direction it goes. H’m. I’m not exactly sure how I would put it into that code, and doing so would just show you the exact 4 lines I showed you before except in a more complicated manner. ???

Nope, its the angle. The way the gun is pointing does not equal the way the bullet is going at all.

That code is almost exactly like my code though, I have no idea what to put in there.

What do you mean by positioning the bullet? Where do you want to position it?

I’m not sure what you mean by this.

You don’t necessarily have to add anything. Let me put it this way: what does my code not do that you want it to?

Well for the first question, I want to position the bullet in the middle of the Ship.

For the second: If, my gun is pointing directly up, the bullet will go quite a bit to the left instead, and not even pass through the barrel.

And for the third: It does exactly what I want to do, except of course, position the bullet in the correct area of the ship, and shoot in the direction that its pointing.

For the positioning: in theory you already know the position of the tip of the gun, right? Just put the bullet there.

If you don’t know the position, then you can use the same logic you use the figure out the deltaX and deltaY, just use the length of the gun instead of the speed.

For the angle, stop adding and subtracting 90! :stuck_out_tongue:

I stopped subtract and adding 90 since I made the image point down. It’s still doing the same.

Here’s another little example that might be closer to what you’re looking for. It shows some “ships” travelling at random headings, and shows the “nose” of each ship as a red circle. You should be able to combine this example with the previous example to achieve the effect you’re going for:


import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main extends JPanel{

	List<Ship> ships = new ArrayList<Ship>();

	public static void main(String... args) {
		new Main();
	}

	public Main(){
		JFrame frame = new JFrame("Bullet Test");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame.add(this);

		Timer t = new Timer(33, new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				for(int i = ships.size()-1; i >= 0; i--){
					ships.get(i).step();
				}
				repaint();
			}

		});

		t.start();

		addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				ships.add(new Ship(e.getX(), e.getY()));
			}
		});



		setBackground(Color.BLACK);

		frame.setSize(500, 500);
		frame.setVisible(true);

	}



	public void paintComponent(Graphics g){
		super.paintComponent(g);
		for(int i = ships.size()-1; i >= 0; i--){
			ships.get(i).paint(g);
		}
	}

	class Ship{

		double x;
		double y;
		double heading;
		double speed = 5;
		double radius = 10;

		public Ship(double x, double y){
			this.x = x;
			this.y = y;
			heading = Math.random()*360;

		}

		public void paint(Graphics g){
			g.setColor(Color.WHITE);
			g.fillOval((int)(x-radius), (int)(y-radius), (int)radius*2, (int)radius*2);


			double noseX = x+Math.cos(Math.toRadians(heading))*radius;
			double noseY = y+Math.sin(Math.toRadians(heading ))*radius;

			g.setColor(Color.RED);
			g.fillOval((int)(noseX-radius/2), (int)(noseY-radius/2), (int)radius, (int)radius);

		}

		public void step(){
			
			heading += -10 + Math.random()*20;


			double deltaX = Math.cos(Math.toRadians(heading))*speed;
			double deltaY = Math.sin(Math.toRadians(heading ))*speed;

			x += deltaX;
			y += deltaY;

			if(x < 0){
				x = getWidth();
			}
			if(x > getWidth()){
				x = 0;
			}

			if(y < 0){
				y = getWidth();
			}
			if(y > getWidth()){
				y = 0;
			}

		}
	}
}

I highly doubt the conversion between radians and degrees is the culprit. More likely it’s the wonky math you’ve got in there. But it’s pretty hard to debug without looking at the same small code base, which is why I’m trying to work from the examples I posted.

This gets the direction of the gun and rotates it:

GunDirection = (int) Math.toDegrees(Math.atan2(TargetShip.getOriginY()  - OriginPositionY, TargetShip.getOriginX() - OriginPositionX));

This makes the bullet:


bulletList.add(new Bullet( (int) GunDirection , (int) OriginPositionX, (int) OriginPositionY, Faction, BulletTexture));

This sets the bullets position right when it spawns:


this.setBulletX((int) (bulletX + Math.cos(Math.toRadians(bulletDirection))));
this.setBulletY((int) (bulletY + Math.sin(Math.toRadians(bulletDirection))));


And this moves the bullet in the direction its supposed to go:

bulletX += Math.cos(Math.toRadians(bulletDirection))*bulletSpeed;
		bulletY += Math.sin(Math.toRadians(bulletDirection))*bulletSpeed;

These are all the code snippets of where any math is used for this, I don’t understand what else you need, unless you want the actual class file of the Mother ship and bullet, then here :frowning: :

MotherShip

package com.me.eclipse.entities;

import java.util.ArrayList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

public class Ship_MotherShip implements Ship {

	public int Faction = 0, Hull = 500, upKeep;
	public Vector2 Position = new Vector2();
	private TextureRegion Ship_Base, Ship_Top, Ship_Gun;
	private Texture ShipSelect, BulletTexture;
	private int BaseDirection, TopDirection, GunDirection = 90;
	private int Width, Height, OriginX, OriginY, OriginPositionX, OriginPositionY, shootDelay = 0;
	private int GoalX, GoalY, Speed = 3;
	private boolean isHovered = false, isSelected = false;
	private Ship TargetShip;
	private Rectangle rect;
	private ArrayList<Bullet> bulletList;

	public Ship_MotherShip(int x, int y, TextureRegion Ship_Base,
			TextureRegion Ship_Top, TextureRegion Ship_Gun, Texture ShipSelect, ArrayList<Bullet> bulletList) {
		this.Ship_Base = Ship_Base;
		this.Ship_Top = Ship_Top;
		this.Ship_Gun = Ship_Gun;
		this.ShipSelect = ShipSelect;
		this.Position.x = x;
		this.Position.y = y;
		this.GoalX = x;
		this.GoalY = y;
		this.Hull = 500;
		this.upKeep = 0;
		this.Faction = 0;
		this.Width = Ship_Base.getRegionWidth();
		this.Height = Ship_Base.getRegionHeight();
		this.OriginX  = Width/2;
		this.OriginY = Height/2;
		this.OriginPositionX = (int) Position.x + OriginX;
		this.OriginPositionY = (int) Position.y + OriginY;
		this.bulletList = bulletList;
		
		rect = new Rectangle();
		rect.setWidth(Ship_Base.getRegionWidth());
		rect.setHeight(Ship_Base.getRegionHeight());
		
		BulletTexture = new Texture(Gdx.files.internal("data/Ships/Bullet.png"));
	}

	@Override
	public void render(SpriteBatch batch) {
		System.out.println("Rednering");
		batch.draw(Ship_Base, Position.x, Position.y, OriginX, OriginY, Width,
				Height, 1, 1, BaseDirection, false);
		batch.draw(Ship_Top, Position.x, Position.y, OriginX, OriginY, Width,
				Height, 1, 1, TopDirection, false);

		batch.draw(Ship_Gun, Position.x, Position.y, OriginX, OriginY, Width,
				Height, 1, 1, GunDirection, false);

		if (isSelected) {
			batch.draw(ShipSelect, Position.x, Position.y);
		}

	}

	@Override
	public void renderGlobal(Texture GreenGlobal, Texture RedGlobal,
			Texture WhiteGlobal, SpriteBatch batch) {
		if (Faction == 0) {
			batch.draw(WhiteGlobal, Position.x - 380, Position.y - 280);
		}
		if (Faction == 1) {
			batch.draw(GreenGlobal, Position.x - 380, Position.y - 280);
		}
		if (Faction == 2) {
			batch.draw(RedGlobal, Position.x - 380, Position.y - 280);
		}

	}

	@Override
	public void update(Vector3 MousePos, Sound select) {
		this.OriginPositionX = (int) Position.x + OriginX;
		this.OriginPositionY = (int) Position.y + OriginY;
		rect.setPosition(Position.x, Position.y);
		BaseDirection += 1;
		shootDelay += 1;
		targetEnemy();
		
		if(shootDelay >= 150){
			Shoot();
			shootDelay -= shootDelay;
		}

		/* Check for mouse hover and selection */
		if (MousePos.x < Position.x + Width && MousePos.x > Position.x
				&& MousePos.y < Position.y + Height && MousePos.y > Position.y) {
			isHovered = true;
		} else {
			isHovered = false;
		}

		if (isHovered && isSelected == false && Faction == 1
				&& Gdx.input.isButtonPressed(Buttons.LEFT)) {
			select.play();
			setSelected(true);
		}
		if (isHovered == false && Gdx.input.isButtonPressed(Buttons.LEFT)) {
			setSelected(false);
			;
		}

		/* Check for mouse move actions */
		if (isSelected == true && Gdx.input.isButtonPressed(Buttons.RIGHT)) {
			moveTo((int) MousePos.x, (int) MousePos.y);
		}

		/* Move to Goal */
		if (Position.x < GoalX) {
			Position.x += Speed;
		}
		if (Position.x > GoalX) {
			Position.x -= Speed;
		}
		if (Position.y < GoalY) {
			Position.y += Speed;
		}
		if (Position.y > GoalY) {
			Position.y -= Speed;
		}

	}

	@Override
	public void findEnemy(Ship ship) {

		if (TargetShip == null && ship.getFaction() != this.Faction) {
			this.TargetShip = ship;
			System.out.println("Target Acquired");
		}

	}

	@Override
	public void targetEnemy() {
		if (TargetShip != null) {
			GunDirection = (int) Math.toDegrees(Math.atan2(TargetShip.getOriginY()  - OriginPositionY, TargetShip.getOriginX() - OriginPositionX));
			System.out.println(GunDirection);
		}
	}

	@Override
	public void moveTo(int x, int y) {
		this.GoalX = x;
		this.GoalY = y;

	}

	@Override
	public int getFaction() {

		return Faction;
	}

	@Override
	public void setFaction(int faction) {
		this.Faction = faction;

	}

	@Override
	public int getHull() {

		return Hull;
	}

	@Override
	public void setHull(int hull) {
		this.Hull = hull;

	}

	@Override
	public int getUpkeep() {

		return upKeep;
	}

	@Override
	public void setUpkeep(int upkeep) {
		this.upKeep = upkeep;

	}

	@Override
	public Vector2 getPosition() {

		return Position;
	}

	@Override
	public void setPosition(Vector2 position) {
		this.Position = position;

	}

	public int getGoalX() {
		return GoalX;
	}

	public void setGoalX(int goalX) {
		GoalX = goalX;
	}

	public int getGoalY() {
		return GoalY;
	}

	public void setGoalY(int goalY) {
		GoalY = goalY;
	}

	public boolean isSelected() {
		return isSelected;
	}

	public void setSelected(boolean isSelected) {
		this.isSelected = isSelected;
	}
	

	@Override
	public int getSpeed() {

		return Speed;
	}

	@Override
	public Rectangle getRectangle() {
		return rect;
	}
	
	@Override
	public void Shoot(){
		bulletList.add(new Bullet( (int) GunDirection , (int) OriginPositionX, (int) OriginPositionY, Faction, BulletTexture));
	}

	@Override
	public int getOriginX() {
		return OriginPositionX;
	}

	@Override
	public int getOriginY() {
		return OriginPositionY;
	}

}

Bullet


package com.me.eclipse.entities;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;

public class Bullet {

	private int bulletDirection;
	private float bulletSpeed = 3f;
	private int bulletX, bulletY;
	private int Faction = 0;
	private boolean isAlive;
	private Texture bulletTexture;
	private Rectangle rect;
	
	public Bullet(int bulletDirection, int bulletX, int bulletY, int Faction, Texture bulletTexture){
		this.bulletDirection = bulletDirection;
		this.setBulletX((int) (bulletX + Math.cos(Math.toRadians(bulletDirection))));
		this.setBulletY((int) (bulletY + Math.sin(Math.toRadians(bulletDirection))));
		this.bulletTexture = bulletTexture;
		this.setFaction(Faction);
		rect = new Rectangle();
		rect.setSize(12,12);
	}
	
	public void render(SpriteBatch batch){
		batch.draw(bulletTexture, bulletX, bulletY);
		
	}
	
	public void update(){
		rect.x = bulletX;
		rect.y = bulletY;
		bulletX += Math.cos(Math.toRadians(bulletDirection))*bulletSpeed;
		bulletY += Math.sin(Math.toRadians(bulletDirection))*bulletSpeed;
	}

	public boolean isAlive() {
		return isAlive;
	}

	public void setAlive(boolean isAlive) {
		this.isAlive = isAlive;
	}

	public int getBulletX() {
		return bulletX;
	}

	public void setBulletX(int bulletX) {
		this.bulletX = bulletX;
	}

	public int getBulletY() {
		return bulletY;
	}

	public void setBulletY(int bulletY) {
		this.bulletY = bulletY;
	}
	
	public Rectangle getRectangle(){
		return rect;
	}

	public int getFaction() {
		return Faction;
	}

	public void setFaction(int faction) {
		Faction = faction;
	}
}

Ensure you are doing atan2 the correct way. Origin - target, not the other way around.

Also ensure that you are multiplying the cos and sin by the same value.

If atan2 is not working (for whatever reason), use vectors. Get dst, square it and normalise (this could be completely wrong, tired as shit).

Doing Origin - Target makes them look in opposite directions, and multiply what?

Negate it.

MathUtils.atan2(-(originY - targetY),  - (originX -  targetX));

When doing cos and sin, you multiply it by a scalar.


velocityX = MathUtils.cos(angle)  * speed
velocity  MathUtils.sin(angle)  * speed

Ensure speed (or whatever you call it) remain the same during both multiplications.

You also need to learn to use vectors to encapsulate your data.

You can literally half your members, they also have really nice functions.

If I do this, then they’re always looking left


GunDirection = (int) Math.toDegrees(Math.atan2(-(OriginPositionY  - TargetShip.getOriginY()), -OriginPositionX - TargetShip.getOriginX()));

and also, my bullets are already using the same bulletDirection in both the statements:

bulletX += Math.cos(Math.toRadians(bulletDirection))*bulletSpeed;
bulletY += Math.sin(Math.toRadians(bulletDirection))*bulletSpeed;