본문 바로가기

Swing/BufferedImage Rotation

BufferedImage Rotation example

화면 중심을 기준으로 마우스를 따라 회전하는 BufferedImage 의 예



화면 중앙에서 마우스 위치를 향하여 회전하며 마우스를 클릭하면 마우스 방향으로 포탄이 발사되는 예제


GameWindow.java, GamePanel.java

package rotation;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.util.*;

import javax.swing.*;

public class GameWindow extends JFrame 
{
	public GameWindow(){
		setTitle("회전 테스트");
		getContentPane().setLayout(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100,50,540,560);
		
		GamePanel gp = new GamePanel();
		add(gp);

		setVisible(true);
	}
	public static void main(String[] args) 
	{
		new GameWindow();
	}
}

class GamePanel extends JPanel
{
	BufferedImage circle;
	BufferedImage barrel;

	java.util.List<Cannonball> ballList = new ArrayList<>();
	
	int centerX, centerY;
	double cannonballX, cannonballY;
	double rad; // 마우스 현재 위치 각도

	public GamePanel() {
		setLayout(null);
		setBounds(10,10,500,500); //정사각형일 경우 오브젝트의 회전효과에 유리하다
		setBackground(Color.WHITE);
		setDoubleBuffered(true);
		
		centerX = getWidth()/2;
		centerY = getWidth()/2;
		
		createBarrel();
		createCircle();

		addMouseListener(new MouseAdapter() {
			@Override
			public void mouseReleased(MouseEvent e) {
			}
			
			@Override
			public void mousePressed(MouseEvent e) {
				Cannonball cb = null;
				for(int i=0;i<ballList.size();i++){
					if(!ballList.get(i).isRunning()){
						cb = ballList.get(i);
						break;
					}
				}
				if(cb==null) {
					cb = new Cannonball();
					ballList.add(cb);
					//System.out.println("포탄 새로 생성됨");
				}
				cb.setFireAngle(rad);
				//발사각도로부터 각 방향속도를 구한다
				cb.setxSpeed(Math.cos(rad));
				cb.setySpeed(Math.sin(rad));
				//발사방향의 포구에 포탄을 위치시킨다
				cb.setX(cb.getxSpeed()*100 + centerX-20);
				cb.setY(cb.getySpeed()*100 + centerY-20);
				cb.setRunning(true);
				//System.out.println("포탄갯수:"+ballList.size());
			}
			
			@Override
			public void mouseExited(MouseEvent e) {
			}
			
			@Override
			public void mouseEntered(MouseEvent e) {
			}
			
			@Override
			public void mouseClicked(MouseEvent e) {
			}
		});
		
		addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseMoved(MouseEvent e) {
				int mouseX = e.getX();
				int mouseY = e.getY();
				rad = Math.atan2(mouseY-centerY, mouseX-centerX);//중앙에서 마우스를 향한 각도
			}
			
			@Override
			public void mouseDragged(MouseEvent e) {
			}
		});
		
		gameLoop();
	}	//End of constructor
	
	private void createBarrel() {
		barrel = new BufferedImage(100, 40, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g2d = (Graphics2D)barrel.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setColor(Color.GRAY);
		g2d.fillRect(0,0,100,40);
	}
	
	private void createCircle() {
		circle = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g2d = (Graphics2D)circle.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setColor(Color.ORANGE);
		g2d.fillOval(0,0,100,100);
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D)g;

		Cannonball cb = null;
		for(int i=0;i<ballList.size();i++){
			cb = ballList.get(i);
			if(!cb.isRunning()) continue;
			g2d.drawImage(cb, (int)cb.getX(),  (int)cb.getY(), null);
		}
		AffineTransform old = g2d.getTransform();
		g2d.rotate(rad, centerX, centerY);
		g2d.drawImage(barrel, getWidth()/2,  getHeight()/2-20, null);
		g2d.setTransform(old);
		g2d.drawImage(circle, getWidth()/2-50,  getHeight()/2-50, null);
	}
	
	private void gameLoop() {
		new Thread() {
			@Override
			public void run() {
				while(true){
					for(int i=0;i<ballList.size();i++){
						Cannonball cb = null;
						cb = ballList.get(i);
						if(!cb.isRunning()) continue;
						cb.setX(cb.getX()+cb.getxSpeed()*3);
						cb.setY(cb.getY()+cb.getySpeed()*3);
						if(cb.getX() < 0 || cb.getX() > getWidth()-40) cb.setRunning(false);
						if(cb.getY() < 0 || cb.getY() > getHeight()-40) cb.setRunning(false);
					}
					repaint();
					try {
						Thread.sleep(30);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}// end of while
			}// end of run()
		}.start();
	}
}



Cannonball.java

package rotation;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

public class Cannonball extends BufferedImage
{
	private double fireAngle; //발사각도(라디안)
	private double x, y;
	private double xSpeed, ySpeed;
	private boolean isRunning;
	
	public Cannonball(){
		super(40,40,BufferedImage.TYPE_INT_ARGB);
		Graphics2D g2d = (Graphics2D) this.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setColor(Color.RED);
		g2d.fillOval(0,0,40,40);
	}

	public double getFireAngle() {
		return fireAngle;
	}

	public void setFireAngle(double fireAngle) {
		this.fireAngle = fireAngle;
	}

	public double getX() {
		return x;
	}

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

	public double getY() {
		return y;
	}

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

	public double getxSpeed() {
		return xSpeed;
	}

	public void setxSpeed(double xSpeed) {
		this.xSpeed = xSpeed;
	}

	public double getySpeed() {
		return ySpeed;
	}

	public void setySpeed(double ySpeed) {
		this.ySpeed = ySpeed;
	}

	public boolean isRunning() {
		return isRunning;
	}

	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}
}