자바 게임

폭풍저그머성찡 ㅣ 2023. 7. 14. 17:56

친구 숙제로 만들었는데 생각보다 잘 만든것 같아서 박제함

자바 첨해보는데 씨샾 2중대 같다.

//MainForm.java
package test;

import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

public class MainForm extends JFrame {	
	/// 사용할 이미지 로드 /////////////////////////////////////////////////////////////////////
	BufferedImage backimage1 = ImageIO.read(new File("src/image/image1.png"));//메인 패널 이미지 1
    BufferedImage backimage2 = ImageIO.read(new File("src/image/image2.png"));//메인 패널 이미지 2
    BufferedImage leftimage = ImageIO.read(new File("src/image/left.png"));// 왼쪽 화살표	
    BufferedImage upimage = ImageIO.read(new File("src/image/up.png"));// 위쪽 화살표
    BufferedImage rightimage = ImageIO.read(new File("src/image/right.png"));//오른쪽 화살표
    BufferedImage downimage = ImageIO.read(new File("src/image/down.png"));//아래쪽 화살표
    BufferedImage correctimage = ImageIO.read(new File("src/image/yourock.png"));//정답 이미지
    BufferedImage wrongimage = ImageIO.read(new File("src/image/yousuck.png"));//오답 이미지
    ////////////////////////////////////////////////////////////////////////////////////////
    
    
    /// 게임 처리에 사용할 변수 목록 //////////////////////////////////////////////////////////////
    static int Currentp[] = new int[4];//로드할 이미지 목록을 저장할 배열
    static int CurrentIndex = 0;//현재 몇번째 화살표를 맞추지 저장할 변수
    static int TotalScore = 0;//전체 점수
    static int timelimit = 30;//남은 시간
    static InfoPanel directionimage[] = new InfoPanel[4];//화살표 이미지를 출력할 JPanel 변형 클래스 배열
    static Timer timer = null;//매 초마다 남은 시간을 계산할 타이머
    private JLabel leftTimeLabel = new JLabel(String.format("You have %d seconds to play!! Press key to start!!", timelimit));// 게임 화면 상단에 표시할 남은 시간 및 점수용 JLabel
    ////////////////////////////////////////////////////////////////////////////////////////
    
    /// Event //////////////////////////////////////////////////////////////////////////////    
    
