티스토리 뷰

내맘대로 게임(Java)

CardGame(완성.)

전광영 2014. 8. 19. 01:34

계획없이 만들다보니. 코드를 막짠곳이 몇몇 보인다.

아무튼.

코드 설명은 주석을 달았다.


 card_back : 카드의 뒷면 이미지

img_1~5 :카드의 앞면이미지 (10개니까 2쌍 5개)\

intro_image : 게임 인트로화면 배경이미지

Card.java

import java.awt.Image;
import java.awt.Toolkit;
public class Card {
	final static int WIDTH = 100; //카드의 가로
	final static int HEIGHT = 150;  //카드의 세로
	int x,y;                       //카드의 x,y 위치
	int state= 0;          //현재 카드의 상태 (뒷면,앞면,카드완성)
	private Image backImg = Toolkit.getDefaultToolkit().createImage("card_back.png");
	private Image frontImg = null;
	int key;
	
	public Card(Image img,int key){     //생성자로 앞면 이미지와 키를 받음
		this.key = key;
		frontImg = img;
	}
	//마우스 클릭한 곳의 x,y 좌표가 클릭 되어있는지 확인
	public boolean isClicked(int x_pos,int y_pos){
		if((x_pos < this.x+WIDTH && x_pos > this.x)
				&&(y_pos < this.y+HEIGHT && y_pos > this.y)	) 
			return true;
		else 
			return false;
	}
	public Image getImage(){
		Image img = null;
		//state가 0이면 카드의 뒷이미지 아니면 카드의 앞이미지 
		img = state == 0 ? this.backImg : this.frontImg;
		return img;
	}
	//완료된 카드가 아니면 카드를 뒤집는다
	public void backCard(){
		if(this.state != 3)
			state= 0;
	}
	public void setPos(int x,int y){
		this.x = x;
		this.y = y;
	}

}


CardCheckThread.java

