본문 바로가기
GameMaker강좌[GMS2]/전략게임강좌

[게임메이커 강좌-전략][GMS2] RTS 게임 만들기-2 유닛 이동

by 타락카얀 2023. 3. 14.
728x90

 

 

GAME MAKER 강좌

 

KAYAN

 

 

 

 

 

 

이전 강좌에서 플레이어 유닛의 선택까지 해보았죠. 이번에는 플레이어 유닛을 이동 시켜 보도록 해요.

 

(▲플레이어 이동)

 

 

 

 

 

◈플레이어 유닛 이동시키기(obj_pl_unit1)

 

 

일단 플레이어 유닛 오브젝트로 이동해서 [Create 이벤트]에 이동에 필요한 변수들을 선언하도록 합니다.

 


   //● obj_pl_unit1 - Create 이벤트
   
  

   flag=0;
   select=0;
   
   HP=10;
   HP_MAX=HP;
   
   //---------이동에 필요한 추가 변수----------
  

   pspeed=2;//이동 속도
   
   move_on=0;//이동 체크
   move_x=0;//이동할 x위치
   move_y=0;//이동할 y위치
   
   target=noone;//공격시 목표 적 유닛
   


 

이동은 mp_potential_step을 이용한 이동을 구현해볼 것입니다.

이것은 이동 경로에 Solid가 체크된 장애물이 있는 경우 회피하여 이동할 수 있어요.

그러나 완벽하게 회피하는 것이 아니지만, 간단한 이동 구현에 아주 유용한 함수라는 점입니다. 와우! 굳!

 

[Step이벤트]를 추가하고, 아래와 같이 이동에 대한 이벤트를 작성합니다.

 


   //● obj_pl_unit1 - Step 이벤트
   

   if move_on==1{
   if point_distance(x,y,move_x,move_y)>pspeed{
   mp_potential_step(move_x,move_y,pspeed,0);
   }
   else{move_on=0;}
   }


 

이렇게 하면 move_x와 move_y좌표를 제공하고, move_on을 1로 명령을 내리면 유닛은 그 위치까지 이동하게 됩니다.

그 위치쯤(최소 범위)에 도착하면 이동을 멈추고 move_on을 다시 0으로 만듭니다.

 

예이! 간단하죠.^^

 

그리고 체력이 0 이하일 때는 유닛을 파기하도록 합니다.

 


   //● obj_pl_unit1 - Step 이벤트
  
 

   if move_on==1{if point_distance(x,y,move_x,move_y)>pspeed{
   mp_potential_step(move_x,move_y,pspeed,0);
   }else{move_on=0;}}
   
   
   //--------- ▼ 이어서 추가
   
   if HP<=0{HP=0;instance_destroy( );}//이것은 체력이 0일때 파기함
   


 

하지만 이동할 곳에 도착하지 못할 것을 예상하여 자동으로 멈추는 이벤트를 하나 만들도록 해요.

이것은 알람 이벤트를 이용합시다. 여기선 [Alarm 5 이벤트]를 사용하도록 하겠습니다.

[Alarm 5 이벤트]를 추가하고, 아래와 같이 추가합니다.

 


   //● obj_pl_unit1 - Alarm 5 이벤트
   
   
   if move_on==1{move_on=0;}


 

이것은 이동시 어느정도 시간을 준 다음, 그 시간 안에 도착하지 못하면 스스로 멈추게 되는 이벤트입니다.

 

플레이어가 겹칠때를 대비해 위치를 서로 떨어뜨리는 이벤트를 만들어 봅시다.

 

(▲겹치는 유닛 떨어 뜨려 놓기)

 

해당 유닛의 parent오브젝트(obj_player)와의 [충돌 이벤트]를 추가하고, 아래와 같이 작성합니다.

 


   //● obj_pl_unit1 - obj_player와의 충돌 이벤트
   
   
   var spd;
   spd=1;
   if x>other.x{x+=spd;}else{x-=spd;}
   if y>other.y{y+=spd;}else{y-=spd;}



 

이렇게 하면 parent가 같은 유닛끼리 충돌 했을 때, 충돌하지 않을 때 까지 서로 이동하게 됩니다.

 

 

 

 

 

