HTML5GAME :: Phaser Js 로 Monster Wants Candy 만들기

달력

52024  이전 다음

  • 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
  • 31

HTML5 게임 엔진 인 Phaser로 만든 다중 플랫폼 게임 인 Monster Wants Candy의 소스를 분석해 보겠습니다. 이 방법으로 엔진에 대한 실질적인 소개를 얻게되며 자신 만의 HTML5 모바일 및 브라우저 게임을 제작하는 데 사용할 수있는 개념을 배우게됩니다.


소개

HTML5 게임을 만들려면 프레임 워크 또는 엔진을 선택하는 것이 좋습니다. 물론 평범한 JavaScript로 할 수도 있지만 프레임 워크를 사용하면 개발 속도가 크게 빨라지고 편하게 개발할수 있습니다.


Phaser는 헌신적 인 커뮤니티가있는 최신 HTML5 게임 개발 프레임 워크로, 아직 들어 본 적이 없다면 반드시 시도해야합니다.


Phaser 란 무엇입니까?

Phaser는 데스크톱 및 모바일 HTML5 게임을 제작하기위한 프레임 워크입니다. 그것은 Photon Storm에 의해 만들어졌습니다. 이 프레임 워크는 순수한 JavaScript로 작성되었지만, 어떤 경우에는 TypeScript 정의 파일을 포함합니다.


Phaser 코드는 Flash gamedev 플랫폼 Flixel을 기반으로하므로 Flash 개발자는 바로 느낄 수 있습니다. 내부적으로 Pixi.js 엔진을 사용하여, 가능한 경우 Canvas 또는 WebGL을 사용하여 화면의 모든 부분을 렌더링합니다.



그것은 아주 새롭지 만 HTML5GameDevs 포럼에서 활발한 커뮤니티의 도움으로 빠르게 성장하고 있습니다. 사용할 수있는 자습서와 기사가 이미 많이 있으며, 공식 문서와 개발 중에 매우 도움이 될 수있는 수많은 예제를 확인할 수도 있습니다. 오픈 소스이며 GitHub에서 무료로 사용할 수 있으므로 소스 코드로 직접 들어가서 배울 수 있습니다.


Monster Wants Candy 무엇입니까?

게임을 제작할 때 먼저 핵심 아이디어를 생각하고 작동하는 프로토 타입을 신속하게 설정하려고합니다. 이 사례 연구에서는 Monster Wants Candy라고 불리는 게임의 간단한 데모부터 시작합니다.


프로토 타입으로 작업하는 대신 프로젝트의 구조를 먼저 보여 주므로 전체 아이디어를 이해할 수 있습니다. 그런 다음 Assets로드에서 부터 메인 메뉴 제작 및 실제 게임 루프에 이르기까지 게임의 개발 단계를 거치게됩니다. 지금 Monster Wants Candy 데모를 보시면 우리가 함께 일하는 것을 보실 수 있습니다.


코딩은 Enclave Games의 Andrzej Mazur가 담당했으며  모든 그래픽 Assets은 Blackmoon Design의 Robert Podgórski가 만들었습니다.



Monster Wants Candy의 이야기는 간단합니다. 사악한 왕이 당신의 사랑을 납치했고 그녀를 되찾기 위해 충분한 사탕을 모아야합니다. 게임 플레이도 간단합니다 : 과자가 떨어지고 있고 그들을 먹을 수 있습니다. 캔디를 먹으면 얻는 점수가 많을수록 좋습니다. 당신이 무엇이든 놓치고 화면에서 떨어지면 생명을 잃고 게임은 끝납니다.


보시다시피 매우 단순한 게임이지만 구조가 완벽합니다. 프레임 워크의 가장 중요한 용도는 이미지로드, 스프라이트 렌더링 및 사용자 활동 감지와 같은 작업에 해당합니다. 또한 코드를 복사하고 코드를 시작하고 자신 만의 게임을 만들 수있는 좋은 출발점이됩니다.


프로젝트 설정 및 구조

Phaser를 시작하는 방법에 대해 프레임 워크 작성자가 직접 작성한 이 유용한 기사를 읽거나 GitHub phaser.min.js 파일을 프로젝트 디렉토리에 복사하여 처음부터 작업을 시작할 수 있습니다. 

IDE가 필요하지 않습니다. 브라우저에서 index.html 파일을 실행하기 만하면 소스 코드에서 변경 한 내용을 즉시 볼 수 있습니다.


우리 프로젝트 폴더에는 HTML5 구조와 필요한 모든 JavaScript 파일을 포함하는 index.html 파일이 들어 있습니다. 두 가지 하위 폴더가 있습니다. img는 모든 그래픽 애셋을 저장하고 src는 게임의 소스 코드를 저장합니다.


