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

[게임메이커강좌-전략]RTS 게임 만들기 - 5 미니맵 구성

by 타락카얀 2013. 7. 2.
728x90



GAME MAKER 강좌

 

 

KAYAN

 

 

 

☆이번에는 화면 상단에 미니맵을 구성하는 것에 대해 알아 볼 것입니다.

 

 

(▲게임 화면)

 

 

 

 

 

 

 

◈미니맵 구성(obj_ctrl_sys)

 

 

 

간단하게 적의 위치와 지금 어느 위치를 보고 있는지 확인할 수 있는 미니맵을 구성해봅시다.

 

 

(▲이번 강좌에서 만들게 될 미니맵)


먼저 게임을 제어하는 시스템 오브젝트(obj_ctrl_sys)로 이동해서, Create 이벤트필요한 변수들을 추가해줍니다.

 

     ★ obj_ctrl_sys - Create 이벤트

     minimap_width=160;//미니맵 가로 사이즈
     minimap_height=120;//미니맵 세로 사이즈
     minimap_click=0;//마우스 포인터가 미니맵 안에 있는지 체크


이것은 미니맵의 크기를 미리 정해주는 것입니다.

다음은 Draw 이벤트에서, 아래와 같이 추가해 미니맵의 위치와 모양을 표시해주도록 해요.

 

     ★ obj_ctrl_sys - Draw 이벤트

     var _w,_h,vx,vy,vw,vh;
     vx=view_xview[0];//미니맵의 표시 기준점
     vy=view_yview[0];//미니맵의 표시 기준점
     vw=view_wview[0];
     vh=view_hview[0];
     _w=minimap_width;
     _h=minimap_height;

     c=c_dkgray;draw_rectangle_color(vx,vy,vx+_w,vy+_h,c,c,c,c,0);//미니맵 바탕
     c=c_gray;draw_rectangle_color(vx,vy,vx+_w,vy+_h,c,c,c,c,1);//미니맵 외곽선


이것은 어두운 회색 바탕의 약간 밝은 회색의 외곽선을 가진 사각형 모양의 미니맵입니다.

 

강좌에서 미니맵의 위치는 (vx, vy)좌표, 즉, 뷰의 좌표인(view_xview[0], view_yview[0])의 좌표를 기준으로

표시됩니다. 만약, 미니맵의 위치를 변경하고 싶다면, 뷰의 좌표에 위치를 추가하시면 됩니다.

예를 들어 화면의 (32, 320) 위치에 미니맵을 표시하고 싶다면, (view_xview[0]+32,view_yview[0]+320)

위치에 미니맵을 표시하세요.

 

     예)

     var _w,_h,vx,vy,vw,vh;
     vx=view_xview[0]+32;//변경된 좌표
     vy=view_yview[0]+320;//변경된 좌표
     _w=minimap_width;
     _h=minimap_height;

     c=c_dkgray;draw_rectangle_color(vx,vy,vx+_w,vy+_h,c,c,c,c,0);//미니맵 바탕
     c=c_gray;draw_rectangle_color(vx,vy,vx+_w,vy+_h,c,c,c,c,1);//미니맵 외곽선

 

다음은 뷰의 위치와 크기를 표시해볼까요.
마찬가지로 Draw이벤트에서, 위의 내용 밑에 아래와 같이 추가합니다.

 

     ★ obj_ctrl_sys - Draw 이벤트

     _px=(view_xview[0]*_w)/room_width;
     _py=(view_yview[0]*_h)/room_height;
     _pw=(view_wview[0]*_w)/room_width;
     _ph=(view_hview[0]*_h)/room_height;
     c=c_white;draw_rectangle_color(vx+_px,vy+_py,vx+_px+_pw,vy+_py+_ph,c,c,c,c,1);


흰색의 사각형모양으로 뷰의 크기와 위치를 확인할 수 있게 만들었습니다.
뷰의 위치와 크기를 미니맵 크기로 환산하자면 아래와 같은 식으로 구할 수 있습니다.

     값=(실제 변동하는 크기X환산할 최대치)/실제 최대 크기

예를 들면 미니맵의 넓이가 160일때 룸 넓이(room_width)를 기준으로 뷰의 x좌표를 미니맵 크기로 환산한다면

     값=(view_xview*160)/room_width

이렇게 됩니다. 간단하죠. 헤헤~
이제 이 식으로 유닛의 위치도 표시해보도록 해요.
Draw 이벤트에 아래와 같이 추가하여, 유닛들의 위치를 표시하도록 합니다.

 

     ★ obj_ctrl_sys - Draw 이벤트

     with(obj_player){
     if x>0 && y>0 && x<room_width && y<room_height{//룸 내에 있을 때만 표시함.
     _x=(x*_w)/room_width;
     _y=(y*_h)/room_height;
     draw_point_color(vx+_x,vy+_y,c_yellow);//플레이어는 노란색
     }}

     with(obj_enemy){
     if x>0 && y>0 && x<room_width && y<room_height{
     _x=(x*_w)/room_width;
     _y=(y*_h)/room_height;
     draw_point_color(vx+_x,vy+_y,c_red);//적은 붉은 색
     }}


