HTML5GAME :: Phaser Js 프레임 워크를 사용하여 'Gravity Quest'를 어떻게 개발 했나요? - Part 1

달력

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

게임 플레이 설계 및 구현


이제 게임의 게임 플레이 디자인과 구현에 대한 통찰력을 얻고 자합니다.

중력 퀘스트 (Gravity Quest)에서는 우주 비행사의 역할을 맡아 우주에서 미네랄 탐침을 수집하는 동안 이상한 사고 때문에 그녀의 우주 왕복선에서 분리됩니다. 생존을 위해, 플레이어는 25 레벨의 모든 우주 비행후 결국 지구로 돌려 보낼 블랙홀로 이동해야합니다. 

플레이어가 도달하려면 (어떤 끌림) 중력총을 이용해야 합니다. 그것을 발사하는 동안, 우주 비행사는 가능한 가장 가까운 소행성으로 가속합니다. 

따라서 타르 잔은 소행성 주변을 돌아 다니면서 검은 색 전체에 도달하거나, 치명적인 물체와 충돌하거나, 우주로 너무 멀리 떠돌아 다니다가 잃어 버리게됩니다. 다음은 설명 된 게임 플레이의 몇 가지 예를 보여줍니다.


 


아이디어 반복하기


앞서 설명한 게임의 최종 개념을 설정하기 전에 다른 디자인으로 몇 차례 반복했습니다. 예를 들어 이전의 아이디어 중 하나는 플레이어는 검은 색 전체를 제어했습니다. 목표는 플레이어가 블랙홀 쪽으로 항상 떠 다니는 다양한 개체 (행성, 우주선 등)를 흡수하여 적의 블랙홀이 흡수하기 전에 수행하는 것입니다. 

이 적들을 추방하기 위해 플레이어는 스크린 주변에서 블랙홀을 능숙하게 움직여야했습니다. 그러나 이 개념의 프로토 타입을 작성함으로써, 나는 플레이어가 블랙홀을 재배치하기 위해 화면에서 게임 플레이가 손가락을 계속 움직여야 하고, 결과적으로 불만족 스러웠다는 것을 빨리 알게되었습니다. 여기서 중요한 점이 게임 플레이에 대한 테스트를 가능한 한 빨리하면 쉽게 아이디어를 수정하거나 완전히 정리 할 수 있다는 사실을 쉽게 알 수 있습니다.



개념 구현하기


다음에서는 필자가 Phaser 프레임 워크로 게임 플레이를 구현 한 방법을 설명해 보겠습니다 (참고 : 필자는 이 기사 작성 시점 인 최신 버전 2.0.7을 사용하고 있습니다). 저는 우주 비행사가 레벨을 이동하기 위해 사용자 입력시 소행성과 어떻게 상호 작용하는지에 대해 집중적으로 다룰 것입니다. 실행 가능한 데모를 정의하는 데 필요한 모든 부분을 제시 하겠지만 Phaser 프레임 워크를 사용하는 모든 측면에 대해서는 자세히 설명하지 않겠습니다. 관심있는 독자는 토마스 팔레 프 (Thomas Palef)의 광범위한 책 디스 카이저 (Phaser)와 같은 더 포괄적 인 소개를 살펴 봐야합니다.


기초로서 Phaser는 게임 개체의 초기화가 필요합니다. 이 작업을 수행하는 기능은 게임의 의도 된 너비와 높이 (예 : 640 및 480 픽셀)와 렌더링 방법 (Canvas 또는 WebGL)을 정의하고, Phaser.AUTO를 사용하면 Phaser가 가장 적절한 렌더링 방법을 선택할 수 있습니다. 추가 매개 변수를 사용하여 게임의 캔버스가 삽입되는 DOM 요소 (예 : div)를 선택할 수 있습니다.이 경우 id는 'game'입니다.

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

Listing 1 : 페이저 게임 객체를 인스턴스화한다.


Phaser의 게임은 적어도 하나의 State로 구성됩니다. 게임 상태는 일반적으로 고유 한 기능 집합을 나타냅니다. 예를 들어, 한 State에서는 게임 메뉴를 담당하고 다른 State에서는 실제 게임 플레이를 담당합니다. 각 State는 일반적으로 목록 2에 설명 된 preload, create 및 update 세 가지 기능으로 구성됩니다.

var mainState = {
 preload: function() {
  // called once upon instantiation of the state
  // typically used to load required assets
 },
 create: function() {
  // called once after the preload function
  // typically used to set up the game
 },
 update: function() {
  // called 60 times per second
  // typically used to react to user input, define game logic etc.
 }
}

Listing 2 : 상태 정의.


(이 경우) State만 정의하면 게임에 추가 할 수 있으며 목록 3과 같이 즉시 시작될 수 있습니다.


...
game.state.add('main', mainState);
game.state.start('main');

목록 3 : 게임에 상태를 추가하고 시작.


