본문 바로가기
GameMaker강좌[GM8]/3D기능강좌

[게임메이커강좌-3D 강좌]간단한 FPS게임 만들기-3-필드의 아이템 체크와 계단 이동

by 타락카얀 2014. 1. 1.
728x90

 

 

GAME MAKER 강좌

 

 

KAYAN

 

 

이번 강좌에서는 필드의 아이템을 체크하는 방법과 계단을 이동하는 방법에 대해 알아보도록 합시다.

 

 

(▲ 계단)

 

 

(▲ 아이템 체크)


강좌 2까지 따라해보셨다면 이번 강좌는 응용편이 되겠군요.
먼저 필드에 있는 아이템을 체크하는 방법에 대해 알아봅시다.

 

 

 

 

 

 

 

 

 

 

 

◈ 필드의 아이템 체크(obj_item)

 


일단 아이템을 체크하려면 아이템 오브젝트(obj_item)가 있어야 겠지요.
아이템 오브젝트를 하나 만들고, 룸에 배치할 수 있게 Sprite에 적당한 스프라이트 이미지를

지정하도록 해요.

물론 이 스프라이트 이미지는 마스크 역할도 같이 할 것입니다.

 

 

(▲ 아이템 오브젝트)


그리고 Create 이벤트를 추가하고, 간단하게 Z축과 높이에 대한 변수들을 선언하도록 합니다.
(블럭들과 마찬가지로 3D상에서 체크할 수 있어야 하기 때문)

 



     ★ obj_item - Create 이벤트

     z=0;//z축
     ztop=5;//높이

     color=c_white;//체크 확인


 

color 변수는 테스트시 체크가 되었는지 확인하기 위해 변수를 작성했습니다.
체크가 되면 빨간색으로 변하게 되고, 그렇지 않으면 일반적인 모습이 되는 것이지요.

이제 아이템 모델을 표시하도록 합시다.

 

 

(▲ 임시 아이템)


강좌에선 간단하게 체크가 되는지 확인만 할것이라 위와 같은 형태로 표시하겠지만,

여러분은 어느정도 모습을 갖춘 모델로 표시하도록 하세용.

먼저 텍스쳐로 사용할 이미지를 배경이미지(back_item)로 준비하도록 해요.

 

 

(▲ 아이템 텍스쳐)


그리고 Draw 이벤트를 추가하고, 모델을 표시하도록 합시다.

 



     ★ obj_item - Draw 이벤트

     draw_set_color(color);//카메라(플레이어)에서 체크했을때 색을 혼합시킴
     draw_set_alpha(1);
     texid=background_get_texture(back_item);//텍스쳐

     d3d_transform_add_translation(x,y,z+1);
     d3d_draw_floor(-8,-8,0,8,8,0,texid,1,1);//아이템 표시
     d3d_transform_set_identity();

     draw_set_color(c_white);//혼합시켰던 색을 다시 기본 값으로 되돌림.

     color=c_white;//체크 혼합색 초기화



이것은 카메라(플레이어)로부터 체크가 되었을 때, color 변수 값에 따라 모델을 체크되었는지 식별이

가능하도록 어떠한 색을 혼합시켜 표시할 것이고, 그렇지 않을 경우는 원래 모습으로 표현할 것입니다.

 

 

(▲ color값에 따른 아이템 체크 표현)


