http://phaser.io/tutorials/making-your-first-phaser-game 을 번역한 글입니다.
Part 1 - Introduction
part1.html을 열어보면 다음과 같은 획일화 된 Phaser를 포함한 HTML 구조가 보인다.
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });
function preload() {
}
function create() {
}
function update() {
}
1 line은 Pahser.Game 오브젝트의 인스턴스를 생성하여 game 변수에 할당함으로서 Pahaser life를 만듭니다. 첫 번째와 두 번째 파라미터는 생성할 Canvas의 사이즈입니다. 세 번째 파라미터는 Phaser.CANVAS나 Phaser.WEBGL 그리고 Phaser.AUTO가 가능하지만 자동으로 WebGL으로 시도하는 Phaser.AUTO를 추천합니다. 브라우저나 디바이스가 지원하지 않으면 CANVAS에서 떨어져 나가겠지만요. 네 번째 파라미터는 우리가 만든 canvas element를 삽입할 DOM element의 id입니다. 우리가 그것을 공백으로 놔두면 간단히 body에 추가됩니다. 마지막 파라미터는 Phaser에 필수적인 함수들에 대한 참조입니다.
Part 2 - Loading Assets
우리가 필요한 asset들을 로딩해봅시다. preload 함수에서 game.load를 호출해줍시다. Phaser는 실행되면서 자동으로 그것들을 읽고 로드합니다.
function preload() {
game.load.image('sky', 'assets/sky.png');
game.load.image('ground', 'assets/platform.png');
game.load.image('star', 'assets/star.png');
game.load.spritesheet('dude', 'assets/dude.png', 32, 48);
}
이것은 4가지 asset: 3가지 이미지, 그리고 하나의 sprite sheet 입니다. 첫 번째 파라미터는 asset의 키이고, 두 번째는 로딩될 에셋의 링크 주소입니다. 당신은 첫 번째 파라미터의 이름으로 JavaScript에서 자유롭게 사용할 수 있습니다.
Create a Sprite
우리의 게임에 sprite를 추가하기 위해 create 함수에 아래 코드를 넣어줍시다.
game.add.sprite(0, 0, 'star');
Part 3 - World Building
Note : 게임 월드는 고정되지 않은 모든 방향으로 무한하게 확장될 수 있습니다. 편의를 위해 Phaser는 0,0 (좌측 상단)에 위치시키지만 built-in Camera를 이용해 필요한만큼 이동시킬 수 있습니다.
world 클래스는 game.world 를 통해 접근할 수 있습니다. 그리고 간편한 메소드와 속성들로하여금 당신이 world 내에 객체들을 할당할 수 있게합니다. 이 튜토리얼에서는 간단히 game.world.height 정도를 사용하지만 다른 튜토리얼에서 다양한 것을 경험할 수 있습니다. 이제 create 함수를 업데이트 해봅시다.
var platforms;
function create() {
// We're going to be using physics, so enable the Arcade Physics system
game.physics.startSystem(Phaser.Physics.ARCADE);
// A simple background for our game
game.add.sprite(0, 0, 'sky');
// The platforms group contains the ground and the 2 ledges we can jump on
platforms = game.add.group();
// We will enable physics for any object that is created in this group
platforms.enableBody = true;
// Here we create the ground.
var ground = platforms.create(0, game.world.height - 64, 'ground');
// Scale it to fit the width of the game (the original sprite is 400x32 in size)
ground.scale.setTo(2, 2);
// This stops it from falling away when you jump on it
ground.body.immovable = true;
// Now let's create two ledges
var ledge = platforms.create(400, 400, 'ground');
ledge.body.immovable = true;
ledge = platforms.create(-150, 250, 'ground');
ledge.body.immovable = true;
}
게임을 실행하면 위와 같이 world가 생성된 것을 볼 수 있습니다.
Part 4 - Groups
그룹은 진짜 강력합니다. 그룹으로 묶인 유닛들은 하나의 유닛처럼 취급되어 컨트롤되어집니다. 당신은 또한 그룹 간의 Collision 체크도 가능합니다. 이 게임에서는 두 가지 그룹을 사용할 것입니다. 아래와 같이 platforms를 위한 그룹을 만들어 줍니다.
platforms = game.add.group();
이제 이전에 불러왔던 ground 이미지를 바닥에 놓고 platforms 그룹에 추가해줍니다. 그리고 immovable 속성을 true로 지정해줍니다. 이렇게 하지 않으면 플레이어와 충돌할 때 ground는 움직이게 될 것 입니다. 두 개의 ledge도 ground와 동일한 방식으로 만들어 줍니다.
Ready Player One
이제 새로운 변수 player를 만들고, 다음 코드를 create 함수에 넣어줍니다.
// The player and its settings
player = game.add.sprite(32, game.world.height - 150, 'dude');
// We need to enable physics on the player
game.physics.arcade.enable(player);
// Player physics properties. Give the little guy a slight bounce.
player.body.bounce.y = 0.2;
player.body.gravity.y = 300;
player.body.collideWorldBounds = true;
// Our two animations, walking left and right.
player.animations.add('left', [0, 1, 2, 3], 10, true);
player.animations.add('right', [5, 6, 7, 8], 10, true);
이 코드는 ‘player’라는 새로운 sprite를 생성합니다. 이전에 load했던 dude를 힐끗 보시면 다른 sprite와 다르게 sprite sheet로 로드된 것을 눈치 빠르신 분들은 기억하고 계실 것 입니다. 이것은 에니메이션 프레임을 가지고 있기 때문입니다. 다음 그림이 full sprite sheet 입니다.
Part 5 - A world of physics
Phaser는 다양한 종류의 물리 시스템을 제공합니다. Arcade, Ninja, P2.JS Full-Body Physics 입니다. 우리의 튜토리얼에서는 간단하고 적은 부하를 야기하며, 모바일에 최적화 되어있는 Arcade를 사용하도록 하겠습니다. ArcadePhysics.Body 객체의 인스턴스를 sprite에 추가하면 sprite의 물리적 바디는 Arcade Physics 엔진의 영향을 받습니다. body 객체에는 속성이 있는데 테스트를 위해 아래의 코드를 추가해줍니다.
player.body.gravity.y = 300;
위의 수치는 임의적인 것 같지만, 논리적입니다. 높은 수치를 넣을수록 당신의 객체는 무거워지는 것 입니다. 이대로 게임을 실행하면 플레이어는 멈춤 없이 ground를 무시하고 떨어질 것 입니다. 그 이유는 우리가 아직 ground와 player 간의 collision을 체크하지 않았기 때문입니다. 이전에 우리는 ground와 ledges를 immovable로 지정했습니다. 만약 우리가 지정하지 않았다면 캐릭터는 ground와 부딪혔을 때 잠시 멈추고 둘은 같이 떨어질 것 입니다. 왜냐하면 ground는 moving physical 객체이므로 player가 그것을 쳤을 때, 결과적으로 충돌의 힘은 ground에 적용될 것이기 때문입니다. 두 개의 바디는 서로의 속도를 교환하고 결과적으로 같이 떨어지게 될 것 입니다.
그래서 collision check를 위해 update 함수에 아래와 같이 코드를 넣어줍니다.
function update() {
// Collide the player and the stars with the platforms
game.physics.arcade.collide(player, platforms);
}
update 함수는 매 프레임마다 호출됩니다. Physics.collide 함수는 마법과 같은 퍼포먼스입니다. 이것은 두 오브젝트를 얻어 충돌을 테스트하고 각각에 대해 퍼포먼스합니다. 이 케이스에서는 player Sprite와 platforms Group을 넣었습니다. 영리하게도 Group 멤버모두에게 실행됩니다.
Physics Engine
P2 : 복잡한 충돌들에 대한 완전한 물리 시스템을 가지고 있음. (앵그리버드)
Ninja : P2보다는 덜 강력하다, 하지만 여전히 타일맵과 슬로프를 조절하는데 적절하다.
Arcade : AABB로 불리는 사각형 충돌을 다룬다. 하지만 최고의 퍼포먼스를 보여준다.
Part 6 - Keyboard controls
우리는 캐릭터를 옮길 필요가 있습니다. 아마 당신은 관련 서적의 맨 앞에서 이벤트 리스너에 대해서 뒤적이고 있겠죠. 하지만 여기서는 필요없습니다. Phaser는 built-in 키보드 매니저를 가지고 있습니다. 그리고 손쉬운 function을 제공합니다.
cursors = game.input.keyboard.createCursorKeys();
커서의 4가지 속성: Up, Down, Left, Right 는 Phaser.Key 객체의 인스턴스 입니다. 그리고 아래의 코드를 Update loop에 등록해줍니다.
// Reset the players velocity (movement)
player.body.velocity.x = 0;
if (cursors.left.isDown)
{
// Move to the left
player.body.velocity.x = -150;
player.animations.play('left');
}
else if (cursors.right.isDown)
{
// Move to the right
player.body.velocity.x = 150;
player.animations.play('right');
}
else
{
// Stand still
player.animations.stop();
player.frame = 4;
}
// Allow the player to jump if they are touching the ground.
if (cursors.up.isDown && player.body.touching.down)
{
player.body.velocity.y = -350;
}
비록 우리는 많은 코드를 추가했지만 읽기는 꽤 쉽습니다. 첫 째, 우리는 스프라이트의 horizontal velocity를 초기화해야합니다. 이제 우리는 left 커서가 눌리는지를 체크해야합니다. 만약 당신이 negative horizontal velocity를 적용하고 시작하면 left Running 애니메이션이 시작될 것입니다. 매 프레임 velocity를 초기화 시켜줌으로서 stop-start 스타일 무브먼트가 적용됩니다. 캐릭터 스프라이트는 키가 눌릴 때만 움직일 것이며 그렇지 않으면 멈출 것 입니다. Phaser은 또한 더 복잡한 모션을 구현하도록 해줍니다. mementum(타력)과 acceleration(가속) 등.
Jump to it
마지막 코드는 점프 능력을 부여하는 것입니다. UP 커서는 우리의 점프키 입니다. 그리고 그것은 우리가 Down 인지를 검사하여 실행됩니다. 또한 우리는 플레이어가 floor를 터치하고 있는지도 검사합니다. 그렇지 않으면 공중에서 점프가 가능하게 되죠. 두 조건이 모두 충족되면 캐릭터는 305px/sec로 점프하게 됩니다. 캐릭터는 중력 때문에 자동으로 떨어지게 됩니다.
Part 7 - Starshine
이번에는 이 게임의 목표를 주겠습니다. 화면에 별들을 흩뿌리고 캐릭터가 그것을 먹을 수 있게 해봅시다. 이를 위해 우리는 ‘stars’라는 새로운 그룹을 만들어야합니다. create 함수에 아래의 코드를 넣어줍시다.
stars = game.add.group();
stars.enableBody = true;
// Here we'll create 12 of them evenly spaced apart
for (var i = 0; i < 12; i++)
{
// Create a star inside of the 'stars' group
var star = stars.create(i * 70, 0, 'star');
// Let gravity do its thing
star.body.gravity.y = 6;
// This just gives each star a slightly random bounce value
star.body.bounce.y = 0.7 + Math.random() * 0.2;
}
이 과정은 우리가 platform 그룹을 만들 때와 유사합니다. JavaScript의 for 반복문을 이용해 12개의 별들을 게임에 만들어 줍니다. 그들은 i * 70을 통해 조정된 x 좌표를 가지게 됩니다. 그리고 gravity를 부여하고, platforms와 부딪혔을 때 튕기게 bounce를 지정해줍니다.
Bounce의 값은 0.7에서 0.9를 랜덤으로 가지게 됩니다. 게임을 시작하게 되면 star는 떨어지게 됩니다. 이를 Platforms와 부딪히게 하기 위해 update에 아래 코드를 넣어줍니다.
game.physics.arcade.collide(stars, platforms);
또한 캐릭터와 오버랩 되는지를 아래의 코드를 통해서 체크합니다.
game.physics.arcade.overlap(player, stars, collectStar, null, this);
위의 함수는 플레이어와 별 그룹이 오버랩되면 collectStar 함수로 넘어가도록 합니다.
function collectStar (player, star) {
// Removes the star from the screen
star.kill();
}
Part 8 - Finishing touches
마지막으로 스코어를 넣도록 하겠습니다. 우리는 이를 위해 Phaser.Text 객체를 사용할 것입니다. 아래의 두 변수를 작성합니다. 하나는 실제 스코어이고, 다른 하나는 text 객체 입니다.
var score = 0;
var scoreText;
scoreText는 create 함수에서 설정합니다.
scoreText = game.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
16x16은 텍스트의 display를 조정합니다. score: 0 는 디폴트 문자이고 사이즈와 칼라를 정해줍니다. 폰트를 명세하지 않으면 브라우저의 디폴트 폰트를 사용합니다. (Windows는 Arial.) 다음으로 collectStar 함수를 수정합시다. 플레이어가 star를 줍게되면 점수가 증가하도록 반영합니다.
function collectStar (player, star) {
// Removes the star from the screen
star.kill();
// Add and update the score
score += 10;
scoreText.text = 'Score: ' + score;
}