2019년 6월 15일 토요일

GMS2 Object Depth, Object 간 depth 출력


서론
GMS에서 여러개의 Object가 Draw될때 서로 겹치는 부분이 발생합니다. 겹치는 부분에 있어서 어떤 Object를 출력 할지 결정하는것이 이번 시간의 내용입니다.

Object의 출력을 Layer에 넣고 출력하면 될텐테 만약 같은 layer라면 출력 순서를 어떻게 정하면 될까요?

아래 동영상을 보면 이해하기가 쉽습니다.

https://youtu.be/rcMHwdvEDy0


이론은 간단
일반적으로 3차원에서는 Z축이 존재하고 Z-order 로 멀리있는것을 먼저 출력하게 됩니다.
2D에서는 일반적으로 정면 45도 각도 위에서 아래쪽을 내려다 보는 형태로 많이 제작하므로, 동일하게 멀리 있는것은 먼저 출력해주면 됩니다.
여기 예제에서는 Y축이 작을수록 위쪽에 위치해 있으므로 먼저 출력되도록 하면됩니다.

아래 그림에서 좌측은 원본이고, 우측이 원하는 결과 입니다.



구현 절차

0. object 생성

object0,1,2 와 object_draw(room에 sprite없이 추가), object_parent(draw object의 부모)

1. draw할 object 부모 설정

많은 코드가 중복되므로 중복을 막기 위해 부모 object_parent를 설정합니다.
자식은 object0, 1, 2 를 가집니다. 더 많은 object가 있다면 더 추가해도 됩니다.

2. object의 draw막기

object_parent 의 Draw 이벤트를 막습니다.
막는방법은 핸들러를 생성하기만 하면 됩니다.

3. draw 원하는 object 들의 정보를 모으기

원하는 정보는 Pre-Draw에서 모을 수 있습니다. pre-Draw 핸들러는 scr_addto_depthgrid() 스크립트를 호출 하도록 합니다. 이곳에는 object들을 grid에 모으는 역할을 합니다.

scr_addto_depthgrid() 스크립트
with(object_draw){
 if( !ds_exists(ds_depthgrid,ds_type_grid) ){
  //         objname, y
  // object
  
  // 2는  objname, y 2개 이기 때문에 
  // 1은 처음 만들어서 데이터가 없기 때문에
  ds_depthgrid = ds_grid_create(2,1)
  ds_grid_set(ds_depthgrid,0,0,other)
  ds_grid_set(ds_depthgrid,1,0,other.y)
 }else{
  gridheight = ds_grid_height(ds_depthgrid)
  // grid 크기 하나 더 늘림
  ds_grid_resize(ds_depthgrid,2,gridheight+1)
  ds_grid_set(ds_depthgrid,0,gridheight,other)
  ds_grid_set(ds_depthgrid,1,gridheight,other.y)
 }
}

ds_grid_create grid를 만듭니다. grid는 2차원 배열입니다.
ds_grid_set 는 grid특정 위치에 값을 넣습니다.
ds_grid_height grid의 높이를 구합니다.
ds_grid_resize gird크기를 변경합니다.

object_draw에 멤버로 있는 gird인 ds_depthgrid를 생성하여 object들을 하나씩 넣습니다. 이때 y값도 같이 넣습니다. 만약 메모리가 부족하다면 gird크기를 하나씩 증가시킵니다.

4. 모은 정보를 이용하여 Y축결과로 sort하기

모아진 gird는 object_draw라는 object의 멤버 grid로 모아집니다. 그래서 create 이벤트에 ds_depthgrid=0 값을 추가 하도록 합니다.
그리고 나서 draw 핸들러에서 Y값 기반으로 sort를 합니다.
ds_grid_sort(ds_depthgrid,1,true)

5. sort된 결과로 draw를 한꺼번에 하기

object_draw Draw 핸들러
if(ds_exists(ds_depthgrid,ds_type_grid)){

 ds_grid_sort(ds_depthgrid,1,true)
 
 dsheight = ds_grid_height(ds_depthgrid)
 for( i=0;i<dsheight;i++){
  instance = ds_grid_get(ds_depthgrid,0,i)
  with(instance){
   draw_self()
  }
 }
 
 ds_grid_destroy(ds_depthgrid)
}

정렬된 grid에서 ds_grid_get을 이용하여 저장된 object를 꺼내서 draw_self()하게되면 이미지가 draw됩니다.

6. 누수 방지

마지막으로 Destory에는 메모리 누수 방지를 위해서 메모리 해제 코드를 한번 더 추가합니다.
object_draw Destory 핸들러
if(ds_exists(ds_depthgrid,ds_type_grid)){
 ds_grid_destroy(ds_depthgrid)
}


7. 테스트를 위한 처리

object2에 키보드 조작을 위한 step핸들러 추가

if keyboard_check(vk_left){
 x=x-1
}

if keyboard_check(vk_right){
 x=x+1
}

if keyboard_check(vk_up){
 y=y-1
}

if keyboard_check(vk_down){
 y=y+1
}


댓글 없음:

댓글 쓰기