본문 바로가기
GameMaker강좌[GMS2]/기타장르강좌

[게임메이커 강좌-기타][GMS2]그리드 기반의 길찾기-2 응용편1

by 타락카얀 2023. 1. 11.
728x90

 

 

GAME MAKER 강좌

 

KAYAN

 

 

 

 

 

◈ 그리드 기반의 길찾기(Path finding) 응용편1

 

 

이번 강좌에서는 길찾기를 직접 구성해봅시다.

 

강좌에서는 마우스를 클릭하면 그 위치로 플레이어가 이동하도록 만들 거에요.

 

(▲ 마우스를 클릭하면 이동)

 

먼저 룸 시작시 그리드와 패스를 만들어야 합니다.

그리드와 패스를 만들 오브젝트( obj_system )를 하나 추가하고 [Room Start 이벤트]를 추가합니다.

 


   //● obj_system - Room Start 이벤트
   
   global.grid=32;
   global.move_grid=mp_grid_create(0,0,ceil(room_width/global.grid),ceil(room_height/global.grid),global.grid,global.grid);
   
   global.move_path=path_add( );


 

그리드는 룸의 크기 만큼 셀을 만듭니다.

그러면 룸 내의 그리드 크기만큼 좌표를 사용할 수 있게 됩니다.

 

강좌에서는 그리드의 크기를 32X32 정도의 크기로 설정했습니다만, 크기가 크면 좀 더
간결하게 이동할 수 있고, 작으면 정교하게 패스를 만들 수 있습니다.
다만, 이동하는 오브젝트의 이미지 크기를 고려해 그리드의 크기를 결정하는 것이 좋습니다.

 

그리드를 사용하는 모든 룸의 크기가 동일하다면 한 번만 만들어도 되지만, 룸마다 크기가 다를 수

있으므로 룸 시작시 다시 만드는 방법을 사용하는 것이 좋습니다.

다만, 패스 같은 경우는 변경할 부분이 없기 때문에 룸 시작시 만들어도 되지만, 게임 시작시 한 번만

만들어도 됩니다.

일단 강좌에서는 룸 시작시에 만드는 것으로 하겠습니다.

 

그리고 룸 종료시 그리드와 패스를 파기하도록 합니다.

 


   // obj_system - Room End 이벤트
   
   mp_grid_destroy(global.move_grid);
   
   path_delete(global.move_path);


 

이와 같이 하면 룸 시작시에 룸에 사용할 그리드와 패스를 만들고, 다음 룸으로 갈 때,

현재 룸에서 사용한 그리드와 패스를 파기하고 이동합니다.

물론 다음 룸에도 그리드를 사용한다면 다시 새로 만들고, 파기하게되는 것이죠. 단순합니다.

 

 

플레이어 오브젝트( obj_player )를 하나 만듭니다.

플레이어의 이미지는 그리드 셀 중심에 위치하도록 중심점을 맞춰주세요.

 

(▲ 플레이어의 이미지는 그리드 셀 중심에 위치하도록 설정)

 

오브젝트에 [Create 이벤트]를 추가하고 이동에 관련된 변수를 선언해줍니다.

이벤트를 구성하다 필요한 변수가 있다면 하나씩 추가해주면 됩니다.

 


   // obj_player - Create 이벤트
   
   move_on=0;


 

[Step 이벤트]를 추가하고, 여기서 패스 이동을 구성하겠습니다.

먼저, 마우스 좌표를 만들어 봅시다.

패스는 그리드 셀 중심을 지나가기 때문에 마우스 좌표는 그리드 셀 중심에 위치하도록 마우스 좌표 값을 변환합니다.

그래야 패스를 구성할 때, 정확한 위치가 구성되기 때문이죠.

 


   // obj_player - Step 이벤트
   
   var mx,my;
   mx=(floor(mouse_x/global.grid)*global.grid)+floor(global.grid/2);
   my=(floor(mouse_y/global.grid)*global.grid)+floor(global.grid/2);


 

마우스 좌표를 그리드 셀 크기만큼 나누고, 소수점을 버린 후, 다시 곱해주면

셀 좌측 상단의 좌표를 얻을 수 있습니다. 여기에 다시 그리드 셀 크기의 반을 더해주면

셀의 중심 좌표를 얻을 수 있습니다.

 

다음은 마우스를 클릭 했을 때, 패스를 작성하기 전에 장애물을 먼저 추가해줍니다.

장애물을 추가하기전에 mp_grid_clear_all 함수를 사용하여 모든 장애물을 클리어해주고,

