본문 바로가기
JAVA

자바 비행기 게임 만들어보기 #3

by binghe819 2020. 5. 2.

이번엔 게임 동작시키는데 있어서 큰 그림을 그리는 순서가 될 것 같다.

 

저번 포스터에서 비행기를 출력하고 움직이는 것까지 했는데, 이걸 하나의 비행기가 아닌 여러개의 비행기가 

 

동시에 출력되고, 미사일등이 날라다니면서 충돌로직을 구현하려면 구조가 잘 짜여있어야한다.

 

또한, 나중의 확장성을 고려한다면 구조는 효율성에 있어서도 매우 중요하다고 생각든다.

 

이것저것 공부하다 결국 Swing에서 많이 사용되는 MVC패턴을 응용해서 만들어보기로 했다.


순서

  • MVC응용 구조 설계
    • Model
    • View
    • Controller
  • 미사일 발사

 

MVC 응용 구조 설계

MVC를 알게된 경로는 Java 공식 문서와 튜토리얼 사이트 그리고 블로그이다.

 

기본적인 개념은 MVC - 위키피디아에 잘 나와 있다.

 

이번 프로젝트의 MVC 구조가 틀린 부분도 많고 비효율적일 수도 있을거라 생각한다.

( 피드백이나 공부자료 추천해주시면 감사합니다~ )

 

이번 사이드 프로젝트에서는 다음과 같은 구조를 사용한다.

 

직접 그려본 이번 프로젝트의 MVC구조

  • Model : DB ( 위치값, HP, 미사일 위치등 저장 )역할 담당.
  • View : Model의 값을 지속적으로 받아와 출력을 담당. ( 스레드 )
  • Controller : 사용자의 입력 ( 사용자 키 입력 )과 게임 로직 ( 미사일 이동, Crash로직 )을 담당. ( 스레드 )
객체지향과 디자인 패턴등 설계에 관련된 내용을 더 공부해야 겠다고 생각이 들었다..

Model

Model에 저장될 데이터의 형식을 클래스를 이용해 구성하였다.

 

Model에 저장할 데이터처리하는 클래스의 구조는 아래와 같이 설계 하였다.

GameObject 구조 ( 회색 네모는 Movable 인터페이스 구현된 클래스 )

클래스의 구조는 공통적인 변수를 기준으로 구성했으며, 직접 구현할 필요가 없는 부모 클래스는 추상클래스를 사용하였다.

 

또한, 미사일이나 적 비행기들은 반복적으로 움직이기때문에 move()라는 메서드를 인터페이스를 이용해 구현하므로써 오버라이딩을 강제하도록 하였다. ( 해당 객체들은 움직임이 꼭 있어야 하기 때문에 )

 

GameObject
Movable

자세한 코드는 깃헙 을 참고바랍니다.

 

객체지향의 설계에 대한 지식이 부족하다고 느낀 프로젝트이기도 하다.
객체지향의 설계와 관련된 공부를 더 하여 포스팅 할 예정이다.

View

import javax.swing.*;
import java.awt.*;

public class GameView extends JFrame{
    // 이미지 버퍼
    Image buffImg;
    Graphics buffG;

    // model, controller
    GameModel model;
    GameController controller;


    public GameView(GameModel model, GameController controller) {
        this.model = model;
        this.controller = controller;

        // 프레임의 대한 설정.
        setTitle("JFrame 테스트"); // 프레임 제목 설정.
        setSize(854,480); // 프레임의 크기 설정.
        setResizable(false); // 프레임의 크기 변경 못하게 설정.
        setVisible(true); // 프레임 보이기;
//        setDefaultCloseOperation(DISPOSE_ON_CLOSE); // 프레임의 x버튼 누르면 프레임스레드 종료.
        setDefaultCloseOperation(EXIT_ON_CLOSE); // 프레임의 x버튼 누르면 프로세스 종료.
        addKeyListener(controller);

        // 컨트롤 스레드 실행. ( 데몬스레드를 사용하여 View가 멈추면 컨트롤의 스레드도 멈춤. )
        Thread control_thread = new Thread(this.controller);
        control_thread.setDaemon(true);
        control_thread.start();
    }