//1초의 딜레이를 이용하여 카드가 일치하는지 확인
public class CardCheckThread extends Thread{
	GameMouseEvent gameEvent; //마우스 리스너 객체를 가져옴
	viewController controller;
	Card[] cards;
	int index1,index2;
	public CardCheckThread(GameMouseEvent gameEvent,int index1,int index2) {
		//객체를 이용하여 controller 객체와 cards의 참조값을 대입한다.
		this.gameEvent = gameEvent;
		this.controller = gameEvent.controller;
		this.cards = gameEvent.cards;
		this.index1 = index1;
		this.index2 =index2;
	}
	@Override
	public void run() {
		try {
			Thread.sleep(1000); //1초 딜레이
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(cards[index1].key == cards[index2].key){ //뒤집은 카드의 key가 일치한다면 상태 변환
			cards[index1].state = 3;
			cards[index2].state = 3;
			gameEvent.count++;
		}else{ //카드의 key가 일치하지 않는다면 둘의 카드를 다시 뒤집는다.
			cards[index1].backCard();
			cards[index2].backCard();
		}
		gameEvent.gameState = 0; //첫번째 카드를 받을 준비한다.
		gameEvent.GameEnd(); //게임끝났는지 확인.
		controller.gameRepaint();
	}

}


GameMouseEvent.java

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class GameMouseEvent implements MouseListener{
	viewController controller; //뷰 컨트롤러
	Card[] cards;              //카드 배열
	int gameState = 0;        //게임상태 0=첫번째 카드 받을수 있음,1 두번째카드 받을수 있음
	int[] buffer = new int[2]; //클릭한 카드의 인덱스임시저장을 위해
	int count = 0;
	public GameMouseEvent(viewController controller) { //컨트롤러 객체를 파라미터로 받음
		this.controller = controller; 
		cards = controller.gamePanel.cards; 
	}
	@Override
	public void mouseClicked(MouseEvent e) {
	}
	@Override
	public void mouseEntered(MouseEvent e) {
	}
	@Override
	public void mouseExited(MouseEvent e) {
	}
	@Override
	public void mousePressed(MouseEvent e) {
		switch(gameState){ //게임상태에따라 처리가 달라짐
		case 0:             //첫번째 카드를 받을준비가 된경우
			for(int i = 0 ; i < 10 ;i++){ //클릭한 좌표가 0~9까지의 카드중 어느것을 클릭했는지
				if(cards[i].isClicked(e.getX(),e.getY()) 
						&& cards[i].state ==0){ //해당카드가 클릭되면 i가 그카드인덱스 값이 된다. state =0 즉. 뒤집힌 상태
					cards[i].state =1;        //state로 1로 바꾸어 이미지를 바꿈
					gameState++;              //game상태를 올려서 두번째카드를 받을준비
					buffer[0] = i;            //버퍼에 해당 뒤집은 카드의 인덱스를 저장
				}
			}
			break;
		case 1:                          //두번째카드를 받을준비가 된상태
			for(int i = 0 ; i < 10 ;i++){ //클릭한 좌표가 0~9까지의 카드중 어느것을 클릭했는지
				if(cards[i].isClicked(e.getX(),e.getY())
						&& cards[i].state ==0){
					cards[i].state =1;      //state로 1로 바꾸어 이미지를 바꿈   
					buffer[1] = i;			//버퍼에 해당 뒤집은 카드의 인덱스를 저장
					gameState++;			 //game상태를 올려서 결과를 기다리는 상태로 변함
					/*의문점. 카드의 상태를 바꾸고 repaint()한후에 바로 sleep()을 주면. 
					 * repaint()메소드가 먹히질 않음...
					 * 그래서 새로운 쓰레드 생성하여를 이용하여 다뤘음.
					 * 이것 때문에 코드가 더 복잡해짐.
					 * java awt에 대한 지식이 필요.(생명주기 같은..)
					 */
					new CardCheckThread(this, buffer[0], buffer[1]).start();
				}
			}
			break;
		}
		controller.gameRepaint();//카드화면 repaint();
	}
	@Override
	public void mouseReleased(MouseEvent e) {
	}	
	public void GameEnd(){
		if(count == 5){
			System.exit(0);
		}
	}
}


GamePanel.java

import java.awt.Graphics;
import java.awt.Label;
import java.awt.Toolkit;
import java.util.Date;
import java.util.Random;

import javax.swing.JPanel;

public class GamePanel extends JPanel{
	//카드의 위치정보를 가진 상수 배열[x,y][순서]
	final static int[][] CARD_POS ={
		{50, 150,250,350,450,50, 150,250,350,450},
		{20, 190, 20,190, 20,190, 20,190,20,190}};
	//카드의 이름을 가진 상수배열
	final static String[] CARD_IMG_NAME ={
		"img_1.png","img_2.png","img_3.png","img_4.png","img_5.png"
	};
	int shuffleList[] = new int[10];  //카드의 위치를 바꿀 셔플리스트 
	Card cards[] = new Card[10];      //카드의 배열
	Random rnd = new Random(new Date().getTime()); //랜덤을 위함. 시드값으로 현재 시간정보를 넘겨서 
	Toolkit toolkit = Toolkit.getDefaultToolkit(); //이미지 생성을 위함
	