폴더 구조가 어떻게 보이는지는 다음과 같습니다.



src 폴더에는 JavaScript 파일이 있습니다. 이것은 마술이 일어나는 곳입니다. 이 튜토리얼에서는 그 폴더에있는 모든 파일의 목적과 내용을 설명합니다.


이 튜토리얼의 GitHub 에서 각 파일의 소스를 볼 수 있습니다.


Index.html

index.html 파일부터 시작하겠습니다. 기본 HTML5 웹 사이트처럼 보이지만 텍스트와 많은 HTML 요소를 추가하는 대신, Canvas 요소로 렌더링하는 Phaser 프레임 워크를 초기화합니다.


<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title>Monster Wants Candy demo</title>

    <style> body { margin: 0; background: #B4D9E7; } </style>

    <script src="src/phaser.min.js"></script>

    <script src="src/Boot.js"></script>

    <script src="src/Preloader.js"></script>

    <script src="src/MainMenu.js"></script>

    <script src="src/Game.js"></script>

</head>

<body>

<script>

(function() {

    var game = new Phaser.Game(640, 960, Phaser.AUTO, 'game');

    game.state.add('Boot', Candy.Boot);

    game.state.add('Preloader', Candy.Preloader);

    game.state.add('MainMenu', Candy.MainMenu);

    game.state.add('Game', Candy.Game);

    game.state.start('Boot');

})();

</script>

</body>

</html>


doctype을 가진 HTML 문서의 일반적인 구조와 <head>의 일부 정보 : charset 인코딩, 페이지 제목 및 CSS 스타일을 정의합니다. 

일반적으로 우리는 모든 스타일을 넣은 외부 CSS 파일을 참조 할 것이지만 여기서는 필요하지 않습니다. 앞에서 언급했듯이 모든 것이 Canvas 요소에 렌더링되므로 스타일을 지정할 HTML 요소가 없습니다. .


마지막으로해야 할 일은 Phaser.min.js 파일에서부터 Phaser 프레임 워크의 소스 코드와 함께 모든 자바 스크립트 파일을 게임의 코드가 포함 된 모든 파일에 포함시키는 것입니다. 모든 자바 스크립트 파일을 하나로 결합하여 브라우저의 요청 수를 줄이는 것이 좋으므로 게임로드가 빨라지지만 이 자습서에서는 별도로 로드 할 것입니다.


<body> 태그의 내용으로 이동하여 프레임 워크를 초기화하고 게임을 시작하십시오. 이 코드는 자체 호출 함수 내에 있습니다. 첫 번째 줄은 다음과 같습니다.

var game = new Phaser.Game(640, 960, Phaser.AUTO, 'game');


이 코드는 몇 가지 기본값으로 페이저를 초기화합니다 :


640은 게임의 캔버스 너비 (픽셀)이고 960은 게임의 높이입니다.


Phaser.AUTO는 Canvas에 게임을 렌더링하는 방법을 프레임 워크에 알려줍니다. 세 가지 옵션이 있습니다 : CANVAS, WEBGL, AUTO. 

첫 번째는 캔버스의 2D 컨텍스트에서 게임을 실행합니다. 

두 번째는 가능한 경우 WebGL을 사용하여 렌더링합니다 (주로 현재 데스크톱이지만 모바일 지원은 개선되고 있습니다). 

세 번째는 WebGL이 지원이되면 WebGL, 그렇지 않으면 2D 캔버스 렌더링이 사용됩니다.


프레임 워크 초기화는 game이라는 단일 객체에 지정되며, Phaser 인스턴스를 참조 할 때 사용하게됩니다.


다음 줄은 게임에 상태를 추가하는 것입니다.

game.state.add('Boot', Candy.Boot);


'Boot'는 상태 이름이고 Candy.Boot는 그 상태를 시작할 때 실행될 객체입니다 (다음 단계에서 정의 됨). 

Boot (구성), Preloader (자산로드), MainMenu (우리 게임의 메인 메뉴) 및 Game (게임의 기본 루프)에 대한 상태를 추가합니다. 

마지막 줄인 game.state.start ( 'Boot')는 Boot 상태를 시작하여 Candy.Boot 객체의 적절한 함수가 실행되도록합니다.


보시다시피, 하나의 주요 자바 스크립트 게임 객체가 만들어졌으며 많은 다른 객체가 특수 목적으로 할당되었습니다. 우리 게임에서는 Boot, Preloader, MainMenu 및 Game 객체가 게임 상태가되며 프로토 타입을 사용하여 정의합니다. 프레임 워크 자체 (preload (), create (), update () 및 render ()) 용으로 예약 된 객체에는 몇 가지 특수 함수 이름이 있지만, 자체 startGame (), spawnCandy managePause ()). 이 모든 것을 잘 이해하지 못한다면 걱정하지 마십시오. 나중에 코드 예제를 사용하여 모든 것을 설명 할 것입니다.


