티스토리 뷰
계획없이 만들다보니. 코드를 막짠곳이 몇몇 보인다.
아무튼.
코드 설명은 주석을 달았다.
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 |
댓글