	public MainForm() throws Exception {
		setTitle("Rythme Game");//게임 제목 표시
		Container c = getContentPane();//JPanel들을 묶어서 출력하기 위한 컨테이너 선언
		setLayout(null);
		leftTimeLabel.setForeground(Color.RED);//게임 화면 상단 문자열 글자색 지정
		leftTimeLabel.setHorizontalAlignment(JLabel.CENTER);//게임 화면 상단 문자열 표시 위치
		leftTimeLabel.setFont(new Font("Verdana", Font.BOLD, 15));//게임 상단 화면 문자열 글씨체 및 글씨 크기
		ImagePanel background = new ImagePanel(backimage1, backimage2);//근육맨 이미지 2개가 번갈아 표시될 ImagePanel 클래스 객체 초기화
		background.setLocation(0, 0);//ImagePanel 위치 지정
		background.setPreferredSize(new Dimension(800, 500));//ImagepPanel 크기 지정
		background.setLayout(new FlowLayout());
		c.add(background);//컨테이너에 ImagePanel 추가 	    		
		background.add(leftTimeLabel);//ImagePanel 위에 점수 및 남은 시간을 표시
		for(int i=0;i<4;i++) {
			directionimage[i] = new InfoPanel(i);//각각의 화살표를 출력하기 위한 InfoPanel 객체 초기화
			directionimage[i].setLocation(i * 150 + 100, 550);//InfoPanel 위치 지정
			directionimage[i].setPreferredSize(new Dimension(100, 100));//InfoPanel 크기 지정
			directionimage[i].setBounds(i * 150 + 100, 550, 100, 100);//InfoPanel 크기 지정
			c.add(directionimage[i]);//컨테이너에 InfoPanel 추가
		}
		
		/// 키보드 이벤트 처리 //////////////////////////////////////////////////////////////
		addKeyListener(new KeyAdapter() {
    		public void keyPressed(KeyEvent e) {
    			if(timer.isRunning() == false) {// 게임 타이머가 시작되지 않은 경우, 
    				timer.start();//게임 타이머를 시작한다
    			}
    			leftTimeLabel.setText(String.format("Left Time : %d   Your Score : %d", timelimit, TotalScore));//새로운 키를 눌렀을 경우, 점수 문자열 초기화
    			System.out.println(e.getKeyCode());
    			if(Currentp[CurrentIndex] == e.getKeyCode()) {//정답 키를 입력한 경우
					directionimage[CurrentIndex].SetCorrect();//현재 InfoPanel에 정답 이미지를 출력하게 하고
					TotalScore += 10;//점수 추가
				}
    			else {//오답 키를 입력한 경우
    				directionimage[CurrentIndex].SetWrong();//현재 InfoPanel에 오답 이미지를 출력하게 하고 
    				TotalScore -= 5;//점수 제거
    			}
    			CurrentIndex++;//다음 입력은 다음 InfoPanel이 받을 수 있도록 CurrentIndex + 1
    			if(CurrentIndex == 4) {//만약 현재 이미지가 마지막 이미지 였을 경우
    				new Thread() {
    					@Override
    					public void run() {
    						try {
								sleep(150);//150ms 대기 후 ( 바로 넘어갈 경우, 마지막 이미지의 정답 여부를 볼 수 없음 )
							} catch (InterruptedException e) { 
								e.printStackTrace();
							}
    						CurrentIndex = 0;//CurrentIndex 초기화하고
    						resetDirectionPanel();//새로운 화살표 배당받기
    					}    					
    				}.start();//별도의 쓰레드에서 실행하는 이유는 UI 쓰레드에서 Thread.sleep()을 실행할 경우, UI 쓰레드의 작동자체가 멈추기 때문에 이미지가 바뀌지 않는다. ( 이 부분은 window programming 관련 지식이 필요하므로, 그냥 대충 스킵하는게 좋을 것 같음. 필요 시 문의 )
    			}    		
    		}
    	});		
		/////////////////////////////////////////////////////////////////////////////////////
		
		
		/// 타이머 초기화 //////////////////////////////////////////////////////////////////////	
		timer = new Timer (1000, new ActionListener() {// 1000ms (1초) 마다 동작하는 타이머 초기화
    		public void actionPerformed(ActionEvent e) {
    			timelimit--;//남은 시간 - 1
    			leftTimeLabel.setText(String.format("Left Time : %d   Your Score : %d", timelimit, TotalScore));//점수 및 잔여 시간 문자열 출력
    			if(timelimit == 0) {//게임이 끝난 경우
    				JOptionPane.showMessageDialog(null, String.format("your score : %d!!", TotalScore), "GAME OVER!!", JOptionPane.OK_OPTION);//점수를 알려주는 메세지 박스 출력
    				TotalScore = 0;//점수 초기화
    				timelimit = 30;//잔여시간 초기화
    				leftTimeLabel.setText(String.format("Left Time : %d   Your Score : %d", timelimit, TotalScore));//점수 및 잔여 시간 문자열 초기화
    				timer.stop();//게임 타이머 중지. 다음 키보드 입력 시 새로운 게임 시작
    				resetDirectionPanel();//새로운 화살표 할당
    			}
    		}
    	});
		/////////////////////////////////////////////////////////////////////////////////////
				
		
		setSize(800,700);//창 전체 사이즈 지정
		setPreferredSize(new Dimension(800, 700));//창 전체 사이즈 지정
		setLocationByPlatform(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);		
		pack();		
	    setVisible(true);
	}
	