이제 카메라 오브젝트, 그러니까 플레이어에서 이 아이템을 체크하게 하면 되는 것입니다.
먼저 체크할 스크립트를 하나 만듭시다.

 



     ★ 스크립트 - place_3d_inst_ext

     //place_3d_inst_ext(obj,x,y,zmin,zmax);

     var _obj,it,i,n,_x,_y,_z1,_z2,_zc,_on,_d1,_d2,_inst;
     _obj=argument0;
     _x=argument1;
     _y=argument2;
     _z1=argument3;
     _z2=argument4;
     n=instance_number(_obj);
     _on=0;

     _inst=noone;

     if !(collision_point(_x,_y,_obj,1,1)=noone){
     for(i=0;i<n;i+=1;){it=instance_find(_obj,i);
     if !(collision_point(_x,_y,it,1,1)=noone){
     //---------------------------
     _zmin=it.z;
     _zmax=it.z+it.ztop;
     _d1=abs(_z2-_z1);
     _d2=abs((_zmax)-_zmin);

     if _d1<=_d2{

     _zc=_z1+(_d1/2);
     if (_zmin<_z1 && _zmax>_z1) || (_zmin<_z2 && _zmax>_z2) || (_zmin<_zc && _zmax>_zc){

     _on=1;_inst=it;break;}
     }

     else{
     _zc=_z1+(_d2/2);
     if (_z1<_zmin && _z2>_zmin) || (_z1<_zmax && _z2>_zmax) || (_zmin<_zc && _zmax>_zc){

     _on=1;_inst=it;break;}
     }
     //---------------------------
     }}
     }

     return _inst;



이 스크립트는 이전에도 만들어 보셨죠.
좌표만 따로 입력할 수 있게 만든 place_3d_inst 의 확장 스크립트입니다.

     place_3d_inst_ext(obj,x,y,zmin,zmax)

     obj : 충돌 대상
     x, y : 현재 좌표
     zmin : 현 오브젝트 z좌표의 최소값
     zmax : 현 오브젝트 z좌표의 최대값

 

(▲ 스크립트의 체크 방식)


이전 스크립트와 마찬가지로 충돌하는 블럭 중 높이별로 3등분하여 어느 한쪽이라도 걸린다면

그 블럭의 ID를 반환하는 스크립트입니다.


강좌에서 아이템 체크는 아래와 같은 방식으로 체크 할 것입니다.

 

 

(▲ 아이템 체크 방식)


이것은 카메라(obj_cam)으로 부터 아이템 체크 가능한 거리를 여러개로 나누어 분기별로 조금씩

이동하면서 체크하는 방식입니다.

카메라 오브젝트(obj_cam)으로 이동해서, Draw 이벤트 끝에 아이템 체크 이벤트를 추가 작성하도록

합시다.

 



     ★ obj_cam - Draw 이벤트

     //체크 가능한 거리는 64, 카메라로부터 2씩 보는 방향으로 이동하며 체크
     for(i=0;i<64;i+=2;){

     _x=x+lengthdir_x(lengthdir_x(i,cam_yang),cam_zang);
     _y=y+lengthdir_y(lengthdir_x(i,cam_yang),cam_zang);
     _z=z+eye-lengthdir_y(i,cam_yang);

     aa=place_3d_inst_ext(obj_item,_x,_y,_z-1,_z+1);//아이템 체크

     if !(aa=noone){//아이템이 있는가?
     with(aa){color=c_red;}//해당 아이템의 color변수를 빨간색으로 설정하고 반복문을 빠져나감
     break;}
     }



이것은 체크 가능한 거리가 64이고, 카메라로부터 2씩 보는 방향으로 이동하면서 아이템이 있는지

체크하는 것입니다.

 

그리고 만약 아이템을 체크 가능한 거리안에 있다면, 그 아이템의 color변수를 c_red(빨간색)으로

설정하게 되지요.

그렇게 되면 체크되는 동안 해당 아이템은 빨간색으로 혼합되어 표시될 것입니다.

 

 

(▲ 아이템 체크)


와우! 아이템 체크가 끝났습니다.
제대로 되는지 아이템을 룸에 배치하고, 테스트 해보도록 해요.

 

 

 

 

 

 

 


◈ 계단 이동(obj_stair8)


다음은 계단 이동에 대해 알아보도록 합시다.

 

(▲ 계단 이동 가능한 블럭)


계단 이동은 위와 같이 높이가 높을 때는 점프하지 않는 이상 이동하지 못하고, 계단과 같이 올라갈 수 있는

정도의 낮은 높이라면 이동시킬 겁니다.
강좌에서 올라갈 수 있는 높이는 10정도로 낮은 높이일 때 올라갈 수 있도록 하겠습니다.