이 기본 설정을 하였으면, 목록 4에 표시된 것처럼 preload 함수 내에서 필요한 스프라이트를 로드 할 수 있습니다. 이 경우 우주 비행사가 소행성에 가장 가까운 소행성에 발사 할수있는 우주 비행사, 소행성 및 중력선에 대한 스프라이트를 로드합니다. 

...
game.load.image('astronaut', 'assets/astronaut.png');
game.load.image('asteroid', 'assets/asteroid.png');
game.load.image('gravityRay', 'assets/gravityray.png');
...

Listing 4 : preload 함수에서 Asset로드하기.


create 함수에서 먼저, Phaser의 아케이드 물리 시스템 (후자의 물리 시스템에 대해 자세히 설명)을 목록 5와 같이 활성화 합니다. 게임 세계에서 스프라이트에 body를 할당 할 수 있습니다. 이 body에서 중력이나 가속과 같은 효과를 적용하고 충돌을 검사 할 수 있습니다.

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

목록 5 : 아케이드 물리 시스템 활성화.


다음으로, create 함수에서 중력선, 소행성 및 우주 비행사가 미리로드 된 Asset을 사용하여 게임에 배치합니다. 목록 6에서 볼 수 있듯이, 중력선은 게임 월드의 왼쪽 상단 모퉁이에 위치하고 있습니다. 이 위치는 나중에 중력 광선이 시작되는 우주 비행사의 위치와 관련하여 조정됩니다. 중력 광선의 앵커는 수직 중심으로 설정됩니다. 광선은 사용자 입력시에만 표시되어야 하므로 중력 광선의 가시성을 false로 설정합니다.

...
// create gravity ray between astronaut and closest asteroid:
this.gravityRay = game.add.sprite(0, 0, 'gravityray');
this.gravityRay.anchor.setTo(0, 0.5);
this.gravityRay.visible = false;
...

목록 6 : 중력 광선을 게임에 배치.


이 데모에서는 목록 7처럼 7 개의 소행성이 게임에 추가됩니다. 모든 소행성은 Phaser의 rnd.integerInRange를 사용하여 게임 세계에서 무작위로 배치됩니다. 잠재적 인 소행성 위치에서 100 픽셀의 경계가 제외됩니다. (실제 게임에서 모든 소행성의 위치는 모든 레벨에 대해 수동으로 정의됩니다.) 또한 모든 소행성 앵커는 중심에 놓여 우주 비행사가 나중에 소행성의 왼쪽 위 모퉁이로가 아니라 중심쪽으로 가속하게 합니다. 또한 아케이드 물리 시스템은 모든 소행성에 대해 활성화합니다. 소행성은 그 다음 배치 처리를 위해 소행성을 결합한 사전 정의 된 소행성 그룹에 추가됩니다.

...
// (randomly) place asteroids and add to group:
this.asteroids = game.add.group();
for (var i = 0; i < 7; i++) {
 var asteroid = game.add.sprite(
  game.rnd.integerInRange(100, game.world.width - 100),
  game.rnd.integerInRange(100, game.world.height - 100),
  'asteroid');
 asteroid.anchor.setTo(0.5, 0.5);
 game.physics.enable(asteroid, Phaser.Physics.ARCADE);
 this.asteroids.add(asteroid);
};
...

목록 7 : (무작위로) 소행성을 게임에 배치.


마지막으로, create 함수에서 우주 비행사는 목록 8에 표시된대로 게임 세계의 중심에 위치합니다. 모든 소행성의 경우와 마찬가지로, 물리엔진은 활성화됩니다.

...
// create astronaut at the center of the world:
this.astronaut = game.add.sprite(game.world.width * 0.5, game.world.height * 0.5, 'astronaut');
this.astronaut.anchor.setTo(0.5, 0.5);
game.physics.enable(this.astronaut, Phaser.Physics.ARCADE);
...

Listing 8 : 우주 비행사를 세계에 배치.


다음에서는 create 함수에서 게임의 Scene을 설정한 후, update 함수에서 플레이어 컨트롤을 활성화하는 데 필요한 로직으로 작성하겠습니다.


먼저, 플레이어에게 가장 가까운 소행성과 그 거리가 목록 9에 표시 된 바와 같이 결정됩니다. 초기 거리는 가능한 가장 높은 값으로 설정됩니다. 모든 소행성에 대해 우주 비행사와의 거리는 아케이드 물리시스템 인 distanceBetween에서 사용할 수있는 도우미 함수를 사용하여 계산됩니다. distanceBetween은 2 개의 아케이드 물리 객체를 입력하면 앵커 포인트 사이의 거리를 반환합니다. 결정된 거리가 현재 가장 작은 거리보다 작은 경우이 거리가 저장되고 해당 소행성이 가장 가까운 거리로 설정됩니다.

