Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
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
Archives
Today
Total
관리 메뉴

기록

day 0529 멀티쓰레드 본문

📖

day 0529 멀티쓰레드

슈슈파나 2024. 5. 29. 17:15

package com.kosta.exam01;
class Person {
	private String name;
	
	public Person(String name) {
		super();
		this.name = name;
	}
	
	public void sayHello() {
		for(int i = 1; i <= 10; i++) {
			System.out.println("hello, " + name + " : " + i);
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	} 
}
public class PersonTest {
	public static void main(String[] args) {
		Person p = new Person("이름");
		p.sayHello();
	}
}

public class PersonTest {
	public static void main(String[] args) {
		Person p1 = new Person("이름1");
		Person p2 = new Person("이름2");
		p1.sayHello();
		p2.sayHello();
	}
}

 
/동시에 호출 직접호출 X/

/thread 가동/

 
/멀티 Thread 프로그래밍/

p1.sayHello();
p2.sayHello();

 

메소드를 호출하면 호출한 순서대로 동작합니다

객체 p2 입장에서는 p1의 sayHello()가 모두 끝나야 자신에게 기회가 옵니다

만약 p1이 sayHello()를 동작하다가 문제가 발생되면 p2에게는 영영 기회가 오지 않을 수 있어요

만약, p1과 p2가 가능하면 공평하게 작업을 수행하도록 하려면 "멀티쓰레드 프로그래밍"으로 할 수 있어요  

 

자바에서는 멀티쓰레드 프로그래밍을 위하여 

Thread 클래스와 Runnable 인터페이스를 이용합니다

 

Thread 클래스를 상속하거나 Runnable 인터페이스를 구현하거나
공평하게 동작시키고자 하는 일을 (즉 쓰레드가 해야할 일)
run 메소드를 오버라이딩 해서 그 안에 써 줍니다
 
그리고 쓰레드를 가동시키기위해서는 start() 메소드를 호출합니다
 
만약 start() 메소드를 호출하지않고 직접 run()을 호출하면 오류는 나지 않지만
이것은 공평하게 스케줄링은 되지않고 일반메소드처럼 동작합니다
즉, 먼저 호출한 객체가 작업이 완료되고 다음의 객체에게 기회가 옵니다
그래서 쓰레드를 가동시키려면 run()을 호출하는것이 아니라 start()를 호출해야 합니다
 
또, Runnable 인터페이스를 구현한 경우에는
Runnable 인터페이스는 쓰레드를 가동시키기 위한 start() 메소드가 없기 때문에
Thread 객체로 포장한 후 start()를 호출해야 합니다
 

package com.kosta.exam02;

public class Person extends Thread {
	private String name;
	
	public Person(String name) {
		this.name = name;
	}
	