게임

이제 Boot, Preloader 및 MainMenu 상태를 잊어 버리세요. 자세한 내용은 나중에 설명합니다. 부트 상태가 게임의 기본 설정을 처리하고, Preloader가 모든 그래픽 Assets을 로드하며 MainMenu가 게임을 시작할 수 있는 화면을 보여줍니다.


게임 자체에 초점을 맞추고 Gamestate의 코드가 어떻게 되어있는지 봅시다. 전체 Game.js 코드를 살펴보기 전에 개발자의 관점에서 게임 자체의 개념과 로직의 가장 중요한 부분에 대해 이야기 해 봅시다.


세로 모드


이 게임은 세로 모드로 재생됩니다. 즉, 플레이어가 휴대 전화를 세로로 들고 게임을 재생합니다.



이 모드에서는 화면의 너비가 가로보다 커지는 가로 모드와 달리 화면의 높이가 너비보다 큽니다. 몬스터 원츠 캔디 (Monster Wants Candy)와 같은 세로 모드에서 더 잘 작동하는 게임 종류 (Craigen과 같은 플랫폼 게임 포함) 및 두 모드에서 작동하는 일부 유형이 있습니다. 일반적으로 가로 모드에서 더 잘 작동하는 유형이 있습니다. 그러한 게임을 코드화 하십시오.


Game.js


game.js 파일의 소스 코드를 살펴보기 전에 구조에 대해 이야기 해 보겠습니다. 우리를 위해 창조 된 세계가 있으며, 그 안에는 사탕을 잡는 플레이어 캐릭터가 있습니다.


게임 세계 : 괴물 뒤의 세상은 움직이지 않습니다. 배경에 Candyland의 이미지가 있습니다. 배경에서 괴물을 볼 수 있으며, 사용자 인터페이스도 있습니다.


플레이어 캐릭터 : 이 데모는 매우 간단하고 기본이기 때문에 작은 괴물은 사탕을 기다리는 것 외에는 아무 것도하지 않습니다. 플레이어의 주요 임무는 사탕을 수집하는 것입니다. 
캔디 : 게임의 핵심 메카닉은 최대한 많은 캔디를 잡는 것입니다. 사탕은 화면의 상단 가장자리에서 출현하며, 플레이어는 떨어지는대로 클릭해야 합니다. 사탕이 화면 하단에서 떨어지면 제거되고 플레이어 캐릭터가 손상을 입습니다. 우리는 생명 시스템을 구현하지 않았기 때문에 게임이 즉시 종료되고 적절한 메시지가 표시됩니다.
이제 Game.js 파일의 코드 구조를 살펴 보겠습니다.

Candy.Game = function(game) {

    // ...

};

Candy.Game.prototype = {

    create: function() {

        // ...

    },

    managePause: function() {

        // ...

    },

    update: function() {

        // ...

    }

};

Candy.item = {

    spawnCandy: function(game) {

        // ...

    },

    clickCandy: function(candy) {

        // ...

    },

    removeCandy: function(candy) {

        // ...

    }

};


Candy.Game 프로토 타입에는 다음 세 가지 기능이 정의되어 있습니다.

- create ()는 초기화를 처리합니다.

- managePause ()는 게임을 일시 중지하고 일시 정지 해제합니다.


- update ()는 틱마다 주 게임 루프를 관리합니다.


하나의 캔디를 나타내는 item이라는 편리한 객체를 만들 것입니다. 다음과 같은 유용한 함수가 있습니다.

- spawnCandy ()는 게임 세계에 새로운 캔디를 추가합니다.

- clickCandy ()는 사용자가 캔디를 클릭하거나 탭하면 시작됩니다.

- removeCandy ()는 그것을 제거합니다.


다음 코드를 봅시다.

Candy.Game = function(game) {

    this._player = null;

    this._candyGroup = null;

    this._spawnCandyTimer = 0;

    this._fontStyle = null;

    Candy._scoreText = null;

    Candy._score = 0;

    Candy._health = 0;

};


여기서 우리는 나중에 코드에서 사용할 모든 변수를 설정하고 있습니다.


this._name을 정의함으로써, 변수의 사용을 Candy.Game 범위로 제한합니다. 즉, 다른 상태에서는 사용할 수 없다는 의미입니다. 즉, 필요하지 않으므로 왜 노출합니까?


Candy._name을 정의하면 다른 상태 및 객체에서 이러한 변수를 사용할 수 있으므로 예를 들어 Candy._score를 Candy.item.clickCandy () 함수에서 사용 수 있습니다.


객체는 null로 초기화되고 계산에 필요한 변수는 0으로 초기화됩니다.