일단 일반 블럭과 구분하기 쉽게 높이가 낮은 블럭 오브젝트(obj_stair8)를 따로 만들도록 합시다.
그리고 Parentobj_block 을 지정합니다.

 

 

(▲ 계단 오브젝트)


그리고 Create 이벤트를 추가하고, 높이에 대한 변수를 선언하도록 해요.

 



     ★ obj_stair8 - Create 이벤트

     z=0;
     ztop=8;//올라갈 수 있는 높이인 10보다 작게 높이를 설정



Draw 이벤트를 추가하고, 계단 모양의 모델을 표시하도록 합시다.
강좌에서는 블럭과 같은 모양이지만, 높이만 낮게 설정할 것입니다.

 



     ★ obj_stair8 - Draw 이벤트

     draw_set_color(c_white);
     draw_set_alpha(1);

    
     texid=background_get_texture(back_floor);
     d3d_transform_add_translation(x,y,z);
     d3d_draw_block(0,0,0,32,32,8,texid,1,1);
     d3d_transform_set_identity();



다음은 카메라 오브젝트(obj_cam)로 이동해서 Step 이벤트에 계단을 인식하도록 이벤트를 추가해야

합니다.

 



     ★ obj_cam - Step 이벤트

     spd=2;
     dir=cam_zang;
     key_pressed=0;
     if keyboard_check(ord("A")){dir=cam_zang+90;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}

     if keyboard_check(ord("D")){dir=cam_zang-90;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}

     if keyboard_check(ord("W")){dir=cam_zang;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}

     if keyboard_check(ord("S")){dir=cam_zang+180;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}


     zspeed-=0.3;
     if zspeed<-8{zspeed=-8;}

     if keyboard_check_pressed(vk_space){if jump=0{zspeed=6;jump=1;}}

     //---------------------------
     zmin=0;

     n=instance_number(obj_block);
     for(k=0;k<n;k+=1;){it=instance_find(obj_block,k);
     aa=instance_place(x,y,it);
     if instance_exists(aa){

     //---------------▼ 이벤트를 삭제해야 하는 부분
     //if z>=aa.z+aa.ztop{if zmin<=aa.z+aa.ztop{zmin=aa.z+aa.ztop;}}
     //---------------이벤트를 삭제해야 하는 부분

     //---------------▼ 이벤트 추가
     //계단

     if abs((aa.z+aa.ztop)-zmin)<10 && aa.z+aa.ztop>z{

     //올라갈 수 있는 블럭의 높이가 10정도 인가?

     if z<aa.z+aa.ztop{zspeed=2;}else{z=aa.z+aa.ztop;}

     //2정도의 속도로 짧게 점프해 올라감
     }
     //---------------▲ 이벤트 추가

     //일반 블럭
     if z>=aa.z+aa.ztop{if zmin<=aa.z+aa.ztop{zmin=aa.z+aa.ztop;}}


     i=1;repeat(ztop){if aa.z+aa.ztop>z+i && aa.z<z+i{
     x=xprevious;y=yprevious;
     if key_pressed=1{
     x+=lengthdir_x(spd,dir)*!(place_meeting(x+lengthdir_x(spd,dir),y,aa));
     y+=lengthdir_y(spd,dir)*!(place_meeting(x,y+lengthdir_y(spd,dir),aa));
     }
     break;}i+=1;}

     i=0;repeat(ceil(abs(zspeed))+1){
     if zspeed>0{if (aa.z>z+ztop+i-1 && aa.z<=z+ztop+i){z=aa.z-ztop;zspeed=-0.3;break;}}

    
     if z+i-1>=aa.z+aa.ztop && z+i>=aa.z+aa.ztop-2{if zmin<=aa.z+aa.ztop{

     zmin=aa.z+aa.ztop;break;}}
    
     if zspeed<0{i-=1;}else{i+=1;}}
     }
     }
     //---------------------------
     z+=zspeed;
     if z<=zmin{z=zmin;zspeed=0;jump=0;}



