(Java2D) How to shoot Bullets according to the player rotation

Hello,
Shooting bullets based on the player rotation was causing a little problem to me, and am sure that it will cause problems for other new developers here, so i decided to share a full example on how to shoot bullets based on the player rotation.

1st, like every Java 2D game we create our main class
there is nothing fancy here to explain

//this is the game window 

package rot;

import javax.swing.JFrame;

public class RotateME extends JFrame {

	public static final int WIDTH = 800, HEIGHT = 600;

	public RotateME() {

		add(new Board());

		setTitle("rotate me please");
		setSize(WIDTH, HEIGHT);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setResizable(true);
		setVisible(true);

	}

	public static void main(String[] args) {
		new RotateME();

	}

}

now we create the bullet class

package rot;

public class Bullet {

	private double x, y, a; // x,y and angle
	private int w, h; //width and height 

	// constructor
	public Bullet(double x, double y, double a, int w, int h) {

		this.x = x;
		this.y = y;
		this.a = a;
		this.w = w;
		this.h = h;
	}

	// returning all the necessary value of this class

	public double getX() {
		return x;
	}

	public double getY() {
		return y;
	}

	public double getA() {
		return a;
	}

	public int getW() {
		return w;
	}

	public int getH() {
		return h;
	}

	// setting the values
	public void setA(double aa) {

		this.a = aa;
	}

	public void setX(double x) {
		this.x = x;
	}

	public void setY(double y) {
		this.y = y;
	}
	public void setW(int w) {
		this.w = w;
	}

	public void setH(int h) {
		this.h = h;
	}

	// move toward the angle
	// //forward
	public void moveForward(int speed) {
		x += Math.cos(a)*speed;
		y += Math.sin(a)*speed;
	}

}

and the player class, i almost commented everything, i hope it’s clear for you


//this is the hero class

package rot;

import java.awt.Image;
import java.awt.Rectangle;
import java.util.ArrayList;

import javax.swing.ImageIcon;

public class Hero {

	private double x, y, a; // x,y and angle
	private int w, h, tmpLoad; // width and height and reloading counter (for
								// shooting)

	private ArrayList bullets; // this will hold our bullets 

	private String img = "res/hero.png"; // this is the path of the image
	private Image image;  //and this is the image 

	// constructor
	public Hero(double x, double y, double a, int w, int h) {

		this.x = x;
		this.y = y;
		this.a = a;
		this.w = w;
		this.h = h;

		bullets = new ArrayList();
		tmpLoad = 0;
		

		ImageIcon ii = new ImageIcon(img);
		image = ii.getImage();
	}

	// returning all the necessary value of this class

	public Image getI() {
		return image;
	}

	public double getX() {
		return x;
	}

	public double getY() {
		return y;
	}

	public double getA() {
		return a;
	}

	public int getW() {
		return w;
	}

	public int getH() {
		return h;
	}

	public Rectangle getBounds() {
		return new Rectangle((int) x, (int) y, w, h);
	}

	public ArrayList getBullets() {
		return bullets;
	}

	// setting the values
	public void setA(int aa) {

		a = Math.toRadians(aa);
	}

	public void setX(double x) {
		this.x = x;
	}

	public void setY(double y) {
		this.y = y;
	}

	// move toward the angle
	// //forward
	public void moveForward(int sx, int sy) {
		x += Math.cos(a) * sx;
		y += Math.sin(a) * sy;
	}

	// //backward
	public void moveBackword(int sx, int sy) {
		x -= Math.cos(a) * sx;
		y -= Math.sin(a) * sy;
	}

