연습으로 만든 프로그램이라 이미지들은 여기저기 퍼와서 사용했기 때문에 저작권 문제가 걸린다.
따라서 배포는 불가능하고, 자바 스윙을 공부하는 사람들을 위해 코드라도 공유하고자 이렇게 글을 올린다.
최대한 주석을 달아가면서 다른 사람도 알아보기 쉽도록 코딩했으니, 혹시라도 참고하고자 하는 사람이 있다면 조금이나마 도움이 될 것이라 생각한다.
이미지 경로만 바꿔서 내용을 좀 수정하고 다듬으면 충분히 다른 프로그램을 만드는 데에 응용할 수 있을 것이다.
참고로.. 디자인 보완, 충돌 테스트에서의 좀더 세밀한 좌표 계산, 부가적인 기능 추가 등의 업그레이드가 절실히 필요하지만... '절대 시간'이 부족한 관계로 모두 구현하지 못했다.
위에서 음식들이 랜덤속도로 내려오고, 아래에서 밥돌이가 좌우로 움직이며 메뉴를 받는 형태다.
클래스는 총 4개로 만들었다.
아무쪼록 도움이 되는 사람이 있기를...
▼ Main클래스
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
public class Main extends JFrame {
private JPanel contentPane;
public JPanel panel;
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
// JPanel panel을 contentPane에 추가 - 모든 이미지가 나타날 곳
panel = new JPanel();
panel.setBackground(new Color(240, 255, 240));
setBounds(100, 50, 900, 700);
setContentPane(panel);
setResizable(false);
panel.setLayout(null);
/* Image image = Toolkit.getDefaultToolkit().getImage("D:/prg/meal/title.gif");
ImageIcon imageIcon = new ImageIcon(image);
JLabel titleLabel = new JLabel(imageIcon);
panel.add(titleLabel);*/
setVisible(true);
// 주인공 라벨을 생성해서 JPanel panel에 추가
// 패널의 크기 값을 Hero클래스에 불러오기 위해 setVisible 이후에 추가해야 한다!!!
Hero hero = new Hero(this);
// repaint를 반드시 해줄 것!!!
this.repaint();
// 주인공 쓰레드 작동
Thread th = new Thread(hero);
th.start();
// Menu클래스의 객체 생성.
Menu menu = new Menu(panel);
// repaint를 반드시 해줄 것!!!
this.repaint();
// contentPane.add(menu, BorderLayout.CENTER);
// Food 쓰레드 작동
Thread th1 = new Thread(menu);
th1.start();
}
public static void main(String[] args) {
Main frame = new Main();
}
▼ 밥돌이 클래스
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Hero extends JLabel implements Runnable{
private JPanel panel;
private Image img;
private static JLabel riceLabel;
JFrame frame;
// Menu클래스에 riceLabel을 넘겨주기 위해 이 함수를 만들어 준다
public static JLabel getRiceLabel(){
return riceLabel;
}
public Hero(JFrame main) { // contentPane의 정보를 Main 클래스로부터 받아옴
frame = main;
this.panel = ((Main)main).panel;
// 주인공 이미지 불러옴
img = Toolkit.getDefaultToolkit().getImage("D:/prg/meal/riceman.gif");
// 주인공 이미지를 ImageIcon 클래스를 이용해 ImageIcon타입으로 받음
ImageIcon imageIcon = new ImageIcon(img);
// ImageIcon타입의 주인공 이미지를 JLabel에 삽입
riceLabel = new JLabel(imageIcon);
// 주인공의 시작 위치와 크기 설정
riceLabel.setLocation((int)panel.getSize().getWidth()/2-10, (int)panel.getSize().getHeight()-110);
riceLabel.setSize(100, 100);
panel.updateUI();
// 주인공 라벨을 panel에 추가
panel.add(riceLabel);
// updateUI를 반드시 해줄 것!!!
panel.updateUI();
// g.drawImage(jLabel, (int)riceManStartX, (int)riceManStartY, contentPane)
}
@Override
public void run() {
// 좌우로 움직일 픽셀 값
int speedX = 2;
while (true) {
try {
Thread.sleep(6);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// content패널의 가로 크기
double contentWidth = panel.getSize().getWidth();
// 주인공 라벨의 너비
int riceLabelWidth = riceLabel.getWidth();
// 주인공 라벨의 X좌표
double riceLabelX = riceLabel.getLocation().getX();
// 주인공 라벨의 움직인 X좌표
double riceLabelMovedX = riceLabelX + speedX;
boolean test1 = speedX > 0 && (riceLabelMovedX + riceLabelWidth) > contentWidth; // x경계의 오른쪽 끝
boolean test2 = speedX < 0 && riceLabelMovedX < 0; // x경계의 왼쪽 끝
if (test1 || test2) {
speedX = speedX * (-1); // 방향을 바꿔라
riceLabelMovedX = riceLabelX + speedX; // 옮길 위치
}
riceLabel.setLocation((int)riceLabelMovedX, (int)riceLabel.getLocation().getY());
if(Menu.check){break;}
}
}
▼ 음식 메뉴 클래스
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Menu implements Runnable{
private JPanel panel;
private JLabel[] foodLabel;
private String[] foods;
static boolean check;
private String[] foodName;
private String whatFood;
// JPanel panel의 정보를 Main클래스에서 가져옴.
public Menu(JPanel panel){
this.panel = panel;
// ArrayList로 이미지의 주소값을 넣어줌
List list = new ArrayList();
list.add("D:/prg/meal/food/baekban.png");
list.add("D:/prg/meal/food/bread.png");
list.add("D:/prg/meal/food/care.png");
list.add("D:/prg/meal/food/chicken.png");
list.add("D:/prg/meal/food/dakdori.png");
list.add("D:/prg/meal/food/ddugbboggi.png");
list.add("D:/prg/meal/food/donggas.png");
list.add("D:/prg/meal/food/dubujungol.png");
list.add("D:/prg/meal/food/fish.png");
list.add("D:/prg/meal/food/gimbab.png");
list.add("D:/prg/meal/food/hambuger.png");
list.add("D:/prg/meal/food/jjajang.png");
list.add("D:/prg/meal/food/jjigae.png");
list.add("D:/prg/meal/food/jook.png");
list.add("D:/prg/meal/food/mandu.png");
list.add("D:/prg/meal/food/naengmyun.png");
list.add("D:/prg/meal/food/pizza.png");
list.add("D:/prg/meal/food/samgyetang.png");
list.add("D:/prg/meal/food/sandwich.png");
list.add("D:/prg/meal/food/shabshab.png");
list.add("D:/prg/meal/food/soju.png");
list.add("D:/prg/meal/food/soondae.png");
list.add("D:/prg/meal/food/susi.png");
// foodLabel 생성
foodLabel = new JLabel[list.size()];
foodName = new String[] {"백반","빵","카레","치킨","닭볶음탕","떡복이","돈까스","두부전골"
,"생선구이","김밥","햄버거","짜장면","김치찌개","죽","만두"
,"냉면","피자","삼계탕","샌드위치","샤브샤브","소주 한잔","순대"
,"초밥"};
// food 이미지 불러옴
for (int i = 0; i < list.size(); i++) {
Image foodImg = Toolkit.getDefaultToolkit().getImage(list.get(i));
// food 이미지를 ImageIcon 클래스를 이용해 ImageIcon타입으로 받음
ImageIcon imageIcon = new ImageIcon(foodImg);
foodLabel[i] = new JLabel(imageIcon);
// panel의 가로 크기
double panelWidth = panel.getSize().getWidth();
// foodLabel의 X값을 랜덤으로 해주기 위해 이렇게 해놓자
int randomX = (int)(Math.random()*(panelWidth-100));
// foodLabel의 처음 위치와 크기를 설정
foodLabel[i].setLocation(randomX, (int)panel.getY()+30);
// foodLabel[i].setLocation(30+foodLabel[i].getX(), (int)panel.getY()+30);
foodLabel[i].setSize(155, 100);
// food 라벨을 Menu 패널에 추가
panel.add(foodLabel[i]);
// updateUI를 반드시 해줄 것!!!
// panel.updateUI();
}
}
@Override
public void run() {
while(true){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* // panel의 X, Y좌표
double panelX = panel.getLocation().getX();
double panelY = panel.getLocation().getY();
// panel의 너비
double panelWidth = panel.getSize().getWidth();
*/
for (int i = 0; i < foodLabel.length; i++) {
// 아래로 움직일 픽셀 값, for문 안에 넣어줘야 각각의 foodLabel들이 다른 픽셀 값으로 움직인다.
double speedY = Math.random()*30;
// foodLabel의 X, Y좌표
double foodLabelX = foodLabel[i].getLocation().getX();
double foodLabelY = foodLabel[i].getLocation().getY();
foodLabel[i].setLocation((int)foodLabelX, (int)(foodLabelY + speedY));
check = kissCheck(foodLabel[i]);
if(check){
whatFood = foodName[i];
// System.out.println(whatFood);
break;}
}
if (check) {
// 종료 후, 다이얼로그 결과창 생성
Result result = new Result(whatFood);
break;
}
}
}
public boolean kissCheck(JLabel food){
// Hero클래스에 있는 riceLabel을 받아온다.
// Hero hero = new Hero(panel);
JLabel riceLabel = Hero.getRiceLabel();
// foodLabel과 riceLabel이 충돌했을 때 멈추도록 해주기 위한 구간
Polygon polygon = new Polygon();
// kiss하는 지점을 좀더 가깝게 해주려고 +, -를 해줬다.
int riceLabelX = riceLabel.getX()+30;
int riceLabelY = riceLabel.getY()+30;
int riceLabelWidth = riceLabel.getWidth()-50;
int riceLabelHeight = riceLabel.getHeight()-50;
int[] xPoints = { riceLabelX, (riceLabelX + riceLabelWidth),
(riceLabelX + riceLabelWidth), riceLabelX };
int[] yPoints = { riceLabelY, riceLabelY,
(riceLabelY + riceLabelHeight), (riceLabelY + riceLabelHeight) };
polygon = new Polygon(xPoints, yPoints, 4);
if (polygon.intersects((double) food.getX(), (double) food.getY(),
(double) food.getWidth(), (double) food.getHeight())) {
// static변수 boolean을 이용해서 foodLabel의 움직임과 riceLabel의 움직임을 동시에 제어해주자.
// true가 되면 break;하도록.
return true;
}else{
return false;
}
}
▼ 결과창 클래스
import java.awt.Color;
import java.awt.Container;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Result extends JDialog{
JLabel resultTextLabel = new JLabel();
private String whatFood;
public Result(String whatFood) { //
this.whatFood = whatFood;
// EXIT_ON_CLOSE로 설정해줄 경우 다이얼로그 창이 뜨지 않는다. 주의할 것!
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
resultTextLabel.setText(" 오늘은 " + whatFood + " 먹는 날!");
this.setBackground(new Color(240, 255, 240));
add(resultTextLabel);
setSize(200, 100);
setLocation(450,350);
setVisible(true);
}