이것과 같이 이전 강좌의 내용중 수정하거나 추가해야할 부분이 있습니다.

     if z>=aa.z+aa.ztop{if zmin<=aa.z+aa.ztop{zmin=aa.z+aa.ztop;}}

중간에 위와 같은 부분이 있는데 이 부분을 삭제하고,

 

 
     //▼ 계단식 이동으로 수정

     if abs((aa.z+aa.ztop)-zmin)<10 && aa.z+aa.ztop>z{

     //올라갈 수 있는 블럭의 높이가 10정도 인가?

     if z<aa.z+aa.ztop{zspeed=2;}else{z=aa.z+aa.ztop;}

     //2정도의 속도로 짧게 점프해 올라감
     }



이렇게 변경해야합니다.
이것은 이동할 때 블럭에 올라갈 수 있는 10 높이인지 체크하여, 올라갈 수 있는 높이라면 짧게

점프를 하여 조금씩 올라가게 하는 것입니다.
의외로 간단하죠. 굳!

 

만약 올라갈수 있는 높이를 10보다 크게 하고 싶다면, 강좌에서 설정한 10 대신 여러분이 원하시는

높이로 설정하고, zspeed값을 좀 더 크게 잡으시면 될 거에요.


이제 블럭위에 있을때 여러 블럭을 체크하는 것이 필요해요.
왜냐하면 이동할 수 있는 블럭인지, 아니면 이동할 수 없는 블럭인지 구별해야 블럭에 끼이지 않기

때문이죠.

일단 블럭체크에 대한 스크립트를 하나 추가해야 합니다.

 



     ★ 스크립트 - place_3d_obj

     //place_3d_obj(obj,zmin,zmax);

     var _obj,i,_z1,_z2,_zc,_d1,_d2,_inst;
     _obj=argument0;
     _z1=argument1;
     _z2=argument2;

     _inst=0;

     if instance_exists(_obj){
     if place_meeting(x,y,_obj){
     //---------------------------
     _zmin=_obj.z;
     _zmax=_obj.z+_obj.ztop;
     _d1=abs(_z2-_z1);
     _d2=abs((_zmax)-_zmin);

     if _d1<=_d2{

     _zc=_z1+(_d1/2);
     if (_zmin<_z1 && _zmax>_z1) || (_zmin<_z2 && _zmax>_z2) || (_zmin<_zc && _zmax>_zc)

     {_inst=1;}
     }
     else{

     _zc=_z1+(_d2/2);
     if (_z1<_zmin && _z2>_zmin) || (_z1<_zmax && _z2>_zmax) || (_zmin<_zc && _zmax>_zc)

     {_inst=1;}
     }
     //---------------------------
     }}

     return _inst;



엇! 이전에 만든 place_3d_inst 스크립트와 비슷하지요.
place_3d_inst 에서는 collision_point를 사용하여 점으로 체크하게 했지만, 이것은 place_meeting으로

현재 카메라 지정된 마스크를 사용해 블럭과 체크하는 것입니다.

이 스크립트는 해당 오브젝트와 충돌하게 되면 1을 반환하게 되고, 그렇지 않으면 0을 반환합니다.

 

     place_3d_obj(obj,zmin,zmax)

     obj : 충돌 대상
     zmin : 현 오브젝트 z좌표의 최소값
     zmax : 현 오브젝트 z좌표의 최대값

