공부한것들을 정리하는 블로그 입니다.
타자 게임(스레드&이벤트핸들러) 본문
반응형
타자 게임(스레드&이벤트핸들러)
Frame, AWT, 멤버변수 선언 등
import java.util.*; import java.awt.*; import java.awt.event.*; /* * 해석 : hodu */ class 타자게임2 extends Frame { // final을 사용한 것은, // 팔드에 저장된 초기값을 프로그램 실행 도중에 수정하지 못하게 하기위함 final int FRAME_WIDTH = 400; final int FRAME_HEIGHT = 300; final int SCREEN_WIDTH; final int SCREEN_HEIGHT; int speed = 700; // 단어가 떨어지는 속도... 높을 수록 느리다. int interval = 2 * 1000; // 새로운 단어가 나오는 간격 int score = 0; int life = 3; int curLevel = 0; final int MAX_LEVEL; boolean isPlaying = false; // WordGenerator는 일정시간(interval)간격으로 // data배열의 한 요소를 골라서 // words(Vector인스턴스)에 저장하는 일을 수행한다 WordGenerator wg = null; // 단어를 생성하는 쓰레드 // WordDropper는 WordGenerator와 같은 쓰레드로 // 모든 단어의 시간을 10부터 0까지 1초에 1씩 감소시키는 일을 한다 WordDropper wm = null; // 단어를 떨어뜨리는 쓰레드 FontMetrics fm; // 화면에서의 글자 길이를 구하는데 사용 ThreadGroup virusGrp = new ThreadGroup("virus"); // 바이러스 쓰레드들의 그룹 String[][] data = { { "개과천선", "견물생심", "결초보은", "경거망동", "경국지색", "고진감래", "과유불급", "구사일생", "권모술수", "백년대계", "백전백승", "사면초가" }, { "개과천선", "견물생심", "결초보은", "경거망동", "경국지색", "고진감래", "과유불급", "구사일생", "권모술수", "백년대계", "백전백승", "사면초가" }, { "개과천선", "견물생심", "결초보은", "경거망동", "경국지색", "고진감래", "과유불급", "구사일생", "권모술수", "백년대계", "백전백승", "사면초가" }, { "개과천선", "견물생심", "결초보은", "경거망동", "경국지색", "고진감래", "과유불급", "구사일생", "권모술수", "백년대계", "백전백승", "사면초가" }, }; // Level(int speed, int interval, int levelUpScore, String[] data) final Level[] LEVEL = { new Level(500, 2000, 1000, data[0]), new Level(250, 1500, 2000, data[1]), new Level(120, 1000, 3000, data[2]), new Level(100, 500, 4000, data[3]), }; Vector words = new Vector(); TextField tf = new TextField(); Panel pScore = new Panel(new GridLayout(1, 3)); Label lbLevel = new Label("Level:" + curLevel, Label.CENTER); Label lbScore = new Label("Score:" + score, Label.CENTER); Label lbLife = new Label("Life:" + life, Label.CENTER); MyCanvas screen = new MyCanvas(); 타자게임2() { this("Typing game ver1.0"); } 타자게임2(String title) { super(title); pScore.setBackground(Color.YELLOW); pScore.add(lbLevel); pScore.add(lbScore); pScore.add(lbLife); add(pScore, "North"); add(screen, "Center"); add(tf, "South"); MyEventHandler handler = new MyEventHandler(); addWindowListener(handler); tf.addActionListener(handler); setBounds(500, 200, FRAME_WIDTH, FRAME_HEIGHT); // 패널의 크기 및 위치 지정 (x,y로 부터 넓이(width, 높이(height)) setResizable(false); // 크기조절 불가능 setVisible(true); // 프레임을 보여줌 SCREEN_WIDTH = screen.getWidth(); SCREEN_HEIGHT = screen.getHeight(); MAX_LEVEL = LEVEL.length - 1; // LEVEL.length로 LEVEL배열의 길이를 구한다 // 문자열의 길이를 부를때는 변수명.length()이고 배열의 길이를 구할때는 배열명.length이다. fm = getFontMetrics(getFont()); } public void repaint() { super.repaint(); screen.repaint(); } public void delay(int millis) { try { Thread.sleep(millis); } catch (Exception e) { } } // 게임이 시작됨 public void start() { showLevel(0); // Level을 정의하고 title에 출력 isPlaying = true; // isPlaying은 life와 wg = new WordGenerator(); wg.start(); wm = new WordDropper(); wm.start(); } public Level getLevel(int level) { if (level > MAX_LEVEL) level = MAX_LEVEL; if (level < 0) level = 0; return LEVEL[level]; } public boolean levelUpCheck() { Level lvl = getLevel(curLevel); return score >= lvl.levelUpScore; } public synchronized int getCurLevel() { return curLevel; } public synchronized void levelUp() { virusGrp.interrupt(); Level lvl = getLevel(++curLevel); lbLevel.setText("Level:" + curLevel); words.clear(); screen.clear(); showLevel(curLevel); speed = lvl.speed; interval = lvl.interval; } // Level을 표시 public void showLevel(int level) { String tmp = "Level " + level; showTitle(tmp, 1 * 1000); // 출력되는 title의 정보 } // 출력되는 title의 정보 public void showTitle(String title, int time) { Graphics g = screen.getGraphics(); Font titleFont = new Font("Serif", Font.BOLD, 20); g.setFont(titleFont); FontMetrics fm = getFontMetrics(titleFont); int width = fm.stringWidth(title); g.drawString(title, (SCREEN_WIDTH - width) / 2, SCREEN_HEIGHT / 2); delay(time); } public static void main(String[] args) { 타자게임2 win = new 타자게임2(); // 연산자 new가 반환한 레퍼런스는 new TypingGameEx5(); win.start(); // 참조변수는 win이다. } }
클래스 및 변수 선언(Canvas, Word, Level 등)
class MyCanvas extends Canvas { public void clear() { Graphics g = getGraphics(); g.clearRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT); } public void paint(Graphics g) { clear(); for (int i = 0; i < words.size(); i++) { Word tmp = (Word) words.get(i); g.setColor(tmp.color); g.drawString(tmp.word, tmp.x, tmp.y); } } } class Level { int speed; int interval; int levelUpScore; String[] data; Level(int speed, int interval, int levelUpScore, String[] data) { this.speed = speed; this.interval = interval; this.levelUpScore = levelUpScore; this.data = data; } } // GameLevel class Word { String word = ""; int x = 0; int y = 0; int step = 5; Color color = Color.BLACK; boolean isVirus = false; Word(String word) { this(word, 10, false); } Word(String word, boolean isVirus) { this(word, 10, isVirus); } Word(String word, int step, boolean isVirus) { this.word = word; this.step = step; this.isVirus = isVirus; if (isVirus) color = Color.RED; int strWidth = fm.stringWidth(word); x = (int) (Math.random() * SCREEN_WIDTH); if (x + strWidth >= SCREEN_WIDTH) x = SCREEN_WIDTH - strWidth; } public String toString() { return word; } } // end of class Word
WordDropper Thread
// WordDropper는 WordGenerator와같은 쓰레드로 // 모든 단어의 y좌표를 변경하여 // 단어가 아래로 향하도록 한다. class WordDropper extends Thread { public void run() { outer: while (isPlaying) { // life가 0이하가 되면 break outer;됨 delay(speed); for (int i = 0; i < words.size(); i++) { Word tmp = (Word) words.get(i); tmp.y += tmp.step; // 화면 최하단에 도달했을때 // 단어는 remove되고 // Life가 감소한다 if (tmp.y >= SCREEN_HEIGHT) { tmp.y = SCREEN_HEIGHT; words.remove(tmp); life--; lbLife.setText("Life:" + life); break; } // life가 0 이하가 되면 // while문을 빠져 나감 if (life <= 0) { isPlaying = false; showTitle("Game Over", 0); break outer; } } // for repaint(); // AWT안에 구현되어 있기 때문에 Frame을 상속받으면 바로 사용 가능 // update()메소드를 자동호출 } } // end of run() }
WordGenerator Thread
// WordGenerator는 일정시간(interval)간격으로 // data배열의 한 요소를 골라서 // words(Vector인스턴스)에 저장하는 일을 수행한다 class WordGenerator extends Thread { public void run() { while (isPlaying) { String[] data = LEVEL[getCurLevel()].data; // 원래 LEVEL메서드의 LEVEL[getCurLevel()].data는 String data[]dlek. 접근자의 기능 int rand = (int) (Math.random() * data.length); // 난수 발생. Virus의 data[] 배열 내부에 선언해놓은 값들을 불러오기 위함 // 약 10번에 한번 꼴로 바이러스를 생성한다. boolean isVirus = ((int) (Math.random() * 10) + 1) / 10 != 0; // word가 발생한다 // word는 data[]배열에서 난수로 발생 // Word(String word, boolean isVirus) Word word = new Word(data[rand], isVirus); words.add(word); // Vector words = new Vector(); // Vector는 필요에 따라 길이를 증감할 수 있음 // remove할때는 Vector가 ArrayList나 LinkedList보다 빠름 delay(interval); } } // end of run() }
VirusThread
class VirusThread extends Thread { public VirusThread(ThreadGroup group, String name) { super(group, name); } public void run() { int rand = (int) (Math.random() * 5); int oldValue = 0; int virusTime = 10 * 1000; // 바이러스 동작시간을 10초로 설정한다. switch (rand) { case 0: speed = speed / 2; break; case 1: interval = interval / 2; break; case 2: speed = speed * 2; break; case 3: interval = interval * 2; break; case 4: words.clear(); break; } // swtich delay(virusTime); int curLevel = getCurLevel(); speed = LEVEL[curLevel].speed; interval = LEVEL[curLevel].interval; } // end of run() }
EventHandler ( ActionListener - actionPerformed() )
// 사용자가 textfield에 타이핑한 값을 받아오는 클래스 및 메서드 // WindowAdapter는 윈도우 이벤트를 받기위한 추상클래스이다. class MyEventHandler extends WindowAdapter implements ActionListener { // ActionListener 객체를 등록하는데 필수 구현함수인 actionPerformed()를 등록 // 최종적으로 이벤트가 오게되면 이 함수의 인수로 actionEvent가 넘어오면서 실행되는 것 // ActionEvent 객체로 어떤 곳에서 이벤트가 발생했는지 알 수 있음(마우스인지 윈도우 이벤트인지 등) public void actionPerformed(ActionEvent ae) { String input = tf.getText().trim(); // 문자열의 앞뒤 공백 제거 tf.setText(""); System.out.println(input); if (!isPlaying) return; // words의 크기를 받는다 for (int i = 0; i < words.size(); i++) { // Class Word Word tmp = (Word) words.get(i); // words가 일치하면, if (input.equals(tmp.word)) { // Vector words = new Vector(); // Vector는 필요에 따라 길이를 증감할 수 있음 // remove할때는 Vector가 ArrayList나 LinkedList보다 빠름 words.remove(i); // words가 제거됨 score += input.length() * 50; // 글자당 50점씩 획득 lbScore.setText("Score:" + score); // Score가 갱신됨 Toolkit.getDefaultToolkit().beep(); // Toolkit을 이용해 컴퓨터에서 비프음이 발생 if (curLevel != MAX_LEVEL && levelUpCheck()) { levelUp(); } else { if (tmp.isVirus) { new VirusThread(virusGrp, "virus").start(); // 처음 0레벨일대는 main의 call stack 내부에서 초기값으로 주어진 date[]나 virusGrp를 이용하여 스레드가 실행되지만 // 그 이후에는 start()메서드를 실행하여 새로운 call stack에서 새로운 스레드를 run() 한다(VirusThread) } } break; } } // for repaint(); // 변화가 있을때 마다 호출해야 바로 바로 적용된다. } public void windowClosing(WindowEvent e) { e.getWindow().setVisible(false); e.getWindow().dispose(); System.exit(0); } } // class MyEventHandler
반응형
Comments