Candy.Game.prototype의 내용으로 이동해서:

create: function() {

    this.physics.startSystem(Phaser.Physics.ARCADE);

    this.physics.arcade.gravity.y = 200;


    this.add.sprite(0, 0, 'background');

    this.add.sprite(-30, Candy.GAME_HEIGHT-160, 'floor');

    this.add.sprite(10, 5, 'score-bg');

    this.add.button(Candy.GAME_WIDTH-96-10, 5, 'button-pause', this.managePause, this);


    this._player = this.add.sprite(5, 760, 'monster-idle');

    this._player.animations.add('idle', [0,1,2,3,4,5,6,7,8,9,10,11,12], 10, true);

    this._player.animations.play('idle');


    this._spawnCandyTimer = 0;

    Candy._health = 10;


    this._fontStyle = { font: "40px Arial", fill: "#FFCC00", stroke: "#333", strokeThickness: 5, align: "center" };

    Candy._scoreText = this.add.text(120, 20, "0", this._fontStyle);


    this._candyGroup = this.add.group();

    Candy.item.spawnCandy(this);


},



create () 함수의 시작 부분에서 우리는 ARCADE 물리 시스템을 설정했습니다. Phaser에서는 몇 가지가 있지만 가장 간단한 방법입니다. 그 후, 게임에 수직 중력을 추가합니다. 그런 다음 배경, 괴물이 서있는 바닥 및 점수 UI 배경을 추가합니다. 우리가 추가하는 네 번째 항목은 일시 중지 버튼입니다. Candy.Preloader ()에 정의되어 있지만 게임 코드 전체에서 사용할 수있는 Candy.GAME_WIDTH 및 Candy.GAME_HEIGHT 변수를 사용하고 있습니다.


그런 다음 플레이어의 아바타 인 괴물을 만듭니다. 프레임 있는 스프라이트 (스프라이트 시트)입니다. 그가 침착하게 서 있고 호흡하는 것처럼 보이게하려면, 우리는 그를 움직일 수 있습니다.


animations.add () 함수는 사용 가능한 프레임에서 애니메이션을 만들고 함수는 다음 네 개의 매개 변수를 사용합니다.

- 애니메이션의 이름 (나중에 참조 할 수 있습니다)

- 우리가 사용하고자 하는 모든 프레임이 있는 테이블 (우리가 원하는 경우에만 사용할 수 있습니다)

- 프레임 속도

- 애니메이션을 반복하여 무한정 재생할지 여부를 지정하는 플래그.

애니메이션을 시작하려면 animations.play () 함수를 지정된 이름으로 사용해야합니다.


그런 다음 spawnCandyTimer를 0 (카운트 준비)으로 설정하고 괴물의 상태를 10으로 설정합니다.



텍스트 스타일 지정하기

다음 두 줄은 화면에 텍스트를 보여줍니다. this.add.text () 함수는 네 개의 매개 변수를 사용합니다. 

화면의 왼쪽 및 위쪽 절대 위치, 실제 텍스트 문자열 및 config 객체입니다. config 객체의 CSS와 유사한 구문을 사용하여 텍스트 서식을 지정할 수 있습니다.


우리 글꼴의 설정은 다음과 같습니다.

this._fontStyle = { 

    font: "40px Arial", 

    fill: "#FFCC00", 

    stroke: "#333", 

    strokeThickness: 5, 

    align: "center"


};


이 경우 글꼴은 Arial, 높이가 40 픽셀, 색상이 노란색, 획이 정의되어 있습니다 (색상 및 두께). 텍스트는 가운데 맞춤입니다.


그런 다음 candyGroup을 정의하고 첫 번째 캔디를 생성합니다.



게임 일시 중지


일시 중지 기능은 다음과 같습니다.

managePause: function() {

    this.game.paused = true;

    var pausedText = this.add.text(100, 250, "Game paused.\nTap anywhere to continue.", this._fontStyle);

    this.input.onDown.add(function(){

        pausedText.destroy();

        this.game.paused = false;

    }, this);


},


일시 중지 버튼을 클릭 할 때마다 this.game.paused의 상태를 true로 변경하고, 해당 프롬프트를 플레이어에 표시하고, 플레이어의 클릭 또는 화면의 탭에 대한 이벤트 리스너를 설정합니다. 해당 클릭 또는 탭이 감지되면 텍스트를 제거하고 this.game.paused를 false로 설정합니다.


게임 개체의 일시 중지 된 변수는 게임에서 애니메이션이나 계산을 중지하기 때문에 Phaser에서 특별하므로 게임을 일시 중지 할 때까지 모든 것이 고정되어 false로 설정됩니다.



업데이트 루프