	/*
	 * firing load = how much time you wait between 2 bullets number = how many
	 * bullet you shot in a single shot spread = distance between 2 bullets
	 */
	public void fire(int load, int number, int spread) {
		
		// if reloading time is done
		if (tmpLoad == 0) { 

			for (int i = 0; i < number; i++) {
				// setting the bullet
				Board.bullet.setX(x + w);
				Board.bullet.setY(y + h / 2);
				Board.bullet.setA(a + ((spread * (i - 1)) / 2));
				Board.bullet.setW(5);
				Board.bullet.setH(5);
				// adding the bullet to the array list
				bullets.add(new Bullet(Board.bullet.getX(),
						Board.bullet.getY(), Board.bullet.getA(), Board.bullet
								.getW(), Board.bullet.getH()));
			}
			//reset the reload time 
			tmpLoad = load;
		} else {
			tmpLoad -= 1;
			
		}

	}
}


and this is the game board :


package rot;

//importing what we need 
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;

import javax.swing.JPanel;

public class Board extends JPanel implements Runnable {

	public static Bullet bullet;

	private Thread loop; // the loop
	private Hero hero;
	private ArrayList bullets;
	private int tmpAngle, sx, sy, reload, numToShoot, spread, bWidth,
			bHeight;
	private boolean moveForward, canForward, canBackward, moveBackward, left,
			right, fire, special;

	// constructor
	public Board() {
		init();
		addKeyListener(new Controll());
		addMouseListener(new Mouse());
		setFocusable(true);
		setBackground(new Color(0, 0, 0));
		setDoubleBuffered(true);
		setFocusable(true);

	}

	// initialisation
	private void init() {
		hero = new Hero(400, 300, 0, 50, 30);
		tmpAngle = 0;
		special = fire = left = right = moveForward = moveBackward = false;
		canForward = canBackward = true;
		sx = sy = 2;

		bullet = new Bullet(0, 0, 0, 0, 0);
		bullets = hero.getBullets();
		reload = 30;
		numToShoot = 1;
		spread = 0;


		loop = new Thread(this);
		loop.start();

	}

	public void paint(Graphics g) {
		super.paint(g);

		Graphics2D g2d = (Graphics2D) g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		AffineTransform old = g2d.getTransform();

		// rotating the hero, rotation point is the middle of the square
		g2d.rotate(hero.getA(), hero.getX() + hero.getW(),
				hero.getY() + hero.getH() / 2);
		// draw the image
		g2d.drawImage(hero.getI(), (int) hero.getX(), (int) hero.getY(),
				hero.getW(), hero.getH(), this);
		g2d.setTransform(old);

		// drawing the bullets
		ArrayList bullets = hero.getBullets();
		for (int i = 0; i < bullets.size(); i++) {
			Bullet tmpB = (Bullet) bullets.get(i);
                        //playing with bullet colors
			if (i % 2 == 0) {
				g2d.setColor(new Color(150, 130, 100));
			} else {
				g2d.setColor(new Color(60, 20, 120));
			}
			g2d.fillRect((int) tmpB.getX(), (int) tmpB.getY(), tmpB.getW(),
					tmpB.getH());
		}
		// in case you have other things to rotate
		g2d.setTransform(old);

	}

	public void play() {

		// if the hero get off the screen
		// we make it appear from the opposite side of the screen
		if (hero.getX() > 800) {
			hero.setX(0);
		} else if (hero.getX() < -100) {
			hero.setX(800);
		}

		if (hero.getY() > 600) {
			hero.setY(0);
		} else if (hero.getY() < -100) {
			hero.setY(600);
		}

		// moving bullets
		ArrayList tmpBs = hero.getBullets();
		for (int i = 0; i < tmpBs.size(); i++) {
			Bullet tmpB = (Bullet) tmpBs.get(i);

			tmpB.moveForward(3);

			if (tmpB.getX() > RotateME.WIDTH || tmpB.getX() < 0
					|| tmpB.getY() > RotateME.HEIGHT || tmpB.getY() < 0) {
				tmpBs.remove(i);
			}

		}

		// check if shooting
		if (fire) {
			hero.fire(reload, numToShoot, spread);
		}
		if (special) {
			hero.fire(5, 3, 2);
		}

		// changing the hero angle
		if (left) {
			tmpAngle -= 1;
		}
		if (right) {
			tmpAngle += 1;
		}

		// setting the hero angle
		hero.setA(tmpAngle);

		// this is just to keep the angle between 0 and 360
		if (tmpAngle > 360) {
			tmpAngle = 0;
		} else if (tmpAngle < 0) {
			tmpAngle = 360;

		}

		// moving the hero
		if (moveForward) {
			if (canForward) {
				hero.moveForward(sx, sy);
			}
		}
		if (moveBackward) {
			if (canBackward) {
				hero.moveBackword(sx, sy);
			}
		}

	}