◈유닛 이동 제어(obj_ctrl_sys, obj_unit_position)

 

 

이제 유닛을 실제로 이동 명령을 내리는 이벤트를 작성해보아요.

 

일단 잠깐만 생각해봅시다.

어느 좌표를 지정해주고, "이동하여랏!"하고 명령을 내리면, 유닛이 이동하게 됩니다.

상상이 가시죠?

하지만 여러개의 유닛을 이동시킨다고 가정해봅시다.

어떤가요?

이것은 한개의 좌표가 주어지기 때문에 지정한 여러 유닛들은 한점을 향해 우루루 이동하게 됩니다.

한점으로 이동시키면 겹치는 부분이 조금 있습니다.

 

(▲ 한점으로 이동)

 

하지만, 이동할 목표지점이 여러부분으로 나뉘면 처음부터 조금 퍼져서 이동할 수 있죠.

 

(▲ 여러지점으로 나누어 이동)

 

어...음... 비교부분에서 전자가 조금 좋아보이긴 한데, 강좌에서는 여러지점으로 나누어 이동시키는 것을 만들어 볼 것입니다.

먼저 스프라이트 이미지를 준비합니다.

 

(▲플레이어 유닛 포지션 오브젝트에 사용할 이미지)

 

그리고 유닛의 포지션을 정해줄 오브젝트(obj_unit_position)를 하나 만듭니다.

 

(▲플레이어 유닛 포지션 오브젝트)

 

이 오브젝트는 화면에서 보이지 않아야 하기 때문에 Visible을 체크해제합니다.

 

그리고 [Create 이벤트]를 추가하고, 필요한 변수를 만들어 줍니다.

 


   //● obj_unit_position - Create 이벤트
   
   
   ind=0;//포지션 번호
   target=noone;//포지션을 정해줄 플레이어 유닛
   check=0;


 

하지만 이 오브젝트를 그냥 배치해도 겹칠 수 있어요.

그렇기 때문에 이것을 떨어 뜨려 놓아야 겠지요.

 

현 오브젝트(obj_unit_position)와의 [충돌 이벤트]를 추가하고, 아래와 같이 작성합니다.

 


   //● obj_unit_position - obj_unit_position 와의 충돌 이벤트
   
   
   var spd;
   spd=2;
   if x>other.x{x+=spd;}else{x-=spd;}
   if y>other.y{y+=spd;}else{y-=spd;}


 

아니 같은 오브젝트와 충돌이벤트를 작성해도 되냐구요?

됩니다.

이 충돌이벤트는 같은 오브젝트라도 게임 상에서는 서로 다른 인스턴스로 간주하기 때문에,

자신을 제외한 다른 인스턴스를 체크하게 되는 것이죠. 굳~

 

그래서 이 이벤트는 같은 오브젝트끼리 체크해서 충돌 하게 되면, 서로 밀려서 충돌 하지 않을 때까지 이동하게 됩니다.

결국 한 곳에 떨어 뜨려도 여러 방향으로 퍼지는 효과를 줄 수 있는 것이죠.

 

간단하게 유닛의 포지션을 정할 오브젝트를 만들었습니다.

이것을 시스템 오브젝트(obj_ctrl_sys)의 [Create 이벤트]에 생성하면 됩니다.

 

시스템 오브젝트(obj_ctrl_sys)로 이동해서 [Create 이벤트]에 아래와 같이 추가합니다.

 


   //● obj_ctrl_sys - Create 이벤트
   
   
   var i;
   i=0;
   repeat(12){
   it=instance_create_depth(x,y,0,obj_unit_position);
   it.ind=i;
   i+=1;
   }


 

이것은 유닛을 최대 선택 수만큼 생성하시면 됩니다.

강좌에서 설정한 선택할 수 있는 유닛 최대 인원수가 12이었죠.

이 강좌에서는 마찬가지로12개만 생성하도록 하겠어요.

 

다음은 마우스를 클릭했을 때, 이 포지션 오브젝트의 위치를 설정해주야 합니다.