update () 함수 이름은 Phaser의 예약어 중 하나입니다. 그 이름을 가진 함수를 작성할 때, 그것은 게임의 모든 프레임에서 실행될 것입니다. 다양한 조건에 따라 계산을 관리 할 수 있습니다.

update: function() {

    this._spawnCandyTimer += this.time.elapsed;

    if(this._spawnCandyTimer > 1000) {

        this._spawnCandyTimer = 0;

        Candy.item.spawnCandy(this);

    }

    this._candyGroup.forEach(function(candy){

        candy.angle += candy.rotateMe;

    });

    if(!Candy._health) {

        this.add.sprite((Candy.GAME_WIDTH-594)/2, (Candy.GAME_HEIGHT-271)/2, 'game-over');

        this.game.paused = true;

    }

}

게임 세계의 모든 틱은 이전 틱 이후 경과 된 시간을 spawnCandyTimer 변수에 추가하여 추적합니다. if 문은 타이머를 재설정하고 게임 세계에 새 캔디를 스폰 할 시간인지 여부를 확인합니다. 

매 초마다 이렇게 처리합니다 (즉, spawnCandyTimer가 1000 밀리 초를 경과 할 때마다). 그런 다음 forEach를 사용하여 내부에있는 모든 캔디 객체가있는 캔디 그룹을 반복합니다.

캔디의 angle 변수에 추가합니다(캔디 객체의 rotateMe 값에 저장 됨). 그들은 떨어지는 동안 각각이 고정 된 속도로 회전합니다. 마지막으로 생명 상태가 0으로 떨어졌는지 확인하고, 0이면 화면 위에 게임오버을 표시하고 게임을 일시 중지합니다.



캔디 이벤트 관리


캔디 로직을 메인 게임과 분리하기 위해 우리는 spawnCandy (), clickCandy () 및 removeCandy ()와 같은 함수를 포함하는 item이라는 객체를 사용합니다. 사탕과 관련된 변수 중 일부는 Game 개체에 사용하기 쉽도록 유지하는 반면 다른 항목은 더 나은 유지 관리를 위해 항목 기능에만 정의됩니다.

spawnCandy: function() {

    var dropPos = Math.floor(Math.random()*Candy.GAME_WIDTH);

    var dropOffset = [-27,-36,-36,-38,-48];

    var candyType = Math.floor(Math.random()*5);

    var candy = game.add.sprite(dropPos, dropOffset[candyType], 'candy');

    candy.animations.add('anim', [candyType], 10, true);

    candy.animations.play('anim');


    game.physics.enable(candy, Phaser.Physics.ARCADE);

    candy.inputEnabled = true;

    candy.events.onInputDown.add(this.clickCandy, this);


    candy.checkWorldBounds = true;

    candy.events.onOutOfBounds.add(this.removeCandy, this);

    candy.anchor.setTo(0.5, 0.5);

    candy.rotateMe = (Math.random()*4)-2;

    game._candyGroup.add(candy);


},

이 함수는 세 가지 값을 정의하여 시작합니다.

- 캔디를 떨어 뜨리는 랜덤 화 된 x 좌표 (캔버스의 너비와 너비 사이)

- 높이 (우리는 사탕의 유형에 따라 나중에 결정 함)에 따라 사탕을 떨어 뜨리는 y 좌표,


- 무작위로 추출한 캔디 유형 (우리는 다섯 가지 다른 이미지를 사용합니다)


그런 다음, 위에서 정의한 시작 위치와 이미지를 사용하여 하나의 캔디를 스프라이트로 추가합니다. 이 블록에서 마지막으로 수행 할 작업은 캔디가 생성 될 때 사용할 새 애니메이션 프레임을 설정하는 것입니다.


다음으로 중력이 설정되면 화면 상단에서 자연스럽게 떨어질 수 있도록 물리 엔진 용 캔디 바디를 활성화합니다. 그런 다음 캔디의 클릭작업에 대한 이벤트 리스너를 설정합니다.


캔디가 화면 경계를 벗어날 때 이벤트를 발생 시키도록하려면 checkWorldBounds를 true로 설정하십시오. events.onOutOfBounds ()는 캔디가 화면을 벗어날때 호출 될 함수입니다. 그리고 removeCandy ()를 호출하도록합니다. 정확히 중간에 캔디에 앵커를 설정하여 축 주위로 앵커를 회전시켜 자연스럽게 회전합니다. 우리는 rotateMe 변수를 여기에 설정하여 update () 루프에서 이를 변경하면 사탕을 회전시킬 수 있습니다. -2와 +2 사이의 값을 선택합니다. 마지막 줄은 우리가 새로 만든 사탕을 캔디 그룹에 추가하여 모든 것을 반복 할 수 있도록합니다.


다음 함수 인 clickCandy ()로 넘어 갑시다.

