본문 바로가기

프로그래밍/libGDX 엔진

libGDX #2 화면 만들기 도전

libGDX의 설치가 끝났으니, 이제 기본적인 화면 구성을 만들어보자.

우리가 만들 게임은 내 프로젝트 기준으로 pug-game 폴더에서만 로직을 만들게되는 구조이다. 현재, 이 안에는 PugGame.java 파일만 하나 덩그라니 있으며, 데스크탑 or 안드로이드에서 실행을 시키면 저 파일부터 읽어서 시작하게되는 시작점이 된다. 그럼 PugGame.java에서부터 따라 들어가게끔 화면을 구성해야하는데, 아직 PugGame.java에 구현된 내용이 없다. create가 있지만 이것만으로는 부족하다. libgdx에서는 게임에 필요한 기본적인 요소를 create, resize, render, pause, resume, dispose로 정의하여 제공하고 있다. 기본적인 lifecyle은 create -> resize가 기본적으로 한 번 실행된 후, render가 무한하게 도는 구조이다. 그 후, 종료 이벤트가 오면 pause 후, dispose되는것이다. pause와 resume은 안드로이드에서 주로 쓰게 될 기능인데, 게임을 하는 중 전화가 오거나하는 등의 화면에서 포커스가 벗어나게되면 pause 이벤트를 타고, 다시 화면으로 포커스가 돌아오면 resume 이벤트를 타는 그런 구조이다. 아래의 그림을 보면 쉽게 이해가 갈 것이다.

그럼, 라이프사이클에 맞게 PugGame.java를 꾸며보자. 자동생성 기능을 통해 아래와 같이 6개의 메소드를 생성하자.

이걸로 껍데기는 생성이 끝났다. 그 외에 개발의 편의를 위해 LOG, FPS, DEV_MODE를 정의하였다. 주석과 함께 적었으니 설명은 주석을 읽으세요.


게임이 시작될 때 create() 가 가장 먼저 호출되는데, 여기에 화면 인스턴스를 생성해서 화면이 나오도록하자. 우리가 어떤 게임을 만들던지 꼭 필요한 3개의 화면이 있는데 스플래쉬화면(게임로딩화면), 메뉴화면, 게임화면 3가지이다. 가장 먼저 스플래쉬화면이 로딩되야하고, 로딩이 끝나면 메뉴화면으로 넘어가야 한다. 이제 create()가 호출되었을때, 스플래쉬화면을 호출하고, 스플래쉬 또한, 꾸며보자.

package com.dpug.puggame;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.FPSLogger;
import com.dpug.puggame.screen.SplashScreen;

public class PugGame extends Game {

	/**
	 * 로그를 남길때 사용하는 상수 정의
	 */
	public static String LOG = PugGame.class.getSimpleName();

	/**
	 * 매 초마다 현재 FPS를 로깅하는 libGDX에서 제공하는 클래스 선언
	 */
	private FPSLogger fpsLogger;

	/**
	 * 개발 모드를 구분하기 위한 상수 정의
	 */
	public static boolean DEV_MODE = true;

	// 스플래쉬 화면 선언
	private SplashScreen splashScreen;

	@Override
	public void create() {
		// 로그 출력
		Gdx.app.log(PugGame.LOG, "게임이 생성되었습니다.");

		// fps 생성
		this.fpsLogger = new FPSLogger();

		// 스플래쉬 화면 생성
		this.splashScreen = new SplashScreen(this);

		// PugGame이 상속받고 있는 Game 클래스에 스크린에 스플래쉬화면을 넣어줌
		setScreen(this.splashScreen);
	}

	@Override
	public void resize(int width, int height) {
		super.resize(width, height);
		Gdx.app.log(PugGame.LOG, "게임화면 크기 변경: " + width + " x " + height);
	}

	@Override
	public void render() {
		super.render();
		// 개발 모드일때, 현재 FPS를 로깅
		if (DEV_MODE) {
			this.fpsLogger.log();
		}
	}

	@Override
	public void pause() {
		super.pause();
		Gdx.app.log(PugGame.LOG,"게임 잠시 멈춤");
	}

	@Override
	public void resume() {
		super.resume();
		Gdx.app.log(PugGame.LOG,"게임 다시 시작");
	}

	@Override
	public void dispose() {		
		super.dispose();
		Gdx.app.log(PugGame.LOG,"게임 종료");		
		splashScreen.dispose();
	}
}

단순히 PugGame에서는 create에서 SplahScreen을 생성해서 Game에다가 setScreen 해준것이 전부이다. Screen 클래스를 꾸미기 이전에 구조적인 관점에서 먼저 접근을하면, 우리가 만들 화면 클래스는 최소 3개이다. 그런데 게임화면이 고작 3개로 갈리도 없다. 게임이 커지면 커질수록 더 많은 화면이 나오게 될 것이고, 화면들은 매 번 같은 동작구조로 움직이는데 이걸 하나로 묶지 않는다면 어찌 Java를 할 줄 안다 말하겠는가?! 따라서, AbstractScreen을 만들어 Screen들을 묶어 관리하게 할 것이다. AbstractScreen은 현재 껍데기만 존재할 것이고, SplashScreen은 AbsctractScreen을 상속받아 필요한 부분인 show() 만 구현하면 될 것이다.
package com.dpug.puggame.screen;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.dpug.puggame.PugGame;

public class AbstractScreen implements Screen {

	protected final PugGame game;

	public AbstractScreen(PugGame game) {
		this.game = game;
	}

	/**
	 * 해당 클래스 이름 스트링으로 반환하는 함수
	 */
	protected String getName() {
		return getClass().getSimpleName();
	}

	@Override
	public void render(float delta) {

	}

	@Override
	public void resize(int width, int height) {
		Gdx.app.log(PugGame.LOG, "화면 크기 변경: " + getName() + " 이 " + width
				+ " x " + height);
	}

	@Override
	public void show() {
		Gdx.app.log(PugGame.LOG, "화면을 보여줌: " + getName());
	}

	@Override
	public void hide() {
		Gdx.app.log(PugGame.LOG, "화면을 숨김: " + getName());
	}

	@Override
	public void pause() {
		Gdx.app.log(PugGame.LOG, "화면을 멈춤: " + getName());
	}

	@Override
	public void resume() {
		Gdx.app.log(PugGame.LOG, "화면을 재개: " + getName());
	}

	@Override
	public void dispose() {
		Gdx.app.log(PugGame.LOG, "화면을 반환: " + getName());
	}

}

AbstractScreen을 상속받아 SplashScreen을 구현, show함수만 구현하면 되고, 나머진 구현하지 않아도 알아서 AbstractScreen에서 찾아 실행하게 된다.

package com.dpug.puggame.screen;

import com.badlogic.gdx.Gdx;
import com.dpug.puggame.PugGame;

public class SplashScreen extends AbstractScreen {

	public SplashScreen(PugGame game) {
		super(game);
	}

	@Override
	public void show() {
		super.show();
		Gdx.app.log(PugGame.LOG, "스플래쉬 화면 show 실행: " + getName());
	}

}


이제 실행하면, 여전히 검은화면만 출력되지만 console창에 다음과 같이 출력되게 된다. 상속구조로 인해 AbstractScreen과 SplashScreen에서 두 번 출력되는 로그도 있지만 이제 show()만 꾸미면 무언가 화면에 보이게 될 것 같아보인다.