← Log

I am Ironman: 프로젝트 세팅

I am Ironman 게임 개발기· 2 / 7
  1. 1 — I am Ironman: 프로젝트 소개
  2. 2 — I am Ironman: 프로젝트 세팅
  3. 3 — I am Ironman: 게임 화면 구현
  4. 4 — I am Ironman: 콘텐츠 모션과 애니메이션
  5. 5 — I am Ironman: 콘텐츠 물리 충돌 처리
  6. 6 — I am Ironman: 게임 씬 구성
  7. 7 — I am Ironman: 게임 배포와 프로젝트 점검

Phaser.js 프로젝트는 기존에 사용 중인 프로젝트 내부에 생성하고 레포지토리도 그대로 유지했다. Pygame 로 개발 당시 1개의 메인 파일에 모든 코드를 작성했기에 관리 상 문제가 없고 오히려 버전 관리로서 그대로 두는 것이 좋을 것 같았다.

I am Ironman

이번 사이드 프로젝트 개발 시 <중점> 을 둔 부분은,

  • 최대한 기능적으로 분리가 가능한 요소를 클래스로 모듈화하고, 역할을 논리적으로 분배한다.
  • 유지 관리 측면에서 기능에 대한 주석을 정확하게 기입한다.
  • 가독성 측면에서 클래스 및 메서드의 명칭에서 일관성을 유지하고 불필요한 코드는 제거한다.

프로젝트 구조

아래는 게임 기본 사항 구현이라는 목표의 최종 디렉토리 구조이다.

assets
├─ images 이미지
├─ sounds 효과음
├─ fonts 폰트

src
├─ index.html 게임이 렌더링될 페이지 정의
├─ main.ts 전체 게임의 초기화 설정하는 진입점
├─ scenes 게임
├─ handlers 게임 이벤트 처리 기능 관리
├─ objects 게임 콘텐츠 정의
├─ managers 게임 콘텐츠의 상태 기능 관리(objects 클래스의 객체 관리)
├─ config.ts 게임 요소 설정
├─ enum.ts enum 타입 설정
└─ ...
  • 기본적으로 진입점(main.ts)에서 Phaser.js의 Phaser.Game를 이용해 게임을 실행하며,
  • 게임 구현은 Phaser.Scene을 상속받은 각 씬 클래스(scenes)에서 수행한다.
  • 게임 화면에 표시되는 콘텐츠들은 Phaser.GameObjects.Image 등을 상속받아 정의된 클래스(objects)에 의해 객체로 생성되어,
  • 별도의 상속을 받지 않은 기능 관리(managers), 이벤트 처리(handlers)의 기능 처리를 받게된다.

프로젝트 세팅

기본적인 세팅은 크게 게임 개발을 위한 게임 라이브러리(Phaser.js) 와 빌드 도구(Webpack) 두 부분으로 나눌 수 있다.

Phaser.js 세팅

먼저 라이브러리를 설치한다.

npm install phaser

라이브러리 설치 후 게임 화면을 렌더링해 실행할 수 있도록 준비한다.

  • 게임 실행 및 렌더링 웹페이지

    <!-- index.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>I am Ironman</title>
    </head>
    <body>
    </body>
    </html>
    * <script>로 게임 파일(.js)을 불러오지 않는 이유
    Phaser의 튜토리얼에 따르면 index.html에 <script>로 JavaScript 작성하거나 파일을 로드하도록 안내하는데,
    번들러(Webpack)를 사용할 경우 플러그인(html-webpack-plugin)이 번들 파일 로드가 포함된 HTML 파일에 생성하기 때문에
    게임이 중복으로 실행되는 문제가 생긴다.
  • 게임 초기화 및 실행

    // main.ts
    import Phaser from 'phaser';
    import PlayScene from './scenes/playScene';
    
    const config: Phaser.Types.Core.GameConfig = {
      type: Phaser.AUTO,
      width: 1024, // 캔버스 너비
      height: 600, // 캔버스 높이
      scene: [PlayScene], // 게임 씬 모음
      physics: {
        default: 'arcade', // 게임 엔진
        arcade: {
          gravity: { x: 0, y: 0 }, // 게임 중력
        },
      },
      fps: {
        target: 60, // 기준 프레임 수
        min: 30, // 최소 프레임 수
      },
      input: {
        keyboard: true,
      },
    };
    
    const game = new Phaser.Game(config); // 게임 초기화 및 실행
  • 게임 화면에 표시될 씬

    // playScene.ts
    import Phaser from 'phaser';
    
    export default class PlayScene extends Phaser.Scene {
    
      constructor() {
        super({ key: 'PlayScene' });
      }
    
      preload() {} // 자산(이미지, 사운드 등) 로드 [씬 로드 시 호출]
    
      create() {} // 콘텐츠 객체 생성 [씬 실행 시 호출]
    
      update() {} // 게임 로직 업데이트 [매 프레임마다 호출]
    }

Webpack 세팅

개발한 게임은 배포까지 진행할 것이기 때문에 빌드 도구가 필요하다. 가장 익숙한 번들러인 Webpack을 설치한다.

npm install --save-dev webpack webpack-cli webpack-dev-server
  • webpack: 빌드 도구
  • webpack-cli: 웹팩 명령어 프롬프트
  • webpack-dev-server: 개발 서버
* 로컬에서 빌드 버전을 실행해보기 위해 http-server도 필요할 수 있다.

필요에 따라 빌드 시 추가적으로 필요한 기능 플러그인도 함께 설치한다.

npm install --save-dev clean-webpack-plugin html-webpack-plugin copy-webpack-plugin
  • clean-: 빌드 시 이전 빌드 결과물 삭제
  • html-: 번들 결과물을 포함하는 HTML 파일 생성
  • copy-: 특정 파일 및 디렉토리 빌드 결과물에 포함 복사(정적 파일에 사용)

설치 후 번들러 설정을 준비한다.

  • Webpack 설정
    // webpack.config.js
    const path = require('path');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    
    module.exports = {
      mode: 'production', // 프로덕션 모드로 최적화 및 압축
      entry: './src/main.ts', // 애플리케이션의 시작점
      output: {
        filename: 'main.js', // 번들 파일명
        path: path.resolve(__dirname, 'dist'), // 번들 파일 위치
        publicPath: '/', // 외부에서의 번들 파일 경로
      },
      module: {
        rules: [
          {
            test: /\.ts$/, // TypeScript 파일 처리 규칙
            use: 'ts-loader', // TypeScript -> JavaScript
            exclude: /node_modules/,
          },
          {
            test: /\.(png|jpg|gif)$/, // 이미지 파일 처리 규칙
            type: 'asset/resource',
            generator: {
              filename: 'assets/images/[name][ext]', // 이미지 파일 저장 경로
            },
          },
        ],
      },
      resolve: {
        extensions: ['.ts', '.js'],
      },
      plugins: [
        new CleanWebpackPlugin(), // dist 청소
        new HtmlWebpackPlugin({ // html 생성
          template: 'src/index.html',
        }),
        new CopyWebpackPlugin({ // 특정 파일 복사
          patterns: [
            {
              from: 'assets', // 복사할 원본 위치
              to: 'assets', // 복사될 위치
            },
          ],
        }),
      ],
      devServer: { // 개발 서버에서의 설정
        static: {
          directory: path.join(__dirname, 'assets'), // 정적 파일 위치
        },
        compress: true,
        port: 8080,
        hot: true, // 코드 변경 시 변경된 모듈만 즉시 업데이트
      },
    };

스크립트 설정은 아래와 같이 두면 된다.

// package.json
...

"scripts": {
  "build": "webpack --mode production",
  "start": "http-server dist",
  "dev": "webpack serve --mode development"
},

게임 실행

개발 서버를 실행하면 화면에 검정색 캔버스가 렌더링 되는데,
<canvas> 태그로 채워진 것을 확인할 수 있다.

I am Ironman

참고 자료

  • [1] Getting Started with Phaser 3
  • [2] [Webpack] webpack-dev-server가 두 번 실행되는 이유
목차