	/// 메인 함수 ////////////////////////////////////////////////////////////////////////
	public static void main(String[] args) {		
		try {			
			MainForm handle = new MainForm();
			resetDirectionPanel();
		} catch (Exception e) { 
			e.printStackTrace();
		}
	}
	////////////////////////////////////////////////////////////////////////////////////
	
	
	/// 새로운 화살표 할당 함수 /////////////////////////////////////////////////////////////
	public static void resetDirectionPanel() {
		Random random = new Random();
		random.setSeed(System.currentTimeMillis());//현재 시간 (ms)를 랜덤 시드로 설정
		for(int i=0;i<4;i++) {
			Currentp[i] = random.nextInt(4) + 0x25;	// 화살표 키 KeyCode에 해당하는 값 ( 0x25~0x28 ) 을 배열에 무작위로 저장
			directionimage[i].SetState();//화살표 이미지 초기화
		}
	}
	////////////////////////////////////////////////////////////////////////////////////
	
	
	/// 화살표 이미지 출력 클래스 ////////////////////////////////////////////////////////////
	class InfoPanel extends JPanel {
		private int index = -1;//현재 화살표 이미지가 몇번째 화살표 이미지인지 저장
		private Image image = null;//이미지 변수
		public InfoPanel(int idx) {
			index = idx;			
			image = correctimage;
			repaint(0, 0, 100, 100);
		}
		
		// 현재 이미지를 정답 이미지로 설정
		public void SetCorrect() {
			image = correctimage;
			repaint(0, 0, 100, 100);
		}
		
		// 현재 이미지를 오답 이미지로 설정
		public void SetWrong() {
			image = wrongimage;
			repaint(0, 0, 100, 100);
		}
		
		// 현재 이미지를 화살표 이미지로 설정
		public void SetState() {
			int s = Currentp[index];
			switch(s) {
			case 0x25:
				image = leftimage;
				break;
			case 0x26:
				image = upimage;
				break;
			case 0x27:
				image = rightimage;
				break;				
			case 0x28:
				image = downimage;
				break;
			}
			repaint(0, 0, 100, 100);
		}
		
		@Override
	    protected void paintComponent(Graphics g) {//이미지 초기화 함수 오버라이드
	        super.paintComponent(g);
	        g.drawImage(image, 0, 0, 100, 100, this);
	    }
	}
	//////////////////////////////////////////////////////////////////////////////////
	
	
	/// 근육맨 이미지를 표시할 JPanel 클래스 /////////////////////////////////////////////////////////
	class ImagePanel extends JPanel {
	    private Image pimage1 = null, pimage2 = null, image;//image : 실제 표시할 이미지  pimage1,2 : 표시할 1번 2번 이미지를 미리 클래스 안에 저장해둠
	    private int currentp = 1;//1번째 이미지, 2번째 이미지 중 뭘 표시할 건지 결정하는 변수
	    private int height = 500, width = 800;//이미지 크기 지정
	    Timer timer = null;//이미지가 1초마다 바뀔 수 있도록 타이머 선언
	    public ImagePanel(Image image1, Image image2) {        
	    	this.image = image1;
	    	this.pimage1 = image1;
	    	this.pimage2 = image2;        
	    	
	    	/// 이미지 변경 타이머 /////////////////////////////////////////////////////////
	    	timer = new Timer (1000, new ActionListener() {//1초마다 실행되는 타이머 선언
	    		public void actionPerformed(ActionEvent e) {
	    			if(currentp == 1) {
	    				image = pimage1;
	    			}
	    			else {
	    				image = pimage2;
	    			}		
	    			currentp = 1 - currentp;//currentp 가 1인 경우 0이되고 0인 경우 1이 되는 로직
	    			repaint(0, 0, width, height);// 이미지 초기화
	    		}
	    	}); 	    	 
	    	////////////////////////////////////////////////////////////////////////////
	    	
	    	timer.start();	    	
	    	setSize(800, 500);
	    }          
	    
	    @Override
	    protected void paintComponent(Graphics g) {//이미지 변경 함수 오버라이드
	        super.paintComponent(g);
	        g.drawImage(image, 0, 0, width, height, this);
	    }
	}	
	///////////////////////////////////////////////////////////////////////////////////////////
}

 

황철순 키우기 (리겜)