이것은 유닛이 룸 내에 있을 때만 위치를 표시하게 됩니다.
룸 밖에 있을 때도 표시한다면 미니맵에서 벗어나 보기에 안 좋겠지요.
표시색은 되도록이면 눈에 잘보이는 색으로 표시하도록 해요.



◈미니맵에서 드래그해 뷰를 이동시키기(obj_ctrl_sys)

 

 


다음은 미니맵에서 드래그해 뷰를 이동 시켜 보도록 만들어 보아요.
이 이벤트는 사용자 정의 이벤트(User Defined)를 이용해보도록 하겠습니다.
사용자 정의 이벤트(User Defined)는 이벤트에서 직접 실행시키지 않으면, 이벤트가 발생되지 않지만, 이벤트를

호출하게 되면 바로 실행시킬 수 있는 이벤트입니다.
뭐- 이를테면 대기 이벤트라고 볼 수 있지요.

이벤트 메뉴-> Other -> User Defined -> User 0 이벤트를 추가하고, 아래와 같이 작성합니다.

 

     ★ obj_ctrl_sys - User Defined 0 이벤트

     var _w,_h,vx,vy,vw,vh,mx,my;
     vx=view_xview[0];//미니맵의 표시 기준점
     vy=view_yview[0];//미니맵의 표시 기준점
     vw=view_wview[0];
     vh=view_hview[0];
     mx=mouse_x;
     my=mouse_y;
     _w=minimap_width;
     _h=minimap_height;

     //뷰 드래그
     if mx>vx && my>vy && mx<vx+_w && my<vy+_h && pressed=0{//마우스 포인터가 미니맵 안에 있을 때

     _x=floor(((mx-vx)*room_width)/_w);
     _y=floor(((my-vy)*room_height)/_h);
     if mouse_check_button(mb_left){
     view_xview[0]=max(0,min(_x-(vw/2),room_width-vw));
     view_yview[0]=max(0,min(_y-(vh/2),room_height-vh));
     }
     minimap_click=1;
     }


이것은 마우스 포인터가 미니맵 안에 있을 때, 그리고 유닛을 선택하려고 드래그 하지 않았을 때 발생하게 합니다.
그리고 뷰의 위치를 미니맵에서 실제 크기로 환산하여 재배치하게 됩니다.
이때 미니맵 안에 있을 때 필드의 상황에 영향을 주지 않도록 minimap_click변수의 값을 1로 만들 놓습니다.

이제 이 이벤트를 End Step이벤트에서 호출 시켜 봅시다.
End Step 이벤트에 아래와 같이 추가합니다.

 

     ★ obj_ctrl_sys - End Step 이벤트

     //------------------------▼추가
     event_user(0);                                ◀미니맵 이벤트 호출
     //------------------------▲추가

     var mx,my;
     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);

     //------------------------▼수정
     if mbp_L=1 && minimap_click=0{      ◀유닛 선택은 미니맵 밖에 있을 때 발생하도록 변경
     //------------------------▲수정
     with(obj_player){select=0;}
     aa=collision_point(mx,my,obj_player,1,1);
     if !(instance_exists(aa)){mp_x=mx;mp_y=my;pressed=1;}
     else{with(aa){select=1;}}
     }
     //유닛 드래그 선택
     var _x1,_y1,_x2,_y2;
     if pressed=1 && mbc_L=0{

     _x1=mp_x;_y1=mp_y;
     _x2=mx;_y2=my;
     if mp_x>mx{_x1=mx;_x2=mp_x;}
     if mp_y>my{_y1=my;_y2=mp_y;}

     var _sel,_max;
     _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 && minimap_click=0{      ◀유닛 선택은 미니맵 밖에 있을 때 발생하도록 변경
     //------------------------▲수정

     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{
     move_on=1;
     move_x=mx;move_y=my;target=bb;
     alarm[5]=point_distance(x,y,move_x,move_y)/pspeed;
     }
     }}
     }


     //---------------move pointer--------------
     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;}}

     //------------------------▼추가
     if minimap_click=1{pressed=0;minimap_click=0;}//미니맵 체크를 다시 초기화함
     //------------------------▲추가


으아아~ 이렇게 보니 복잡해보이네요. 헤헤~
이 설정, 저 설정 넣다보면 느는건 코드양입니다. 전략 게임을 만들다보면 어쩔 수 없는 부분이죠.