    @Override
    public void paint(Graphics g) {
        buffImg = createImage(getWidth(),getHeight()); // 버퍼링용 이미지 ( 도화지 )
        buffG = buffImg.getGraphics(); // 버퍼링용 이미지에 그래픽 객체를 얻어야 그릴 수 있다고 한다. ( 붓? )
        update(g);
    }

    @Override
    public void update(Graphics g) {
        buffG.drawImage(this.model.player.img,this.model.player.x,this.model.player.y, this); // 유저 비행기 그리기.
        g.drawImage(buffImg,0,0,this); // 화면g애 버퍼(buffG)에 그려진 이미지(buffImg)옮김. ( 도화지에 이미지를 출력 )
        repaint();
    }
}

 

Controller

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class GameController extends KeyAdapter implements Runnable {

    // 키 눌림 처리
    boolean keyUp;
    boolean keyDown;
    boolean keyLeft;
    boolean keyRight;

    // 미사일의 발사 속도를 늦추기 위한 count.
    int cnt = 0;

    // Model에 접근하기 위한 참조변수.
    GameModel model;

    public GameController(GameModel model) {
        this.model = model;
    }

    // 키가 눌렸을 때
    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()){
            case KeyEvent.VK_UP :
                this.keyUp = true;
                break;
            case KeyEvent.VK_DOWN :
                this.keyDown = true;
                break;
            case KeyEvent.VK_LEFT :
                this.keyLeft = true;
                break;
            case KeyEvent.VK_RIGHT :
                this.keyRight = true;
                break;
        }
    }

    // 키가 눌렀다 때졌을 때.
    @Override
    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()){
            case KeyEvent.VK_UP :
                this.keyUp = false;
                break;
            case KeyEvent.VK_DOWN :
                this.keyDown = false;
                break;
            case KeyEvent.VK_LEFT :
                this.keyLeft = false;
                break;
            case KeyEvent.VK_RIGHT :
                this.keyRight = false;
                break;
        }
    }

    // 키에 대한 처리.
    public void keyProcess() {
        cnt++;
        if(this.keyUp){
            if(this.model.player.y >= 26)
                this.model.player.y -= 5;
        }

        if(this.keyDown){
            if(this.model.player.y < 465)
                this.model.player.y += 5;
        }

        if(this.keyLeft){
            if(this.model.player.x > 0)
                this.model.player.x -= 5;
        }

        if(this.keyRight){
            if(this.model.player.x < 790)
                this.model.player.x += 5;
        }
    }

    @Override
    public void run() {
        try {
            while(true){
                keyProcess();
                Thread.sleep(20);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

Main

Main함수

Swing이 동작중 만약 프레임이 꺼지거나 x버튼을 누르면, controller의 스레드도 같이 멈춰줘야하기때문에, View객체 안에 데몬 스레드를 사용하여 controller가 실행되게 하였다. 

 

미사일 발사

미사일 발사의 과정은 아래와 같다.

  1. 사용자 스페이스바 누름. ( Controller의 KeyAdapter )
  2. model의 멤버중 playerMissile이라는 리스트에 새로운 Missile인스턴스를 추가한다.
  3. Controller에서는 미사일의 위치를 계속해서 앞으로 이동시킨다. ( 위치 값 갱신 )
  4. View는 미사일의 위치를 지속적으로 출력한다.

 

Missile 객체는 아래와 같이 설계하였다.

Missile 객체

 

 

펭귄대왕님의 블로그가 많이 참고가 되었다.

 

다음 포스트는 적 비행기를 생성하고 충돌로직을 구현할 예정이다.

'JAVA' 카테고리의 다른 글

자바 비행기 게임 만들어보기 #4  (0) 2020.05.04
자바 비행기 게임 만들어보기 #2  (0) 2020.05.01
자바 비행기 게임 만들어보기 #1  (0) 2020.04.30

댓글