...
var distance = Number.MAX_VALUE;
var closestAsteroid;
this.asteroids.forEach(function(ast){
 var tempDistance = this.distanceBetween(ast, this.astronaut);
 if(tempDistance < distance){
  distance = tempDistance;
  closestAsteroid = ast;
 }
}, this);
...

목록 9 : 우주 비행사에게 가장 가까운 소행성과 그 거리를 결정.


다음으로, 목록 10에 표시된 바와 같이, 결정된 최소 거리가 특정 임계 값보다 250 아래에 있는지 검사합니다. 이때 우주 비행사가 너무 멀리 떨어져 나가고 게임이 종료되고 리스타트 하게 됩니다.

if(distance > 250){
 game.state.start('main');
}
...

목록 10 : 우주 비행사가 지나치게 멀리 떨어진 경우 게임을 다시 시작.


다음으로, 업데이트 기능 내에서, 목록 11의 코드 내용처럼 사용자 입력를 행하는지를 체크합니다. Gravity Quest에서, 사용자 입력은 포인터 (컴퓨터상의 마우스 또는 터치 장치상의 손가락)를 누르고 있는것으로 판단합니다. 사용자 입력이 탐지되면, 우주 비행사를 가장 가까운 소행성으로 가속시키는 힘이 결정됩니다. 이 경우, 우주 비행사가 가장 가까운 소행성과 얼마나 가까운 지에 따라 가속도가  30 이상으로 설정됩니다. 중력 총을 더 강하게 만들어서 그것이 발사되는 대상으로 가깝게 만드는 것입니다. 플레이어는 아케이드 물리 시스템의 accelerateToObject 기능을 사용하여 계산 된 힘으로 가장 가까운 소행성으로 가속됩니다. 또한 우주 비행사는 아케이드 물리 시스템의 angleBetween 기능을 사용하여 가장 가까운 소행성을 향해 회전합니다. 우주 비행사의 앵커가 의도 한 회전을 받기 위해 중심에 놓이는 것이 중요합니다 (목록 8 참조).

...
if(game.input.activePointer.isDown){
 var force = Math.min(30, 30 * (1 - distance / 250));
 game.physics.arcade.accelerateToObject(this.astronaut, closestAsteroid, force);

 this.astronaut.rotation = game.physics.arcade.angleBetween(this.astronaut, closestAsteroid);
}
...

목록 11 : 사용자 입력에 따라 우주 비행사를 가장 가까운 소행성으로 가속.


우주 비행사의 가속에 이어 중력총의 발사가 시각화 되어야합니다. 이를 처리하기 위해 중력선을 목록 12와 같이 사용자 입력시 보이도록 표시하고, 크기를 조정하고 회전합니다. 먼저 중력 광선을 표시합니다 (목록 6에서는 처음에는 보이지 않도록 설정). 그런 다음, 그 위치는 광선이 원점 인 우주 비행사의 위치와 일치합니다. 중력 광선의 회전은 우주 비행사와 마찬가지로 angleBetween 함수를 사용하여 설정됩니다. 중력선의 너비는 우주 비행사와 가장 가까운 소행성에서이 소행성 반경을 뺀 거리로 설정됩니다. 이렇게하면 우주선이 중심이 아닌 소행성의 표면에서 끝나도록 할 수 있습니다. 마지막으로, 중력선의 높이는 우주 비행사가 가장 가까운 소행성까지의 거리를 고려하여 설정됩니다. 여기에서의 의도는 거리가 멀면 광선을 작게 만들어 우주 비행사가 가속하는 힘을 낮추는 것입니다.

...
if(game.input.activePointer.isDown){
 ...
 this.gravityRay.visible = true;
 this.gravityRay.x = this.astronaut.x;
 this.gravityRay.y = this.astronaut.y;
 this.gravityRay.rotation = game.physics.arcade.angleBetween(this.astronaut, closestAsteroid);
 this.gravityRay.width = distance - closestAsteroid.width * 0.5;
 this.gravityRay.height = Math.min(15, 15 * (1 - distance / 250));
}
...

목록 12 : 우주 비행사가 가장 가까운 소행성으로 중력 광선을 렌더링.


마지막으로, 우주 비행사의 가속을 중지하고 중력 광선을 사용자 입력단에 한 번 숨겨야 할 필요가 있습니다 (목록 13 참조).

...
if(game.input.activePointer.isDown){
 ...
} else {
 game.physics.arcade.accelerateToObject(this.astronaut, closestAsteroid, 0);
 this.gravityRay.visible = false;
}
...

목록 13 : 사용자 입력이 멈출 때 중력선을 제거하고 가속을 중지.



데모

위에서 설명한 내용을 정리후, 아래의 버튼을 눌러 데모를 재생하십시오. 데모에서는 우주 비행사가 가장 가까운 소행성을 향해 가속화 할 수 있도록 아무 곳이나 누르십시오.



Posted by 마스터킹
|