이제 이 스크립트를 이용해 Step 이벤트에 아래와 같이 블럭 체크하는 부분을 추가합시다.

 



     ★ obj_cam - Step 이벤트

     spd=2;
     dir=cam_zang;
     key_pressed=0;
     if keyboard_check(ord("A")){dir=cam_zang+90;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}

     if keyboard_check(ord("D")){dir=cam_zang-90;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}

     if keyboard_check(ord("W")){dir=cam_zang;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}

     if keyboard_check(ord("S")){dir=cam_zang+180;
     x+=lengthdir_x(spd,dir)*place_free(x+lengthdir_x(spd,dir),y);
     y+=lengthdir_y(spd,dir)*place_free(x,y+lengthdir_y(spd,dir));key_pressed=1;}


     zspeed-=0.3;
     if zspeed<-8{zspeed=-8;}

     if keyboard_check_pressed(vk_space){if jump=0{zspeed=6;jump=1;}}

     //---------------------------
     zmin=0;

     n=instance_number(obj_block);
     for(k=0;k<n;k+=1;){it=instance_find(obj_block,k);
     aa=instance_place(x,y,it);
     if instance_exists(aa){
     //계단
     //if z>=aa.z+aa.ztop{if zmin<=aa.z+aa.ztop{zmin=aa.z+aa.ztop;}}

     if abs((aa.z+aa.ztop)-zmin)<10 && aa.z+aa.ztop>z{
     if z<aa.z+aa.ztop{zspeed=2;}else{z=aa.z+aa.ztop;}
     }

     //일반 블럭
     if z>=aa.z+aa.ztop{if zmin<=aa.z+aa.ztop{zmin=aa.z+aa.ztop;}}


     i=1;repeat(ztop){if aa.z+aa.ztop>z+i && aa.z<z+i{
     x=xprevious;y=yprevious;
     if key_pressed=1{
     x+=lengthdir_x(spd,dir)*!(place_meeting(x+lengthdir_x(spd,dir),y,aa));
     y+=lengthdir_y(spd,dir)*!(place_meeting(x,y+lengthdir_y(spd,dir),aa));
     }
     break;}i+=1;}

     //---------------▼ 이벤트 추가

     if (place_3d_obj(aa,z,z+ztop)=1){x=xprevious;y=yprevious;}

     //블럭에 충돌하면 멈춤(이동했다면 이전 좌표로 되돌아감)
     //---------------▲ 이벤트 추가

     i=0;repeat(ceil(abs(zspeed))+1){
     if zspeed>0{if (aa.z>z+ztop+i-1 && aa.z<=z+ztop+i){z=aa.z-ztop;zspeed=-0.3;break;}}
     if z+i-1>=aa.z+aa.ztop && z+i>=aa.z+aa.ztop-2{

     if zmin<=aa.z+aa.ztop{zmin=aa.z+aa.ztop;break;}
     }
     if zspeed<0{i-=1;}else{i+=1;}}
     }
     }
     //---------------------------
     z+=zspeed;
     if z<=zmin{z=zmin;zspeed=0;jump=0;}


 

설명은 길었지만, 블럭 충돌 관련 이벤트 한줄만 추가하면 됩니다. 굳!

 

이것은 이동할 수 없는 블럭에 충돌했을 때 멈추고, 이동했을 경우는 이동하기 이전 좌표로 되돌리는

것 이에요.

그러면 실제로 이동하다 블럭에 충돌했을 때 이동하지 못하는 곳일 경우 멈추게 되는 것처럼

보이는거죠.

와우! 드디어 계단 이동이 완성되었습니다.
제대로 작동이 되는지 계단을 룸에 배치하고 테스트 해보도록 해요.

 

 


[참고]
일반적으로 룸에 높이별로 블럭을 직접 배치해도 되지만, 강좌에서는 룸 설정탭의 Creation Code통해

코드로 배치했습니다. Creation Code는 룸이 시작할때 실행되는 이벤트입니다.

 



     ★ 룸 Creation Code

     i=0;

     repeat(10){
     it=instance_create(128+(i*32),320,obj_stair8);
     it.z=i*8;
     i+=1;}



이것은 10개의 블럭을 (128, 320) 좌표에서 오른쪽으로, z값을 8씩 추가하며, 배치하는 겁니다.
물론 블럭을 z값을 따로 설정하고 만들어, 룸에 직접 배치해도 됩니다.

 

 

(▲ 테스트 화면)


이번 강좌는 간단했죠.
강좌에서는 간단하게 표현했지만, 여러분은 좀 더 멋진 게임을 만드실 수 있을 것이라 생각합니다.

 

 

 

 

 


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

 

fpsX1-3-1(계단).gmk
다운로드

 

fpsX1-3-1(계단).exe
다운로드

 

 

300x250

댓글