	// game key controll
	// (my keyboard is AZERTY so ignore the multiple key in
	// the if statement
	private class Controll extends KeyAdapter {

		public void keyPressed(KeyEvent e) {

			if (e.getKeyCode() == e.VK_UP || e.getKeyCode() == e.VK_Z
					|| e.getKeyCode() == e.VK_W) {
				moveForward = true;

			}
			if (e.getKeyCode() == e.VK_DOWN || e.getKeyCode() == e.VK_S) {
				moveBackward = true;

			}
			if (e.getKeyCode() == e.VK_LEFT || e.getKeyCode() == e.VK_Q
					|| e.getKeyCode() == e.VK_A) {
				left = true;
			}
			if (e.getKeyCode() == e.VK_RIGHT || e.getKeyCode() == e.VK_D) {
				right = true;
			}
			if (e.getKeyCode() == e.VK_SHIFT) {
				fire = true;
			}

		}

		public void keyReleased(KeyEvent e) {

			if (e.getKeyCode() == e.VK_UP || e.getKeyCode() == e.VK_Z
					|| e.getKeyCode() == e.VK_W) {
				moveForward = false;
			}
			if (e.getKeyCode() == e.VK_DOWN || e.getKeyCode() == e.VK_S) {
				moveBackward = false;
			}
			if (e.getKeyCode() == e.VK_LEFT || e.getKeyCode() == e.VK_Q
					|| e.getKeyCode() == e.VK_A) {

				left = false;
			}
			if (e.getKeyCode() == e.VK_RIGHT || e.getKeyCode() == e.VK_D) {
				right = false;
			}
			if (e.getKeyCode() == e.VK_SHIFT) {
				fire = false;
			}
		}
	}

	// mouse control
	private class Mouse extends MouseAdapter {

		public void mousePressed(MouseEvent e) {
			if (e.getButton() == e.BUTTON1) {
				fire = true;
			}
			if (e.getButton() == e.BUTTON3) {
				special = true;
			}
		}

		public void mouseReleased(MouseEvent e) {
			if (e.getButton() == e.BUTTON1) {
				fire = false;
			}
			if (e.getButton() == e.BUTTON3) {
				special = false;

			}

		}
	}

	// the wors game loop ever
	@Override
	public void run() {

		while (true) {
			repaint();
			play();
			try {
				Thread.sleep(5);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

}


now before you are finish, you may want to use my hero ::slight_smile:

http://s4.postimg.org/kyixw0lo9/hero.png

in case you faced a problem during this line of code

private String img = "res/hero.png"; // this is the path of the image

make sure that you created a folder named “res” in your workspace project, then in eclipse
-right click to your main folder project --> refresh
-the new folder would appear, right click on it —> Build Path --> use as resource folder

and this is how the final result should look like (this is the special shot 8) )

http://s23.postimg.org/wg5csab6z/Sans_titre.png

i hope i was helpful ::slight_smile:

thank you for reading

PS :
Please make sure to read this article about game loops, the one i used in this example is WRONG and should not be used in a full game project, and i dunno why i don’t wanna fix it xD
sorry ::slight_smile:

Control has one l. ;D

LOL !!!
keep it between us :wink: