Phaser.js: JavaScript 기반 게임 개발 프레임워크

김현조·2023년 5월 7일
7
post-thumbnail

Phaser.js란?

초기 JavaScript는 웹브라우저에 인터렉티브 요소를 추가하기 위해 개발된 경량의 스크립팅 언어였습니다. 그러나 현재는 서버, 모바일, 게임 등의 개발에도 사용되며 그 위상을 넓히고 있습니다. 예를 들어 “뱀파이어 서바이벌”이라는 1인 개발게임은 일반적인 게임 개발엔진이 아닌 JavaScript로 개발되었습니다. 이를 가능하게 해준 것이 바로 Phaser.js입니다. Phaser.js는 Canvas API를 랩핑한 JavaScript 기반 게임 개발 프레임워크입니다. HTML5에서 게임을 개발할 수 있도록 도와주며 데스크탑과 모바일에서 모두 사용 가능합니다. Phaser.js의 기본적인 config는 다음과 같습니다.

const config: {
    width: number; // canvas 너비 (반응형의 경우 window.innerWidth)
    height: number; // canvas 높이 (반응형의 경우 window.innerHeight)
    backgroundColor: number; 
    scene: typeof Scene[]; 
    pixelArt: boolean;
    physics: {
        default: string;
        arcade: {
            debug: boolean;
        };
    };
}

구성 요소

Phaser.js는 크게 Scene과 Sprite라는 객체와 preload, create, upload라는 메서드를 중심으로 구성되어 있습니다. 각각의 역할은 다음과 같습니다.

  • Scene
    • 게임 맵, 화면 하나를 나타내는 단위로 웹페이지 하나와 비슷한 개념입니다.
  • Sprite
    • 캐릭터, 무기와 같은 요소를 뜻하며 스프라이트 이미지 여러개를 연속으로 보여줌으로써 애니메이션을 구성할 수 있습니다.
  • preload
    • asset을 미리 불러오는 메서드입니다,
    • LoadingScene을 구성하고 preload 메서드를 통해 asset을 불러오는 중간에 보여질 화면을 정의할 수 있습니다.
  • create
    • 애니메이션, 스프라이트 등을 화면에 추가하는 메서드입니다.
  • update
    • scene이 실행되는 동안 60fps(1초에 60프레임)의 속도로 매 프레임마다 호출됩니다.
    • update 이벤트에 리스너를 달아서 Sprite가 매 프레임마다 특정 행위를 실행하도록 구현할 수 있습니다.

Scene 만들기

게임 중, 로딩, 게임 종료 등의 상황에 맞춰 Scene을 정의하고 config에 추가해야 합니다. Scene은 다음과 같이 Phaser.Scene을 extend하여 class를 정의하고 config에 추가하는 방식으로 생성할 수 있습니다.

src/scenes/GameScene.js

export default class GameScene extends Phaser.Scene {
  constructor() {
    super();
  }

  preload() {}
	create() {}
	update() {}
}

src/config.js

import GameScene from "./scenes/GameScene";

export const config = {
  type: Phaser.AUTO,
  parent: "phaser-example",
  width: 800,
  height: 600,
  scene: [GameScene],
};

Sprite 만들기

Sprite를 도형을 이용해 만들 수도 있지만 대부분의 게임은 이미지 asset을 활용할 것입니다. 이미지를 이용하여 Sprite를 만들기 위해서는 이미지 preload → create의 과정을 거쳐야 합니다. 먼저 scene의 preload 메서드에서 이미지를 로드합니다.

export default class GameScene extends Phaser.Scene {
  constructor() {
    super();
  }

  preload() {
		this.load.image("arrow", arrowImg);
	}

	// ...
}

이후 scene의 create 메서드에서 해당 이미지를 add 해줍니다.

export default class GameScene extends Phaser.Scene {
  create() {
		this.add.image(200, 450, "arrow");
		this.arrow.setScale(0.15); // 사이즈 배수 조절
	}
}

Sprite 움직이기

활이 포물선을 그리며 이동하도록 구현하려 합니다. 이는 이동할 경로를 그려주고 update함수에서 해당 경로의 x, y값을 따라 이동시키는 방식으로 구현 가능합니다. 먼저 이동 경로를 그려주도록 하겠습니다.

export default class GameScene extends Phaser.Scene {
  create() {
		this.graphics = this.add.graphics();

    this.path = { t: 0, vec: new Phaser.Math.Vector2() };

    const startPoint = new Phaser.Math.Vector2(100, 500);
    const controlPoint1 = new Phaser.Math.Vector2(100, 200);
    const endPoint = new Phaser.Math.Vector2(700, 500);

    this.curve = new Phaser.Curves.QuadraticBezier(
      startPoint,
      controlPoint1,
      endPoint
    );

    this.tweens.add({
      targets: this.path,
      t: 1,
      ease: "Sine.easeInOut",
      duration: 1000,
      yoyo: false,
      repeat: 0,
    });
	}

	update() {
		this.graphics.clear();
    this.graphics.lineStyle(1, 0x00ff00, 1);

    this.curve.draw(this.graphics);
	}
}

다음과 같은 curve를 확인할 수 있습니다.

이어서 arrow를 해당 경로에 맞게 이동시켜줍니다.

import { config } from "../config";
import arrowImg from "../assets/arrow.png";

export default class GameScene extends Phaser.Scene {
  constructor() {
    super();

    this.arrow;
  }

  preload() {
    this.load.image("arrow", arrowImg);
  }

  create() {
    this.arrow = this.add.image(200, 450, "arrow");
    this.arrow.setScale(0.15);

    this.graphics = this.add.graphics();

    this.path = { t: 0, vec: new Phaser.Math.Vector2() };

    const startPoint = new Phaser.Math.Vector2(100, 500);
    const controlPoint1 = new Phaser.Math.Vector2(100, 200);
    const endPoint = new Phaser.Math.Vector2(700, 500);

    this.curve = new Phaser.Curves.QuadraticBezier(
      startPoint,
      controlPoint1,
      endPoint
    );

    this.tweens.add({
      targets: this.path,
      t: 1,
      ease: "Sine.easeInOut",
      duration: 1000,
      yoyo: false,
      repeat: 0,
    });
  }

  update() {
    this.graphics.clear();

    this.curve.getPoint(this.path.t, this.path.vec);
    this.arrow.setPosition(this.path.vec.x, this.path.vec.y);
  }
}

각도 변경하기

하지만 위의 코드로는 화살이 어색하게 이동하기만 할뿐이어서 각도의 변경이 필요합니다. 이 또한 update 함수에 매 프레임마다 각도를 바꾸도록 작성하여 구현할 수 있습니다.

	  update() {
        // ...
        // 각도 변경
        this.arrow.setAngle(this.arrow.angle + 1.5);

        // 도착 지점오면 arrow 삭제
        if (this.arrow.x === this.endPoint[0] && this.arrow.y === this.endPoint[1])
          this.arrow.destroy();
  }

위의 코드까지 더한 결과는 다음과 같습니다.

이와 같은 방법으로 Phaser.js를 활용하면 단순히 canvas API를 활용하는 경우보다 편리하고 폭넓은 게임 구현이 가능합니다. 관련 예시 등을 아래에서 확인해볼 수 있습니다.

출처

0개의 댓글