시스템 오브젝트(obj_ctrl_sys)에서 [Step 이벤트]를 추가하고, 아래와 같이 작성합니다.

 


   //● obj_ctrl_sys - Step 이벤트
   
   
   //왼쪽 버튼을 누르면 포지션을 정할 유닛 해제
   if mouse_check_button_pressed(mb_left){
   with(obj_unit_position){target=noone;check=0;}
   }
   
   //마우스 좌표에서 가까운 위치에 랜덤으로 재배치
   if mouse_check_button_pressed(mb_right){
   with(obj_unit_position){check=1;
   x=mouse_x+irandom_range(-8,8);
   y=mouse_y+irandom_range(-8,8);}
   }


 

마우스 왼쪽 버튼을 누르면 유닛도 선택 해제되고, 포지션 오브젝트(obj_unit_position)는

포지션을 정해줄 유닛을 해제하게됩니다.

 

현 강좌에선 마우스 오른쪽 버튼은 이동으로 쓰일 것입니다.

따라서 마우스 오른쪽 버튼을 눌렀을 때 이 포지션 오브젝트(obj_unit_position)의 위치를

마우스 포인터 위치 주위로 재배치하게 되지요.

 

다음은 [End Step 이벤트]에 포지션 오브젝트에 이동시킬 유닛을 지정해줍니다.

아래와 같이 이전 강좌에서 작성한 코드 이벤트 중 해당 위치에 코드를 삽입해주면 됩니다.

 


   //● obj_ctrl_sys - End Step 이벤트
   
   
   var mx,my,mbc_L,mbp_L,mbc_R;
   mx=mouse_x;
   my=mouse_y;
   mbc_L=mouse_check_button(mb_left);
   mbp_L=mouse_check_button_pressed(mb_left);
   mbc_R=mouse_check_button(mb_right);
   
   
   var aa,bb;
   if mbp_L==1{
   with(obj_player){select=0;}
   aa=collision_point(mx,my,obj_player,1,1);
   if !(instance_exists(aa)){
   mouse_start_x=mx;mouse_start_y=my;
   pressed=1;}
   else{with(aa){select=1;}}
   }
   
   //유닛 선택
   
   var _x1,_y1,_x2,_y2;
   if pressed==1 && mbc_L==0{
   
   _x1=mouse_start_x;_y1=mouse_start_y;
   _x2=mx;_y2=my;
   if mouse_start_x>mx{_x1=mx;_x2=mouse_start_x;}
   if mouse_start_y>my{_y1=my;_y2=mouse_start_y;}
   
   var _sel,_max,it;
   _sel=0;_max=12;
   with(obj_player){
   if _sel<_max{
   if x>_x1 && y>_y1 && x<_x2 && y<_y2{
   select=1;
   //------------------- ▼ 삽입
   
   it=instance_find(obj_unit_position,_sel);
   if instance_exists(it){it.target=id;}
   
   //------------------- ▲ 삽입
   _sel+=1;}
   }
   }
   
   pressed=0;}
   
   
   //------------------- ▼ 삽입
   
   //유닛 이동
   
   if mbc_R==1{
   with(obj_player){if select==1{
   aa=collision_point(mx,my,obj_player,1,1);
   bb=collision_point(mx,my,obj_enemy,1,1);
   if !(instance_exists(bb)){
   if !(instance_exists(aa)){
   move_on=1;
   move_x=mx;move_y=my;
   target=noone;
   alarm[5]=point_distance(x,y,move_x,move_y)/pspeed;
   }
   }else{target=bb;}
   }}
   }
   //------------------- ▲ 삽입
   


 

어우~ 길어보이네요...

 

삽입한 부분은 유닛이 선택될 때, 같이 포지션 오브젝트(obj_unit_position)를 하나 선택하여,

선택된 유닛의 인스턴스 id를 저장하는 것이에요.

 

그리고 마우스 오른쪽 버튼을 눌렀을 때 선택된 플레이어에게 좌표를 지정하여 이동하게 하고,

이동시 시간 제한을 지정(alarm[5] 이벤트)합니다.

강좌에선 제한 시간은 이동 거리를 속도로 나눈 값을 넣었습니다.

이것은 예를 들어 유닛의 속도가 2라고 하고, 이동거리를 320정도라면, 1스텝당 2정도 속도로