clickCandy: function(candy) {

    candy.kill();

    Candy._score += 1;

    Candy._scoreText.setText(Candy._score);


},


하나의 캔디를 매개 변수로 사용하고 Phaser 메소드 kill ()을 사용하여 제거합니다. 또한 점수를 1 씩 늘리고 점수 텍스트를 업데이트합니다.


사탕을 재설정하는 것은 짧고 쉽습니다.

removeCandy: function(candy) {

    candy.kill();

    Candy._health -= 10;


},


캔디가 클릭되지 않고 화면 아래에 사라지면 removeCandy () 함수가 시작됩니다. 캔디 오브젝트가 제거되고 플레이어의 체력이 10만큼 감소합니다. (그는 처음에는 10 점이 있었기 때문에 떨어지는 캔디 한 점을 잃어 버리더라도 게임이 끝납니다.)



프로토 타입 및 게임 상태

게임 메커닉, 핵심 아이디어 및 게임 플레이의 모습에 대해 배웠습니다. 이제 화면의 크기 조정, 에셋로드, 버튼 누르기 관리 등 코드의 다른 부분을 볼 차례입니다.


우리는 이미 게임 상태에 대해 알고 있습니다. 그래서 게임의 상태를 정확히 보도록하겠습니다.


Boot.js


Boot.js는 게임 객체를 정의하는 JavaScript 파일입니다.

Boot.js 파일의 소스 코드는 다음과 같습니다.

var Candy = {};

Candy.Boot = function(game) {};

Candy.Boot.prototype = {

    preload: function() {

        this.load.image('preloaderBar', 'img/loading-bar.png');

    },

    create: function() {

        this.input.maxPointers = 1;

        this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

        this.scale.pageAlignHorizontally = true;

        this.scale.pageAlignVertically = true;

        this.scale.setScreenSize(true);

        this.state.start('Preloader');

    }


};


보시다시피, 우리는 게임을 위한 전역 객체를 생성하는 var Candy = {}로 시작하였습니다. 모든 것이 내부에 저장되므로 전역 네임 스페이스를 부 풀리지 않을 것입니다.


Candy.Boot = function (game) {}은 게임 객체를 매개 변수 (index.html의 프레임 워크로도 생성)로 받는 Boot ()라는 새로운 함수를 만듭니다 (index.html에서 사용됨).


Candy.Boot.prototype = {} 코드는 프로토 타입을 사용하여 Candy.Boot의 내용을 정의하는 방법입니다.

Candy.Boot.prototype = {

    preload: function() {

        // code

    },

    create: function() {

        // code

    }

};


앞에서 언급했듯이 Phaser의 기능에는 몇 가지 예약 된 이름이 있습니다. preload () 및 create ()는 두 가지입니다. preload ()는 모든 에셋을 로드하는 데 사용되며 create ()는 정확히 한 번 (preload () 후) 호출되므로 변수 정의 또는 스프라이트 추가와 같이 객체의 설정으로 사용될 코드를 배치 할 수 있습니다 .


우리의 Boot 객체에는 이 두 함수가 포함되어 있으므로 Candy.Boot.preload () 및 Candy.Boot.create ()를 각각 사용하여 참조 할 수 있습니다. Preload () 함수는 Boot.js 파일의 전체 소스 코드에서 볼 수 있듯이 프리 로더 이미지를 프레임 워크에 로드합니다.

preload: function() {

    this.load.image('preloaderBar', 'img/loading-bar.png');


},


this.load.image ()의 첫 번째 매개 변수는 로딩 바 이미지에 지정한 이름이고 두 번째 매개 변수는 프로젝트 구조의 이미지 파일에 대한 경로입니다.



Preload.js 파일에서 로드되는 다른 모든 이미지의 상태를 표시하는 로드바 이미지가 필요합니다. 그러므로 Boot.js에서 다른 모든 이미지보다 먼저 로드해야합니다.



비율 옵션

create () 함수는 입력 및 크기 조정을 위한 몇 가지 Phaser 설정을 포함합니다.

create: function() {

    this.input.maxPointers = 1;

    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

    this.scale.pageAlignHorizontally = true;

    this.scale.pageAlignVertically = true;

    this.scale.setScreenSize(true);

    this.state.start('Preloader');


}

input.maxPointers를 1로 설정하는 첫 번째 줄은 우리가 게임에서 필요로 하지 않기 때문에 멀티 터치를 사용하지 않을 것을 정의합니다.


scale.scaleMode 설정은 게임의 스케일링을 제어합니다. 사용 가능한 옵션은 EXACT_FIT, NO_SCALE 및 SHOW_ALL입니다. 그것들을 열거 해, 각각 0, 1, 또는 2의 값을 사용할 수 있습니다. 