	@Override
	public void run() { // run을 Override 해준다
		for(int i = 1; i <= 10; i++) {
			System.out.println("hello, " + name + " : " + i);
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam02;

public class PersonTest {
	public static void main(String[] args) {
		Person p1 = new Person("이름1");
		Person p2 = new Person("이름2");
		
		p1.start();
		p2.start();
	}
}

 
/Runnable 인터페이스를 이용하기/

package com.kosta.exam03;

public class Person implements Runnable {
	private String name;
	
	public Person(String name) {
		super();
		this.name = name;
	}	
	
	@Override
	public void run() {
		for(int i = 1; i <= 5; i++) {
			System.out.println("hello, " + name + " : " + i);
			
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam03;

// Runnable 인터페이스를 이용하여 수정 해 봅니다
public class PersonTest {
	public static void main(String[] args) {
		// Runnable 인터페이스 구현
		Person p1 = new Person("이름1");
		Person p2 = new Person("이름2");
		Person p3 = new Person("이름3");
		
		// p1.start(); // start() 호출 불가능 
		// p2.run(); // 일반 메소드처럼 실행

		new Thread(p1).start();
		new Thread(p2).start();
		
		(new Thread(p3)).start();
	}
}

 

/*
PROGRAMMING 2.
정확히 1초에 한 번씩 현재 시각과 "안녕하세요?"를 출력하는 프로그램을 작성하라.
현재 시각은 Date 객체를 생성하면 알 수 있다. 1초 동안 잠드는 sleep() 메소드를 사용하라.
*/
package com.kosta.exam04;

import java.util.Date;

public class Hello extends Thread {
	@Override
	public void run() {
		
		while(true) {
			Date now = new Date();
			System.out.println("안녕하세요? " + "현재시각은 " +  now + " 입니다." );
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam04;

public class HelloTest {
	public static void main(String[] args) {
		Hello h = new Hello();
		h.start();
	}
}

package com.kosta.exam05;

import java.util.Date;

public class Hello extends Thread {
	
	@Override
	public void run() {
		
		while(true) {
			Date now = new Date();
			int year = now.getYear() + 1900;
			int month = now.getMonth();
			int date = now.getDate();
			int hours = now.getHours();
			int minutes = now.getMinutes();
			int seconds = now.getSeconds();
			
			String time = year + "년 " + month + "월 " + date + "일 " 
					+ hours + "시 " + minutes + "분 " + seconds + "초 ";
			System.out.println("안녕하세요? " +  time + " 입니다." );
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam05;

public class HelloTest {
	public static void main(String[] args) {
		Hello h = new Hello();
		h.start();
	}
}

 

/*
PROGRAMMING 1.
1초에 한 번씩 카운트 다운을 위한 메시지를 출력하는 프로그램을
스레드를 이용하여서 작성하여보자.
*/

 
/Thread/

package com.kosta.exam06;

public class CountDown extends Thread {
	
	@Override
	public void run() {
		for(int i = 20; i >= 1; i--) {
			System.out.println(i + "초 전입니다.");

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam06;

public class CountDownEvent extends Thread {
	public static void main(String[] args) {
		CountDown countDown = new CountDown();
	
		countDown.start();
	}
}

/Runnable/

package com.kosta.exam07;

public class CountDown implements Runnable{
	
	@Override
	public void run() {
		for(int i = 20; i >= 1; i--) {
			System.out.println(i + "초 전입니다.");
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam07;

public class CountDownEvent extends Thread {
	public static void main(String[] args) {
		CountDown countDown = new CountDown();
	
		new Thread(countDown). start();
	}
}

package com.kosta.exam08;

public class CountDown extends Thread {
	private int delay;
	private String message;
	
	public CountDown(int delay, String message) {
		super();
		this.delay = delay;
		this.message = message;
	}
	
	@Override
	public void run() {
		// 생성시에 전달받은 대기시간만큼 대기했다가 메세지 출력
		try {
			Thread.sleep(delay);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(message);
	}
}
package com.kosta.exam08;

public class CountDownEvent extends Thread {
	public static void main(String[] args) {
		// 1000 1초, 10000 10초
		CountDown countDown = new CountDown(2000, "연결 장치 분리!!");
		countDown.start();
	}
}

package com.kosta.exam09;

public class CountDown extends Thread {
	@Override
	public void run() {
		for(int i = 20; i >= 1; i--) {
			System.out.println(i + "초 전입니다.");

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("발사!!");
	}
}
package com.kosta.exam09;

public class CountDownEvent extends Thread {
	private int delay;
	private String message;
	
	public CountDownEvent(int delay, String message) {
		super();
		this.delay = delay;
		this.message = message;
	}
	
	@Override
	public void run() {
		// 생성시에 전달받은 대기시간만큼 대기했다가 메세지 출력
		try {
			Thread.sleep(delay);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(message);
	}
}
package com.kosta.exam09;

public class CountDownTest {
	public static void main(String[] args) {
		CountDown countDown = new CountDown();
		CountDownEvent countDownEvent = new CountDownEvent(2000, "연결 장치 분리!!");
		
		countDown.start();
		countDownEvent.start();
	}
}

 

어.... 움....... ㅇㅓ........................ 게임 만들기 ~!~!

나눈 졸라맨 ~v

	public Mypanel(BufferedImage img) {
		// 이미지를 표현하기위한 BufferedImage 객체를 생성합니다
		try {
			img = ImageIO.read(new File("player.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}

// 방법1
public void keyPressed(KeyEvent e) {
    int code = e.getKeyCode();
    System.out.println(code);
    System.out.println("키가 눌러짐");

    // 37 38 39 40 space 32
    if(code == 37) {
        System.out.println("왼쪽눌러짐");
    }
    if(code == 38) {
        System.out.println("위쪽눌러짐");
    }
    if(code == 39) {
        System.out.println("오른쪽눌러짐");
    }
    if(code == 40) {
        System.out.println("아래쪽눌러짐");
    }
}

// 방법2
public void keyPressed(KeyEvent e) {
    switch(e.getKeyCode()) {
                case KeyEvent.VK_LEFT: System.out.println("왼쪽 누름"); break;
                case KeyEvent.VK_UP: System.out.println("위쪽 누름"); break;
                case KeyEvent.VK_RIGHT: System.out.println("오른쪽 누름"); break;
                case KeyEvent.VK_DOWN: System.out.println("아래쪽 누름"); break;
                }
}

 

package com.kosta.game;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

// swing Jpanel 사용한다
public class MyPanel extends JPanel implements KeyListener {
	// 플레이어가 그려질 x, y 좌표를 멤버변수로 선언
	int x = 100, y = 100;
	
	// 이미지파일을 참조하기위한 변수를 선언해요
	BufferedImage img = null;
	
	// 생성자 만들기
	public MyPanel() {
		// 이미지를 표현하기위한 BufferedImage 객체를 생성합니다
		try {
			img = ImageIO.read(new File("player.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 키보드 이벤트를 등록시킨다
		addKeyListener(this);
		
		// 패널은 원래부터 글자를 입력하는 용도가 아니라서 키보드 이벤트를 등록해도 동작하지 않는다
		// 패널에 키보드 이벤트를 등록하려면 포커스를 설정해야합니다
		requestFocus();
		setFocusable(true);
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		// panel이 가지고있는 메소드, 내가 그리고싶은 내용
		// x, y 변수를 멤버변수로 만든다
		g.drawImage(img, x, y, null);
	}

	// KeyListener의 메소드
	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void keyPressed(KeyEvent e) {
		switch(e.getKeyCode()) {
			case KeyEvent.VK_LEFT: x -=10; break; //System.out.println("왼쪽 누름")
			case KeyEvent.VK_UP: y -= 10; break; //System.out.println("위쪽 누름");
			case KeyEvent.VK_RIGHT: x += 10; break; // System.out.println("오른쪽 누름");
			case KeyEvent.VK_DOWN: y += 10; break; // System.out.println("아래쪽 누름");
		}	
		// 다시 그려달라고 요청
		repaint();
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
	}
}
package com.kosta.game;

import java.awt.Color;
import javax.swing.JFrame;

public class MyFrame extends JFrame {
	MyPanel panel;
	
	public MyFrame() {
		// 프레임 배경색을 흰색으로 설정
		panel = new MyPanel();
		setBackground(Color.white);
		add(panel);
		setSize(400, 300);
		setVisible(true);
		// 프로그램 종료
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
}
package com.kosta.game;

public class MyFrameTest {
	public static void main(String[] args) {
		new MyFrame();	
	}
}

핵ㄱㅣ여운 졸라맨 움짤 완성 ㅠ 구ㅣ!! 여!!! 워ㅓ!!!!


 
14:00 ~ 
 
/공통된 클래스 GraphicObject 만들기/

package com.kosta.game2;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

// 미래에 만들어질 적, 미사일, 플레이어이 가져야 할 공통적인 속성과 동작을 일반화 시키기(부모클래스 만들기)
public class GraphicObject {

	// 적, 미사일, 플레이어를 나타 낼 이미지를 담을 변수
	BufferedImage img = null;
	
	// 이미지를 출력 할 좌표 x, y
	int x = 0, y = 0;
	
	// 생성자를 만들어요 (생성시에 이미지 파일명을 매개변수로 전달받아 BufferedImage 객체를 생성한다)
	public GraphicObject(String name) {
		try {
			img = ImageIO.read(new File(name));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	// 미래에 만들어질 후손클래스들이 가져야 할 공통적인 메소드를 만들어요
	public void update() {}
	public void draw(Graphics g) {
		g.drawImage(img, x, y, null);
	}
	public void keyPressed(KeyEvent event) {
	}
}

 
/Missile/

package com.kosta.game2;

import java.awt.event.KeyEvent;
import java.awt.geom.FlatteningPathIterator;

// GraphicObject를 상속받아 "미사일" 클래스를 만들어요
public class Missile extends GraphicObject {
	// 미사일이 발사되었는지 판별하기 위한 변수를 선언
	boolean launched = false;
	
	// 미사일 생성시에 미사일로 표현할 이미지 파일명을 전달받아
	// 부모 생성자인 GraphicObject 생성자에게 전달합니다
	public Missile(String name) {
		super(name);
		
		// 맨 처음 미사일의 위치를 화면에서 벗어난 구석에 놓아요
		y = -200;
	}

	// update 메소드를 Override
	@Override
	public void update() {
		
		// 미사일이 발사되었으면 y의 위치를 1씩 감소시켜서 위로 이동하도록 합니다
		if(launched) { 
			y -= 10;
		}
		
		// y의 위치가 화면에서 벗어나면 (-100보다 작아지면) 
		// launched에 false를 담아서 미사일을 움직이지 않도록 합니다
		if(y < -100) {
			launched = false;
		}
	}
	
	// 키보드가 눌러지면 눌러진 키이벤트 정보와
	// 플레이어의 위치 x, y를 갖고 이 메소드를 호출합니다
	public void keyPressed(KeyEvent event, int x, int y) {
		// 만약 스페이스 키가 눌러지면
		if(event.getKeyCode() == KeyEvent.VK_SPACE) {

			// 미사일을 발사시키기 위하여 launched에 true를 저장합니다
			launched = true;
			
			// 미사일을 플레이어의 위치에서부터 발사시키기 위하여
			// 미사일의 x, y를 매개변수로 전달받은 플레이어의 위치 x, y로 설정
			this.x = x;
			this.y = y;
		}
	}
}

 
/Enermy/

package com.kosta.game2;

// 1) GraphicObject를 상속받아 적을 만들어요
public class Enermy extends GraphicObject {
	// 적을 가로방향으로 왔다 갔다 하도록 합니다
	// 맨 처음 이동거리를 -10으로 설정하여 왼쪽으로 10만큼씩 이동하도록 합니다 
	int dx = -10;
	
	// 2) 생성시에 적으로 표현할 이미지 파일명을 전달받아
	public Enermy(String name) {
		
		// 3) 부모의 생성자(GraphicObject)에게 전달합니다
		super(name);
		
		// 맨 처음 적의 위치를 500,0으로 설정합니다
		x = 350;
		y = 0;
	}

	// 적의 위치를 갱신하기 위하여 update를 오버라이딩 합니다
	@Override
	public void update() {
		// x의 위치를 dx만큼 이동시킵니다
		x += dx;
		
		// x 위치가 왼쪽 끝에 도달하면 다시 오른쪽으로 이동시키기 위해 dx를 +10으로 설정한다
		if(x < 0) {
			dx = +10;
		}
		
		// x 위치가 오른쪽 끝에 도달하면 다시 왼쪽으로 이동시키기 위해 dx를 -10으로 설정한다
		if(x > 350) {
			dx = -10;
		}
	}
}

 
/Player/

package com.kosta.game2;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

// 미래에 만들어질 적, 미사일, 플레이어이 가져야 할 공통적인 속성과 동작을 일반화 시키기(부모클래스 만들기)
public class GraphicObject {

	// 적, 미사일, 플레이어를 나타 낼 이미지를 담을 변수
	BufferedImage img = null;
	
	// 이미지를 출력 할 좌표 x, y
	int x = 0, y = 0;
	
	// 생성자를 만들어요 (생성시에 이미지 파일명을 매개변수로 전달받아 BufferedImage 객체를 생성한다)
	public GraphicObject(String name) {
		try {
			img = ImageIO.read(new File(name));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	// 미래에 만들어질 후손클래스들이 가져야 할 공통적인 메소드를 만들어요
	public void update() {}
	public void draw(Graphics g) {
		g.drawImage(img, x, y, null);
	}
	public void keyPressed(KeyEvent event) {
	}
}

 
/MyPanel/

package com.kosta.game2;

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

import javax.swing.JPanel;

// JPanel을 상속받고 KeyListener 인터페이스를 구현하는 MyPanel 클래스를 만들어요
public class MyPanel extends JPanel implements KeyListener {
	// 게임 구성요소인 적, 플레이어, 미사일을 멤버변수로 선언해요
	Enermy enermy;
	Player player;
	Missile missile;
	
	// 생성자를 만들어요
	public MyPanel() {
		super();
		setBackground(Color.white);
		
		// 키보드 이벤트가 발생하였을 때 일처리를 누가 할 것인지 설정합니다(this)
		this.addKeyListener(this);
		
		// 패널은 원래부터 글자를 입력하는 용도가 아니라서 키보드 이벤트를 바로 설정 할 수 없어요
		// 패널에 키보드 이벤트를 설정하기 위하여 포커스를 설정합니다
		this.requestFocus();
		setFocusable(true);
		
		// 적, 플레이어, 미사일 객체를 각각 생성합니다
		// 생성시에 이미지 파일명을 전달합니다
		enermy = new Enermy("enermy.png");
		player = new Player("player.png");
		missile = new Missile("missile.png");
		

		// 적, 플레이어, 미사일이 동시다발적으로 움직이게 하기 위하여 쓰레드 클래스를 만들어요
		// 이것은 다른곳에서 쓸 일이 없기때문에 이 클래스(Mypanel) 안에 Inner클래스로 만들어요
		class MyThread extends Thread{
			
			// 쓰레드가 해야 할 일 
			// 즉 미사일, 적, 우리편이 동시다발적으로 움직이는 코드는 run을 오버라이딩하여 써 줍니다
			@Override
			public void run() {
				
				// 그래픽 오브젝트(적,플레이어,미사일)이 계속 움직이게 하기 위하여 while(true)를 써요
				while(true) {
					enermy.update();
					player.update();
					missile.update();			
					
					// 갱신된 위치에 다시 그려줄 것을 요청합니다
					repaint();
					
					try {
						Thread.sleep(50); // 0.05초
					} catch (InterruptedException e) {
						e.printStackTrace();
					} // end catch
				} // end while		
			} // end MyThread
		}
		Thread t = new MyThread();
		t.start();
	}
	
	// 쓰레드에서 각각의 그래픽오브젝트의 위치를 변경시킨 후 
	// 다시 그려줄것을 요청(repain)하면 다음의 paint가 동작합니다
	// 이 메소드에서는 각각의 그래픽오브젝트의 draw를 호출 해 줍니다
	@Override
	public void paint(Graphics g) {
		// TODO Auto-generated method stub
		super.paint(g);
		enermy.draw(g);
		player.draw(g);
		missile.draw(g);
	}

	// 패널에 키가 눌러지면 다음이 keyPressed 메소드가 동작합니다
	@Override
	public void keyPressed(KeyEvent event) {
		// 플레이어의 keyPressed 메소드를 호출하면서 키 이벤트를 전달합니다
		player.keyPressed(event);
		// 미사일의 keyPressed 메소드를 호출하면서 키 이벤트와 플레이어의 x, y 위치를 전달합니다
		missile.keyPressed(event, player.x, player.y);
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
	}
}

 
/MyFrame/

package com.kosta.game2;

import java.awt.Color;

import javax.swing.JFrame;

public class MyFrame extends JFrame {
	public MyFrame() {
		setTitle("My Game");
		add(new MyPanel());
		setSize(400, 300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	public static void main(String[] args) {
		new MyFrame();
	}
}

 
하하하 !!! 미사일 맞으면 없어지눈걸 만들어야한다 ㅠ 맞히질 못하눈ㄴ데 어케 없어져 ~~~~

- 오늘 학습한 내용에 대하여 요약 및 정리하고 잘 이해가 되지않는 부분은 질문하여 이해하고 넘어가도록 합니다
  (멀티쓰레드 관련하여 꼭 이해하도록 합니다!!)
- 요약 및 정리가 끝난 사람들은 미사일의 속도를 조절 해 보고 적이 미사일에 맞으면 사라지게 합니다
- 또, 적이 미사일에 맞으면 펑~ 하고 소리를내고 사라지도록 해 봅니다
- 적을 여러개 만들어 봅니다

package com.kosta.game3;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

// 미래에 만들어질 적, 미사일, 플레이어이 가져야 할 공통적인 속성과 동작을 일반화 시키기(부모클래스 만들기)
public class GraphicObject {

	// 적, 미사일, 플레이어를 나타 낼 이미지를 담을 변수
	BufferedImage img = null;
	
	// 이미지를 출력 할 좌표 x, y
	int x = 0, y = 0;
	
	// 생성자를 만들어요 (생성시에 이미지 파일명을 매개변수로 전달받아 BufferedImage 객체를 생성한다)
	public GraphicObject(String name) {
		try {
			img = ImageIO.read(new File(name));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	// 미래에 만들어질 후손클래스들이 가져야 할 공통적인 메소드를 만들어요
	public void update() {}
	public void draw(Graphics g) {
		g.drawImage(img, x, y, null);
	}
	public void keyPressed(KeyEvent event) {
	}
}
package com.kosta.game3;

import java.util.Random;

// 1) GraphicObject를 상속받아 적을 만들어요
public class Enermy extends GraphicObject {
    // x축으로 이동하기위한 변수
	int dx;
    // y축으로 이동하기위한 변수
    int dy;
	
	// 2) 생성시에 적으로 표현할 이미지 파일명을 전달받아
	public Enermy(String name) {
		
		// 3) 부모의 생성자(GraphicObject)에게 전달합니다
		super(name);
		
		// 난수 발생을 위한 Random 객체 생성
        Random r = new Random();
        
        // 적의 x위치를 0~400사이의 난수로 설정
        x = r.nextInt(400);
        
        // 적의 y위치를 0~200사이의 난수로 설정
        y = r.nextInt(200);
        
        // 적의 x축 이동거리를 -19~19사이의 난수로 설정
        dx = r.nextInt() % 20;
        
        // 적의 y축 이동거리를 -9~9사이의 난수로 설정
        dy = r.nextInt() % 10;
	}

	// 적의 위치를 갱신하기 위하여 update를 오버라이딩 합니다
	@Override
	public void update() {
		// x의 위치를 dx만큼 이동시킵니다
		x += dx;
        
        // y의 위치를 dy만큼 이동시킵니다
        y += dy;
		
		// x 위치가 왼쪽 끝에 도달하면 다시 오른쪽으로 이동시키기 위해 이동방향을 반대로한다
		if(x < 0 || x > 400) {
			dx = -dx;
		}
		
		// x 위치가 오른쪽 끝에 도달하면 다시 왼쪽으로 이동시키기 위해 이동방향을 반대로한다
		if(y < 0 || y > 200) {
			dy = -dy;
		}
	}
    // 미사일에 맞았는지 안맞았는지 판별하는 메소드
    public boolean isHit(Missile missile){
    	boolean flag = false;
        // 미사일 x위치가 적의 x보다 크거나 같고, 미사일 x가 적의 x+40보다 작거나 같다면
        if(missile.x >= x && missile.x <= (x+40) && missile.y >= y && missile.y <= (y+40){
        	flag = true;
        }
        return flag;
    }
}
package com.kosta.game3;

import java.awt.event.KeyEvent;
import java.awt.geom.FlatteningPathIterator;

// GraphicObject를 상속받아 "미사일" 클래스를 만들어요
public class Missile extends GraphicObject {
	// 미사일이 발사되었는지 판별하기 위한 변수를 선언
	boolean launched = false;
	
	// 미사일 생성시에 미사일로 표현할 이미지 파일명을 전달받아
	// 부모 생성자인 GraphicObject 생성자에게 전달합니다
	public Missile(String name) {
		super(name);
		
		// 맨 처음 미사일의 위치를 화면에서 벗어난 구석에 놓아요
		y = -200;
	}

	// update 메소드를 Override
	@Override
	public void update() {
		
		// 미사일이 발사되었으면 y의 위치를 1씩 감소시켜서 위로 이동하도록 합니다
		if(launched) { 
			y -= 10;
		}
		
		// y의 위치가 화면에서 벗어나면 (-100보다 작아지면) 
		// launched에 false를 담아서 미사일을 움직이지 않도록 합니다
		if(y < -100) {
			launched = false;
		}
	}
	
	// 키보드가 눌러지면 눌러진 키이벤트 정보와
	// 플레이어의 위치 x, y를 갖고 이 메소드를 호출합니다
	public void keyPressed(KeyEvent event, int x, int y) {
		// 만약 스페이스 키가 눌러지면
		if(event.getKeyCode() == KeyEvent.VK_SPACE) {

			// 미사일을 발사시키기 위하여 launched에 true를 저장합니다
			launched = true;
			
			// 미사일을 플레이어의 위치에서부터 발사시키기 위하여
			// 미사일의 x, y를 매개변수로 전달받은 플레이어의 위치 x, y로 설정
			this.x = x;
			this.y = y;
		}
	}
}
package com.kosta.game3;

import java.awt.event.KeyEvent;

// GraphicObject를 상속받아 우리편(Player)를 만들어요
public class Player extends GraphicObject {
	// 생성시에 플레이어로 사용할 이미지파일을 전달받아서
	public Player(String name) {
		
		// 부모 생성자(GraphicObject) 에게 전달합니다
		super(name);
		
		// 플레이어의 시작 위치
		x = 170;
		y = 200;
	}

	@Override
	public void keyPressed(KeyEvent event) {
		
		// 눌러진 방향키에 따라 x, y좌표를 이동시킵니다
		switch(event.getKeyCode()) {
			case KeyEvent.VK_LEFT: x -= 10; break;
			case KeyEvent.VK_RIGHT: x += 10; break;
			case KeyEvent.VK_UP: y -= 10; break;
			case KeyEvent.VK_DOWN: y += 10; break;
		}
		
		/*
		if(event.getKeyCode() == KeyEvent.VK_LEFT) {
			x -= 10;
		}
		if(event.getKeyCode() == KeyEvent.VK_RIGHT) {
			x += 10;
		}
		if(event.getKeyCode() == KeyEvent.VK_UP) {
			y -= 10;
		}
		if(event.getKeyCode() == KeyEvent.VK_DOWN) {
			y += 10;
		}
		*/
	}	
}
package com.kosta.game3;

public class Boom extends GraphicObject {
	public Boom(String name) {
		super(name);
	}
}
package com.kosta.game3;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import javax.swing.JPanel;

// JPanel을 상속받고 KeyListener 인터페이스를 구현하는 MyPanel 클래스를 만들어요
public class MyPanel extends JPanel implements KeyListener {
	// 게임 구성요소인 적, 플레이어, 미사일을 멤버변수로 선언해요
	Enermy enermy;
	Player player;
	Missile missile;
	Boom boom;
	
    // 적을 여러개 만들기 위하여 리스트를 선언해요
    ArrayList<Enermy> enemies = null;
    
	// 생성자를 만들어요
	public MyPanel() {
		super();
		setBackground(Color.white);
		
		// 키보드 이벤트가 발생하였을 때 일처리를 누가 할 것인지 설정합니다(this)
		this.addKeyListener(this);
		
		// 패널은 원래부터 글자를 입력하는 용도가 아니라서 키보드 이벤트를 바로 설정 할 수 없어요
		// 패널에 키보드 이벤트를 설정하기 위하여 포커스를 설정합니다
		this.requestFocus();
		setFocusable(true);
		
        // 객체를 생성
        enemies = new ArrayList<Enermy>();
        
        // 적을 5개 만들어서 리스트에 담는다
        for(int i = 1; i <= 5; i++){
			enermy = new Enermy("enermy.png");
        }
		player = new Player("player.png");
		missile = new Missile("missile.png");
		boom = new Boom("boom.png");
		

		// 적, 플레이어, 미사일이 동시다발적으로 움직이게 하기 위하여 쓰레드 클래스를 만들어요
		// 이것은 다른곳에서 쓸 일이 없기때문에 이 클래스(Mypanel) 안에 Inner클래스로 만들어요
		class MyThread extends Thread{
			
			// 쓰레드가 해야 할 일 
			// 즉 미사일, 적, 우리편이 동시다발적으로 움직이는 코드는 run을 오버라이딩하여 써 줍니다
			@Override
			public void run() {
				
				// 그래픽 오브젝트(적,플레이어,미사일)이 계속 움직이게 하기 위하여 while(true)를 써요
				while(true) {
                	for(Enermy enermy : enemies){
						enermy.update();
                    }
					player.update();
					missile.update();
					boom.update();
						
					// 갱신된 위치에 다시 그려줄 것을 요청합니다
					repaint();
					
                    // 리스트에 담긴 적을 하나씩 꺼내어 미사일에 맞았는지 판별
                    for(Enermy enermy : enemies){
                    	if(enermy.isHit(missile)){
                            File file = new File("EXPLODE.WAV");
                            try {
                                Clip clip = AudioSystem.getClip();
                                clip.open(AudioSystem.getAudioInputStream(file));
                                clip.start();
                                enemy.x = -3000;
                            }catch (Exception e) {
                                // TODO: handle exception
                            }
                        }
                    }
                    
					try {
						Thread.sleep(50); // 0.05초
					} catch (InterruptedException e) {
						e.printStackTrace();
					} // end catch
				} // end while		
			} // end MyThread
		}
		Thread t = new MyThread();
		t.start();
	}
	
	// 쓰레드에서 각각의 그래픽오브젝트의 위치를 변경시킨 후 
	// 다시 그려줄것을 요청(repain)하면 다음의 paint가 동작합니다
	// 이 메소드에서는 각각의 그래픽오브젝트의 draw를 호출 해 줍니다
	@Override
	public void paint(Graphics g) {
		// 부모의 print를 호출하여 화면을 지운다
		super.paint(g);
        
        // 적을 그린다
        for(Enermy enermy : enemies){
			enermy.draw(g);
        }
        
		player.draw(g);
		missile.draw(g);
		boom.draw(g);
	}

	// 패널에 키가 눌러지면 다음이 keyPressed 메소드가 동작합니다
	@Override
	public void keyPressed(KeyEvent event) {
		// 플레이어의 keyPressed 메소드를 호출하면서 키 이벤트를 전달합니다
		player.keyPressed(event);
		// 미사일의 keyPressed 메소드를 호출하면서 키 이벤트와 플레이어의 x, y 위치를 전달합니다
		missile.keyPressed(event, player.x, player.y);
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
	}
}
package com.kosta.game3;

import java.awt.Color;

import javax.swing.JFrame;

public class MyFrame extends JFrame {
	public MyFrame() {
		setTitle("My Game");
		add(new MyPanel());
		setSize(400, 300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	public static void main(String[] args) {
		new MyFrame();
	}
}

ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