	//생성자
	public GamePanel() {
		init();
		shuffle();
	}
	//카드10개 객체를 마듬
	private void init(){
		for(int i = 0 ; i < 10 ;i++){
			//생성자로 이미지와 key 넘겨줌
			// i% 5함으로써 0번 인덱스 카드와 5번 인덱스 카드는 같은 이미지와 키를 가진다.
			cards[i] = new Card(toolkit.createImage(CARD_IMG_NAME[i % 5]),i % 5);
		}
	}
	//셔플리스트의 값을 하나씩 채워나감. 중복되지 않는 배열을 이용
	private void shuffle(){
		//처음사이즈가 1
		int size = 1;
		int tmpNo=0;  //임시변수
		shuffleList[0] = rnd.nextInt(10); //첫번째에 값을 넣어줌
		label1 :
			while(true){  //모든값들이 완성될때까지 반복(0~9까지 값을 채움)
			if(size == 10) //만약 값들이 다 채워졌다면 break를 이용하여 while루프를 나옴
				break;
			tmpNo = rnd.nextInt(10); //램덤값 생성
			for(int i= 0 ; i < size;i++){ //사이즈를 이요하여 지금껏 찬 값들과 비교
				if(tmpNo == shuffleList[i]) //새로만든 랜덤값이 기존에 배열에 있다면 
					continue label1;       //continue를 이용하여 반복한다
			}
			shuffleList[size] = tmpNo;	  //생성된 랜덤값이 List에 존재하지 않다면 값을 집어넣음
			size++;                      //이후 사이즈 증가
		}
		//for문을 이용하여 모든 카드들에게 값을 좌표를 넣어줌 이때 shuffleList 사용
		for(int i = 0 ; i < 10; i++)
			cards[i].setPos(CARD_POS[0][shuffleList[i]],CARD_POS[1][shuffleList[i]]);
		/*shuffleList를 이용하여 card의 x좌표값을 넣어준다.
			이때 카드 위치 정보를 가진 CARD_POS 상수의 index값을 랜덤으로 하여
			카드의 위치를 바꿀수 있다.
		*/
	}
	@Override
	public void paint(Graphics g) {
		g.clearRect(0,0,MainFrame.FRAME_WIDTH, MainFrame.FRAME_HEIGHT);
		//카드를 뿌려줌.
		for(int i = 0 ; i < 10 ; i++){
			g.drawImage(cards[i].getImage(), cards[i].x, cards[i].y,
					Card.WIDTH, Card.HEIGHT, this);
		}
	}

}


IntroKeyEvent.java

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;


public class IntroKeyEvent implements KeyListener{
	IntroPanel introPanel; //패널을 생성자로 받음.
	public IntroKeyEvent(IntroPanel introPanel) {
		this.introPanel = introPanel;
	}
	@Override
	public void keyPressed(KeyEvent e) {
		//키값이 40 즉,방향키 위쪽 이면
		if(e.getKeyCode() == 38){
			introPanel.select =0;
		//키값이 38 즉,방향키 아래쪽 이면
		}else if(e.getKeyCode() ==40){
			introPanel.select= 1;
		}else if(e.getKeyCode() ==10){//엔터 키
			//select =1 즉 화살표가 gameStart옆에 위치해있을때
			//엔터를 누를경우에 게임시작
			if(introPanel.select == 0) 
				introPanel.gameStart();
			else if(introPanel.select ==1)
				System.exit(0);
		}
		//패널을 다시 그려준다.
		introPanel.repaint();
	}
	@Override
	public void keyReleased(KeyEvent e) {
	}
	@Override
	public void keyTyped(KeyEvent e) {
	}

}


IntroPanel.java

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.*;

//Panel단위로 화면이동을 하기위해 각화면은 Panel을 
//상속받아 클래스를 작성한다
public class IntroPanel extends JPanel{
	int select =0;
	Image intro_image;
	viewController controller;
	public IntroPanel(viewController controller) {
		this.controller = controller;
		//기본툴킷 객체로부터 getImage메소드를 활용하여 이미지를 불러온다.
		intro_image = Toolkit.getDefaultToolkit().getImage("intro_image.jpg");
		this.addKeyListener(new IntroKeyEvent(this));
	}	
	//패널의 paint 메소드를 오버라이드 하여 그려줌
	//메소드가 실행될때 Graphics타입의 g를 인자로 받는다
	//g를 이용하여 패널에 그려준다.
	@Override
	public void paint(Graphics g) {
		//이미지를 그려준다. 이미지객체,시작x,시작y,가로,세로,보여줄 옵저버;
		g.drawImage(intro_image,0,0,getWidth(),getHeight(),this);
		//g객체에 폰트스타일을 바꾸어준다. 이코드에서는 굵은글씨에 30포인트
		g.setFont(new Font("myFont",Font.BOLD ,30));
		//폰트셋을 빨강으로 변경
		g.setColor(Color.red);
		//문자열 삽입!!
		g.drawString("카드 게임", 120, 100);
		//폰트변경후 문자열 삽입.
		g.setFont(new Font("secondFont",Font.ITALIC,20));
		g.setColor(Color.black);
		g.drawString("GameStart",130,250);
		g.drawString("Quit",130,300);
		//기본값 게임시작바로 옆에 화살표를 위치시킨다
		if(select ==0)
			g.drawString("→", 100, 250);
		else //아닐경우
			g.drawString("→", 100, 300);
	}
	public void gameStart(){
		controller.showGamePanel();
	}
}


MainFrame.java

import java.awt.Dimension;
import java.awt.Point;

import javax.swing.JFrame;

public class MainFrame extends JFrame{
	final static int FRAME_WIDTH = 600;
	final static int FRAME_HEIGHT = 500;
	viewController controller;
	//생성자로 프레임의 이름을 받아 그대로 부모클래스로 전달해준다.
	//super() <- 부모클래스의 생성자를 호출하는 것 
	public MainFrame(String title) {
		super(title);
		//윈도우상의 창의 위치를 잡아준다.
		this.setLocation(new Point(200,250));
		//프레임을 보여준다. default = false
		this.setVisible(true);
		//프레임의 창크기를 설정한다.
		this.setPreferredSize(new Dimension(FRAME_WIDTH,FRAME_HEIGHT));
		//컴포넌트 크기만큼 창의 크기를 잡아준다.
		this.pack();
		//프레임창을 닫을 경우 프로세스를 종료하기 위해 사용해야한다. 
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//뷰컨트롤러 등록
		controller = new viewController(this);
	
	}
	//매인클래스.
	public static void main(String args[]){
		//창을 띄우려면 메모리를 잡아야 하므로 자기자신클래스를 생성
		MainFrame mainFrame = new MainFrame("게임");
	}

}


viewController.java

import java.awt.Container;
public class viewController {
	MainFrame mainFrame;  //매인프레임 생성자로 받을예상
	Container contentPane; //contentPane
	IntroPanel introPanel; //시작 패널
	GamePanel gamePanel;   //게임 패널.
	public viewController(MainFrame mainFrame) {
		this.mainFrame = mainFrame; //생성자로 매인프레임을 받는다
		init();
	}
	private void init(){
		introPanel = new IntroPanel(this); //시작패널 생성
		contentPane = mainFrame.getContentPane(); //매인프레임으로부터 컨텐트페인을 가져온다
		contentPane.add(introPanel); //컨텐트패인에 시작패널 추가
		try{
			Thread.sleep(100);
		}catch(InterruptedException ie){
			System.out.println(ie.getMessage());
		}
		introPanel.requestFocus();   //키이벤트를 받기위해 패널을 포커싱해준다.(패널에 이벤트가 달려있기때문에)
	}
	public void showGamePanel(){
		contentPane.remove(introPanel);  //인트로 패널을 삭제
		
		gamePanel = new GamePanel();
		gamePanel.addMouseListener(new GameMouseEvent(this));
		contentPane.add(gamePanel);  //게임을 실행할 패널을 추가
		
		/* setVisible을 끄고 켜야 패널이 교체되어있다 이유는 모름.. */
		mainFrame.setVisible(false);    
		mainFrame.setVisible(true);		
	}
	public void gameRepaint(){
		gamePanel.repaint();
	}
}



'내맘대로 게임(Java)' 카테고리의 다른 글

Java로 만들어본 CardGame(4)  (0) 2014.07.22
Java로 만들어본 CardGame(3)  (0) 2014.07.21
Java로 만들어본 CardGame(2)  (0) 2014.07.20
Java로 만들어본 CardGame(1)  (0) 2014.07.20
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함