이동해서 320/2로 약160스텝정도에 목표 지점에 도착하게 됩니다.(1알람=1스텝)

제한 시간을 좀 더 길게 하고 싶다면, 값을 좀 더 높게 입력하시면 되겠죠.

 

 

만약 이동 위치에 적이 있을 경우 공격 목표로 정하고, 아니라면 그냥 이동만 하는 것이죠.

이 공격에 대한 구체적인 설정은 다음 강좌에서 해볼 것입니다.

 

다음은 포지션 오브젝트(obj_unit_position)이 선택되어진 유닛들의 이동할 위치를 정해주게 해봅시다.

[End Step 이벤트]에 아래와 같이 추가합니다.

 


   //● obj_ctrl_sys - End Step 이벤트
   
   
   var mx,my,mbc_L,mbp_L,mbc_R;
   mx=mouse_x;
   my=mouse_y;
   mbc_L=mouse_check_button(mb_left);
   mbp_L=mouse_check_button_pressed(mb_left);
   mbc_R=mouse_check_button(mb_right);
   
   
   var aa,bb;
   if mbp_L==1{
   with(obj_player){select=0;}
   aa=collision_point(mx,my,obj_player,1,1);
   if !(instance_exists(aa)){
   mouse_start_x=mx;mouse_start_y=my;
   pressed=1;}
   else{with(aa){select=1;}}
   }
   
   //유닛 선택
   
   var _x1,_y1,_x2,_y2;
   if pressed==1 && mbc_L==0{
   
   _x1=mouse_start_x;_y1=mouse_start_y;
   _x2=mx;_y2=my;
   if mouse_start_x>mx{_x1=mx;_x2=mouse_start_x;}
   if mouse_start_y>my{_y1=my;_y2=mouse_start_y;}
   
   var _sel,_max,it;
   _sel=0;_max=12;
   with(obj_player){
   if _sel<_max{
   if x>_x1 && y>_y1 && x<_x2 && y<_y2{
   select=1;
   
   it=instance_find(obj_unit_position,_sel);
   if instance_exists(it){it.target=id;}
  
   _sel+=1;}
   }
   }
   
   pressed=0;}
   
  
   
   //유닛 이동
   
   if mbc_R==1{
   with(obj_player){if select==1{
   aa=collision_point(mx,my,obj_player,1,1);
   bb=collision_point(mx,my,obj_enemy,1,1);
   if !(instance_exists(bb)){
   if !(instance_exists(aa)){
   move_on=1;
   move_x=mx;move_y=my;
   target=noone;
   alarm[5]=point_distance(x,y,move_x,move_y)/pspeed;
   }
   }else{target=bb;}
   }}
   }

  
   //------------------- ▼ 이어서 추가
  
   with(obj_unit_position){

   if instance_exists(target){
   if check==1{
   with(target){if select==1{move_x=other.x;move_y=other.y;}}
   }
   }
   else{target=noone;}
   }
  
   //------------------- ▲ 이어서 추가



 

[Step 이벤트]에서 마우스 오른쪽 버튼을 눌렀을 때, 포지션 오브젝트(obj_unit_position)의

check변수를 1로 했었지요.

왼쪽 버튼을 눌렀을 때는 check변수를 0으로 만들었고요.

따라서 오른쪽 버튼을 눌렀을 때 선택된 유닛의 이동할 위치(move_x,move_y)값을

포지션 오브젝트(obj_unit_position)의 위치로 이동하게 하는 것입니다.

왼쪽 버튼을 눌렀다면 유닛을 해제하는 것이죠.

 

 

좋습니다~! 드디어 이동하는 것까지 해보았습니다.

제대로 이동하는지 테스트 해봅시다.

 

(▲테스트 화면)

 

 

이번 강좌는 그리 길지 않았던것 같네요.

어째든 재밌는 게임을 만들어 봅시다.

 

 

다음 강좌에서는 플레이어 유닛의 공격 설정에 대해 다뤄 보도록 해요.

 

 

 

- 다음 편에서 계속 -

 

 

strategy_rts_example01a_2.yyz
0.05MB

 

 

 

 

 

300x250

댓글