2019년 8월 25일 일요일

GMS2 적 움직임 만들기 state machine이용 2 : 소주제 BOSS 움직임 ( enemy movement with state machine 2 : BOSS )


이전 글에 관한 내용

이전 글에서는 간단하게 적 움직임을 state machine에 어떻게 넣는가에 대해서 알아 보았습니다.

https://swlock.blogspot.com/2019/08/gms2-state-machine-enemy-movement-with.html

이번에는 좀 더 복잡하게 움직이는 움직임에 대해서 알아볼 차례입니다.


BOSS

게임에서의 보스는 항상 어려운 상대이고 도전 욕구를 불러 일으키는 상대입니다. 그렇기 때문에 게임에 있어서 보스는 무작정 절대 깰수 없는 상태로 만들면 안됩니다. 보스 움직임을 만들때 주의해야할 점은 보스는 허점을 만들어야 하고, 패턴을 만들어 두면서 사용자가 그 허점과 패턴을 리트라이 하면서 찾아내는 즐거움을 주어야 합니다.
그리고 일반적으로 강한 공격은 준비 동작(모션) 시간을 주는것이 바람직 합니다.

여기에서 구현하는 BOSS

BOSS는 32*64 이미지로 Crab을 모티브로 만들었으며, 대게를 반으로 잘라서 먹은것과 개구리 눈 부위를 상상하며 Pixel을 찍어서 직접 만들었습니다.

공격전에는 한쪽 발을 들면서 큰 공격을 하며, 상대방이 멀리 있으면 많은 수의 포탄을 날리고 가까우면 3발의 포탄을 날립니다.
따라서 이 BOSS의 상대하는 방법은 몸쪽에 가까이 붙으면서 상대하면 좋은 파해법이 되도록 만들었습니다.

ACTION 코드 비교

이전글에서 만든 object와 비교해보겠습니다. 기존 object는 좌우로 움직으며 총알만 쏩니다. 또하나의 특징은 마지막에 플랫폼에서 떨어지지 않도록 구현하였습니다.
그 부분은 아래 코드의 dLeft, dRight 조건입니다. 해당 조건일때 방향을 바꾸도록 구현이 되있습니다.
step 코드 일부분
// action
state_count++;
if(state==SM_WLKL || state==SM_WLKR){
 // Left 
 if (state==SM_WLKL) {
     facing = -1;
     // Apply acceleration left
     if (vx > 0)
         vx = Approach(vx, 0, tempFric);   
     vx = Approach(vx, -vxMax, tempAccel);
  if( cLeft || dLeft) {
   vx = 0;
   state=SM_WLKR;
  }
 // Right
 } else if (state==SM_WLKR) {
     facing = 1;
     // Apply acceleration right
     if (vx < 0)
         vx = Approach(vx, 0, tempFric);   
     vx = Approach(vx, vxMax, tempAccel);
  if( cRight || dRight ) {
   vx = 0;
   state=SM_WLKL;
  }
 }
 
}

BOSS의 경우 좌우로 떨어질수 있도록 합니다. 다만 벽에 닿는 조건은 그대로 유지가 필요합니다. 아래 코드에서 살펴보면 if( cLeft ) need_to_change_state = true; if( cRight ) need_to_change_state = true; 와 같은 조건으로 벽이 있다면, state를 변하게 만듭니다.

step코드의 일부분
// action
state_count++;
if(state==SM_WLKL || state==SM_WLKR){
 // Left 
 if (state==SM_WLKL) {
     facing = 1;
     // Apply acceleration left
     if (vx > 0)
         vx = Approach(vx, 0, tempFric);   
     vx = Approach(vx, -vxMax, tempAccel);
  if( cLeft ) need_to_change_state = true;
 // Right
 } else if (state==SM_WLKR) {
     facing = -1;
     // Apply acceleration right
     if (vx < 0)
         vx = Approach(vx, 0, tempFric);   
     vx = Approach(vx, vxMax, tempAccel);
  if( cRight ) need_to_change_state = true;
 }
 
}

FIRE코드 비교

총알을 발사하는 코드를 비교해보겠습니다. FIRE State일때 총알을 만들고 state를 firewait 상태로 만듭니다. 이것은 총을 쏜다음 총쏜 후 대기 animation frame을 넣기 위한 코드입니다.

if (state==SM_FIRE) {
 if( state_count > state_count_max ){
  var obj = instance_create_layer(x,y,"Instances",oEBullet);
  var dir = 0;
  if( facing == -1 ) dir = 180;
  else dir = 0; 
  with(obj){
   speed     = 5;
   direction = dir;
  }
  state_count = 0;
  vx = 0;
  state=SM_FIREWAIT;
 }
}

BOSS의 fire는 oPlayer(주인공 객체인데 여기에서는 샘플로 임의의 위치에 배치 하였습니다.) 가 가까이 있다면 3발의 총알을 발사하는 instance를 생성하고 거리가 멀다면 여러발을 발사하는 instance를 생성합니다. 그 부분은 다음 코드 입니다. obj = instance_create_layer(x,y-10,"Instances",oEBulletMulti);

if (state==SM_FIRE) {
 if( state_count > state_count_max ){
  var obj;
  if(distance_to_object(oPlayer)<50){
   obj = instance_create_layer(x,y-10,"Instances",oEBulletTriSp);
  }else{
   obj = instance_create_layer(x,y-10,"Instances",oEBulletMulti);
  }
  var dir = 0;
  if( facing == 1 ) dir = 180;
  else dir = 0;
  var gp = gun_power;
  with(obj){
   gun_power = gp;
   speed     = 5;
   direction = dir;
  }
  state_count = 0;
  state=SM_FIREWAIT;
 }
}

실제 동작 예제






소스 코드


https://drive.google.com/open?id=1KGjIznlC4OFtfu1AA32T8-aHVgDysG42





댓글 없음:

댓글 쓰기