첫 번째 옵션은 사용 가능한 모든 공간 (100 % 너비와 높이, 보존 비율 없음)으로 게임의 크기를 조정합니다. 

두 번째는 스케일링을 완전히 비활성화합니다. 

세 번째 플레이어는 게임이 주어진 차원에 맞는지 확인하지만 단편을 숨기지 않고 모든 내용이 화면에 표시됩니다 (비율은 그대로 유지됩니다).


scale.pageAlignHorizontally 및 scale.pageAlignVertically를 true로 설정하면 게임이 가로 및 세로로 정렬되므로 Canvas 요소의 왼쪽과 오른쪽에 같은 양의 여유 공간이 생깁니다. 상단과 하단도 동일합니다.


scale.setScreenSize (true)를 호출하면 크기 조절이 "활성화"됩니다.


마지막 줄인 state.start ( 'Preloader')는 다음 상태 (이 경우 Preloader 상태)를 실행합니다.



Preloader.js


방금 진행 한 Boot.js 파일에는 간단한 (한 줄짜리) preload () 함수와 create () 함수에 많은 코드가 있지만 Preloader.js는 완전히 다른 것처럼 보입니다. create () 함수는 모든 에셋이 로드 될 때 다른 상태로 이동하는 데 사용됩니다.


Preloader.js 파일의 코드는 다음과 같습니다.

Candy.Preloader = function(game){

    Candy.GAME_WIDTH = 640;

    Candy.GAME_HEIGHT = 960;

};


Candy.Preloader.prototype = {

    preload: function() {

        this.stage.backgroundColor = '#B4D9E7';

        this.preloadBar = this.add.sprite((Candy.GAME_WIDTH-311)/2,

            (Candy.GAME_HEIGHT-27)/2, 'preloaderBar');

        this.load.setPreloadSprite(this.preloadBar);


        this.load.image('background', 'img/background.png');

        this.load.image('floor', 'img/floor.png');

        this.load.image('monster-cover', 'img/monster-cover.png');

        this.load.image('title', 'img/title.png');

        this.load.image('game-over', 'img/gameover.png');

        this.load.image('score-bg', 'img/score-bg.png');

        this.load.image('button-pause', 'img/button-pause.png');


        this.load.spritesheet('candy', 'img/candy.png', 82, 98);

        this.load.spritesheet('monster-idle',

            'img/monster-idle.png', 103, 131);

        this.load.spritesheet('button-start',

            'img/button-start.png', 401, 143);

    },

    create: function() {

        this.state.start('MainMenu');

    }


};


이전 Boot.js 파일과 유사하게 시작됩니다. Preloader 객체를 정의하고 프로토 타입에 두 개의 함수 (preload () 및 create ())에 대한 정의를 추가합니다. Prototype 객체 안에는 두 개의 변수 인 Candy.GAME_WIDTH와 Candy.GAME_HEIGHT가 정의되어 있습니다. 이것들은 게임 화면의 기본 너비와 높이를 설정합니다. 이 너비와 높이는 코드의 다른 곳에서 사용될 것입니다.