이것은 event_user(이벤트 번호)로 사용자 정의 이벤트를 호출할 수 있으며, 호출하는 즉시 이벤트가 발생하게 됩니다.
그리고 미니맵에서 뷰를 드래그하는 것은 유닛 선택부분보다 먼저 발생하도록 처리합니다.


이제 잘되는지 테스트 해봅시다.

 

 

 

 

 

 

 

◈미니맵을 통한 유닛의 이동(obj_ctrl_sys)

 
이번에는 유닛을 선택한 후, 미니맵을 클릭해 이동시켜 보도록 해요.

마찬가지로 사용자 정의 이벤트(User Defined)를 이용하도록 합시다.
이벤트 메뉴-> Other -> User Defined -> User 1 이벤트를 추가하고, 아래와 같이 작성합니다.

 

     ★ obj_ctrl_sys - User Defined 1 이벤트

     var _w,_h,vx,vy,vw,vh,mx,my;
     vx=view_xview[0];//미니맵의 표시 기준점
     vy=view_yview[0];//미니맵의 표시 기준점
     vw=view_wview[0];
     vh=view_hview[0];
     mx=mouse_x;
     my=mouse_y;
     _w=minimap_width;
     _h=minimap_height;

     //유닛 이동
     if minimap_click=1{//미니맵 안에 있고
     if mouse_check_button_pressed(mb_right){//마우스 오른쪽 버튼을 눌렀을 때 발생
     var _x,_y;
     _x=((mx-vx)*room_width)/_w;
     _y=((my-vy)*room_height)/_h;

     with(obj_unit_position){check=1;
     x=_x+irandom_range(-8,8);
     y=_y+irandom_range(-8,8);}

     with(obj_player){if select=1{
     move_on=1;
     move_x=_x;move_y=_y;target=noone;
     alarm[5]=point_distance(x,y,_x,_y)/pspeed;
     }}

     }}


저번 강좌에서 이동 설정에 대해 해보았죠?
넵. 그것과 같은 것입니다.
조금 다르다면 목표물(target) 설정이 없다는 것뿐이죠.
미니맵에서 실제크기로 좌표를 환산하여, 유닛 포지션 오브젝트(obj_unit_position)의 위치를 지정해주고, 선택된

유닛들의 위치도 지정하여 이동 시키는 것입니다.

 

이제 이 이벤트를 End Step이벤트에서 호출 시켜 봅시다.
End Step 이벤트에 아래와 같이 추가합니다.

 

     ★obj_ctrl_sys - End Step 이벤트

     //------------------------미니맵
     event_user(0);
     //------------------------미니맵

     var mx,my;
     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);

     if mbp_L=1 && minimap_click=0{
     with(obj_player){select=0;}
     aa=collision_point(mx,my,obj_player,1,1);
     if !(instance_exists(aa)){mp_x=mx;mp_y=my;pressed=1;}
     else{with(aa){select=1;}}
     }
     //select
     var _x1,_y1,_x2,_y2;
     if pressed=1 && mbc_L=0{

     _x1=mp_x;_y1=mp_y;
     _x2=mx;_y2=my;
     if mp_x>mx{_x1=mx;_x2=mp_x;}
     if mp_y>my{_y1=my;_y2=mp_y;}

     var _sel,_max;
     _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 && minimap_click=0{
     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{
     move_on=1;
     move_x=mx;move_y=my;target=bb;
     alarm[5]=point_distance(x,y,move_x,move_y)/pspeed;
     }
     }}
     }

     //-----------------------▼삽입
     event_user(1);                                ◀미니맵 클릭 이벤트 호출
     //-----------------------▲삽입

     //---------------move pointer--------------
     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;}}

     //------------------------minimap
     if minimap_click=1{pressed=0;minimap_click=0;}
     //end


캬아~ 길다~
위의 위치에 호출 이벤트를 한줄 삽입하시면 됩니다.

이렇게 하면 미니맵을 클릭했을 때 선택된 유닛이 해당 좌표로 이동해요.

 

 

와우~! 드디어 미니맵이 완성되었습니다.
테스트! 테스트를 해봅시다. 하악~!

 

(▲테스트 화면)


후아~ 강좌는 여기까지입니다.
기초적인 부분만 설명했으나, 강좌가 많이 복잡했는데, 재미있으셨는지 모르겠네요.

이제 여러분이 이 강좌를 토대로 응용하셔서 게임을 제작하시면 됩니다.

어째든 재미있는 게임을 만들어 보도록 해요. 아자~!^^


- 끝 -


 

 

 

--------- 예 제 --------

 

 

strategy-RTSX-1-5.gmk
다운로드

 

 

strategy-RTSX-1-5.exe
다운로드

 

 

 

 

300x250

댓글