mp_grid_add_instances 함수로 간단하게 장애물 오브젝트를 추가해주면 됩니다.

 

장애물이 추가된 셀은 패스를 생성할 수 없기 때문에, 마우스를 클릭할 때 장애물을

미리 체크하도록 합니다.

 


   // obj_player - Step 이벤트
   
   var _x,_y,_break;
   _break=0;
   
   if move_on==0{
   
   if position_meeting(mx,my,obj_block){ _break=1; }//장애물 체크
   
   if mouse_check_button_pressed(mb_left) && _break==0{//마우스 클릭
   
   mp_grid_clear_all(global.move_grid);//장애물 위치 클리어
   mp_grid_add_instances(global.move_grid,obj_block,0);//장애물을 그리드에 마킹
   
   }
   }


 

이제 패스를 생성하도록 합니다.

패스는 현재 위치를 시발점으로 마우스 위치까지 이동시키도록 설정합니다.

 


   // obj_player - Step 이벤트
   
   var _break;
   _break=0;
   
   if move_on==0{
   
   if position_meeting(mx,my,obj_block){ _break=1; }
   
   if mouse_check_button_pressed(mb_left) && _break==0{
   
   mp_grid_clear_all(global.move_grid);
   mp_grid_add_instances(global.move_grid,obj_block,0);
   
   //--------- ▼ 추가
   
   x=(floor(x/global.grid)*global.grid)+floor(global.grid/2);
   y=(floor(y/global.grid)*global.grid)+floor(global.grid/2);
   
   mp_grid_path(global.move_grid,global.move_path,x,y,mx,my,0);//패스 생성
   
   //--------- ▲ 추가
   
   }
   }


 

강좌에서는 패스의 대각선을 허용하지 않고, 직선으로만 구성하도록 설정하겠습니다.

 

이동할 수 있는 패스는 포인트 구간이 최소 2개 이상이어야 합니다.

 

(▲ 패스 포인트가 2개 이상일 경우 이동함)

 

따라서 패스 포인트가 2개 이상일 때, path_start 함수를 사용하여 이동시키도록 합니다.

 


   // obj_player - Step 이벤트
   
   var _break;
   _break=0;
   
   if move_on==0{
   
   if position_meeting(mx,my,obj_block){ _break=1; }
   
   if mouse_check_button_pressed(mb_left) && _break==0{
   
   mp_grid_clear_all(global.move_grid);
   mp_grid_add_instances(global.move_grid,obj_block,0);
   
   
   x=(floor(x/global.grid)*global.grid)+floor(global.grid/2);
   y=(floor(y/global.grid)*global.grid)+floor(global.grid/2);
   
   mp_grid_path(global.move_grid,global.move_path,x,y,mx,my,0);
   
   //--------- ▼ 추가
   
   if path_get_number(global.move_path)>=2{
   pspeed=2;
   path_start(global.move_path,pspeed,0,1);//패스를 따라 이동
   move_on=1;
   }
   
   //--------- ▲ 추가
   
   }
   }


 

마지막으로 플레이어가 패스의 도착지점에 이동해 있다면, 패스를 완전히 종료 하도록 합니다.

여기서는 현재 좌표를 갱신하거나, 다른 변수들을 초기화시키면 됩니다.

 


   // obj_player - 이벤트
   
   
   if move_on==1{
   if path_position==1{
   
   path_end( );//패스 종료
   
   x=(floor(x/global.grid)*global.grid)+floor(global.grid/2);//위치 갱신
   y=(floor(y/global.grid)*global.grid)+floor(global.grid/2);
   
   move_on=0;//이동 초기화
   
   path_clear_points(global.move_path);//패스 클리어
   
   }
   }


 

완성되었네요.

패스로 이동하는 오브젝트를 룸에 배치시 그리드 셀 중심에 위치하도록 배치하세요.

 

배치가 끝났다면 잘 되는지 테스트 해봅시다.

 

 

※ 패스가 잘 구성되는지 확인하고 싶을 때는 [Draw 이벤트] 에서 draw_path 함수를 사용하면

사용중인 패스를 간단하게 표시할 수 있습니다.

예)


   //● obj_system - Draw 이벤트

   
  

   draw_path(global.move_path,0,0,1);

 

(▲ 테스트)

 

이 방식은 그리드 기반으로는 가장 기본적인 이동방식입니다.

패스를 오브젝트에서 단일 방식으로 공유하여 고정적인 패스를 사용하기 때문에 오브젝트를

한번에 한개만 이동시킬 수 있습니다.

 

 

pathfinding_example1.yyz
0.04MB

 

 

 

 

 

300x250

댓글