preload () 함수의 처음 세 줄은 스테이지의 배경색을 설정하고 (# B4D9E7, 하늘색), 게임의 스프라이트를 표시하고, setPreloadSprite라는 특수 함수의 기본 색상으로 정의합니다 ) 이미지로딩 진행 상태를 나타냅니다.


add.sprite () 함수를 살펴 보겠습니다.

this.preloadBar = this.add.sprite((640-311)/2, (960-27)/2, 'preloaderBar');


보시다시피 세 가지 값을 전달합니다. 이미지의 절대 왼쪽 위치 (화면의 중심은 스테이지의 너비에서 이미지의 너비를 빼고 결과를 반으로 나눔으로써 얻습니다.), 이미지의 절대 상단 위치 (비슷하게 계산 된), 이미지의 이름 (Boot.js 파일에 이미로드 된 이미지의 이름).



스프라이트 시트로드 중

다음 몇 줄은 load.image () (이미 보았 듯이)를 사용하여 모든 그래픽 애셋을 게임에 로드하는 것입니다.


마지막 3 가지는 약간 다릅니다.

this.load.spritesheet('candy', 'img/candy.png', 82, 98);


단일 이미지를 로드하는 대신 load.spritesheet () 함수는 하나의 파일 (스프라이트 시트) 내의 이미지 전체를 관리합니다. 스프라이트에서 단일 이미지의 크기를 함수에 알리기 위해 두 개의 추가 매개 변수가 필요합니다.


이 경우 하나의 candy.png 파일 안에 5 가지 유형의 사탕이 있습니다. 전체 이미지는 410x98px이지만 단일 항목은 82x98px로 설정되어 load.spritesheet () 함수에 입력됩니다. 플레이어 스프라이트 시트도 비슷한 방식으로 로드됩니다.


두 번째 함수 인 create ()는 게임의 다음 상태 인 MainMenu를 시작합니다. 즉, preload () 함수의 모든 이미지가 로드 된 직후에 게임의 기본 메뉴가 표시됩니다.



MainMenu.js


이 파일은 게임 관련 이미지를 렌더링하는 곳이며, 사용자가 시작 버튼을 클릭하여 게임 루프를 시작하고 게임을하는 곳입니다.


Candy.MainMenu = function(game) {};

Candy.MainMenu.prototype = {

    create: function() {

        this.add.sprite(0, 0, 'background');

        this.add.sprite(-130, Candy.GAME_HEIGHT-514, 'monster-cover');

        this.add.sprite((Candy.GAME_WIDTH-395)/2, 60, 'title');

        this.add.button(Candy.GAME_WIDTH-401-10, Candy.GAME_HEIGHT-143-10,

            'button-start', this.startGame, this, 1, 0, 2);

    },

    startGame: function() {

        this.state.start('Game');

    }


};

구조는 이전 JavaScript 파일과 유사합니다. MainMenu 객체의 프로토 타입에는 preload () 함수가 없습니다. 모든 이미지가 이미 Preload.js 파일에서 로드되었기 때문입니다.


프로토 타입에는 create () 와 startGame ()이라는 두 가지 함수가 정의되어 있습니다. 앞에서 언급했듯이, 첫 번째 이름은 Phaser에만 국한되며 두 번째 이름은 우리 자신의 이름입니다.


startGame ()을 먼저 살펴 보겠습니다.

startGame: function() {

    this.state.start('Game');


}

이 함수는 게임 루프를 시작하는 것만을 처리하지만 자동으로 또는 애셋이로드 된 후에 실행되지 않습니다. 버턴에 할당하고 사용자 입력을 기다립니다.


create: function() {

    this.add.sprite(0, 0, 'background');

    this.add.sprite(-130, Candy.GAME_HEIGHT-514, 'monster-cover');

    this.add.sprite((Candy.GAME_WIDTH-395)/2, 60, 'title');

    this.add.button(Candy.GAME_WIDTH-401-10, Candy.GAME_HEIGHT-143-10,

        'button-start', this.startGame, this, 1, 0, 2);


},

create () 메소드는 우리가 이미 잘 알고 있는 3 개의 add.sprite () Phaser 함수를 가지고 있습니다 : 이미지를 절대 위치에 배치하여 보이는 스테이지에 이미지를 추가합니다. 

우리의 메인 메뉴는 배경, 모서리에있는 작은 괴물, 그리고 게임의 제목을 포함합니다.



버튼

Game 상태에서 이미 사용했던 객체도 있습니다.

this.startButton = this.add.button(Candy.GAME_WIDTH-401-10, Candy.GAME_HEIGHT-143-10,


    'button-start', this.startGame, this, 1, 0, 2);

이 버튼은 지금까지 보아 왔던 방법보다 훨씬 복잡해 보입니다. 

왼쪽 위치, 위쪽 위치, 이미지 (또는 스프라이트)의 이름, 버튼을 클릭 한 후 실행할 함수, 이 함수가 실행되는 컨텍스트 및 이미지의 인덱스를 만들기 위해 8 개의 다른 인수를 전달합니다.


다음은 버튼 스프라이트 시트가 표시되는 상태로 레이블이 지정된 상태입니다.



이것은 이전에 사용한 candy.png 스프라이트 시트와 매우 유사합니다.


함수에 전달되는 된 마지막 세 자리는 오버 (호버), 아웃 (일반) 및 다운 (터치 / 클릭)과 같은 버튼의 여러 상태임을 기억하는 것이 중요합니다. 

우리는 button.png 스프라이트 시트에서 normal, hover 및 click 상태를 각각 가지므로 add.button () 함수의 전달되는 순서를 0, 1, 2에서 1, 0, 2로 변경하여야 합니다.


이제 Phaser 게임 프레임 워크의 기본 사항을 알게되었습니다.



완성 된 게임

이 문서에서 사용 된 데모 게임은 여기서 플레이 할 수있는 완성 된 게임으로 발전했습니다. 보시다시피 생명, 업적, 높은 점수 및 기타 흥미로운 기능이 구현되었지만 대부분이 튜토리얼을 통해 배웠던 지식을 기반으로 합니다.



마치며

지금까지 Monster Wants Candy 데모의 모든 코드 행을 통한 긴 여행 이었지만 Phaser를 배우는 데 도움이되기를 바랍니다. 가까운 장래에 프레임 워크를 사용하여 멋진 게임을 만들 수 있기를 바랍니다.

Posted by 마스터킹
|