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

[게임메이커강좌-디펜스]간단한 디펜스게임 만들기-1

by 타락카얀 2013. 4. 30.
728x90

 

 

 

 

 

 

 

 

◈ 간단한 디펜스 게임 제작

 

 

이번에는 아래와 같이 지역을 방어하는 구조의 간단한 디펜스 게임을 만들어 보도록 해요.
참고-이번편은 액션이 아닌 코드로 게임을 만들 것입니다.

 

 

(▲강좌에서 만들어 볼 디펜스 게임 화면)

 

 

 

 

 

 

 

 

◈캐릭터 오브젝트의 분류

 

 

 

(▲캐릭터 오브젝트 설정)

 

캐릭터의 오브젝트는 위와 같이 분류합니다.
게임 상에서 제어하기 편하도록 위 그림처럼 분류하여 오브젝트를 만드는 것이 좋아요.
상위가 부모 오브젝트, 아래는 하위 오브젝트가 됩니다.

 

 

 

 

 

 

◈플레이어 설정(obj_tw1)

 
우선 플레이어로 사용할 유닛의 이미지를 마련해요.

 

 

(▲강좌에서 사용할 이미지)


캐릭터 오브젝트의 분류의 이미지 처럼 모든 유닛을 통괄할 수 있는 오브젝트와 플레이어의 하위 오브젝트를

각각 만듭니다.

 



     예) obj_allunit - obj_player-obj_tw1

     obj_allunit : 플레이어, 적 유닛을 모두 제어할 수 있는 부모 오브젝트
     obj_player : 실제 배치되는 유닛의 상위 오브젝트
     obj_tw1 : 실제 배치

     obj_enemy : 적 오브젝트의 상위 오브젝트(부모오브젝트는 플레이어와 마찬가지로 obj_allunit)
     obj_en1 : 실제 배치



먼저 Parent 오브젝트인 obj_player 오브젝트 Create 이벤트에 제어할 변수들을 선언합니다.
물론 실제 배치되는 obj_tw1 오브젝트 Create 이벤트에 직접 선언해도 됩니다.

 



     //obj_player - Create이벤트

     hp=30;//체력
     hp_max=hp;//최대 체력

     range=0;//공격범위
     att=0;//공격 수치
     att_sw=0;//공격 토글 스위치
     delay=0;//공격 시간차


공통이 되는 변수나 스크립트는 유닛마다 따로 하는 것보다 부모 오브젝트(Parent 오브젝트)의 이벤트에서

하는것이 관리하기 좋습니다. 부모 오브젝트의 이벤트를 하위 오브젝트에 상속 시킬 수 있기 때문이지요.

 

다음은 obj_tw1(실제 배치되는 유닛)Create이벤트에 변수를 선언합니다.

 



     //obj_tw1 - Create이벤트
     event_inherited();//부모오브젝트의 이벤트를 계승함.

     hp=50;//체력
     hp_max=hp;//최대체력

     target=noone;//목표물 체크. noone은 상수로 -4이며 인스턴스가 없을 때의 기본값입니다.

     range=128;//공격 범위
     att=5;//공격 수치
     delay=90;//공격 시간차


 

부모 오브젝트에 있던 변수들 중 몇가지 변수들의 값을 재 조정해 주었습니다.

 

[참고]

 

     event_inherited()

 

이것은 부모 오브젝트(Parent 오브젝트)이벤트를 상속할때 사용하는 함수 입니다.

부모 오브젝트에 있는 이벤트가 현재 하위 오브젝트에 없는 경우 그대로 상속되어 사용할 필요가 없지만,

부모 오브젝트와 동일한 이벤트가 있는 경우 하위 오브젝트의 이벤트를 우선하기 때문에, 부모 오브젝트의

이벤트를 같이 실행할 수 없습니다.

그래서 부모 오브젝트의 이벤트를 실행하기 위해선 이 함수를 사용해야하는 것이지요.

 

그리고 obj_tw1Step이벤트에 목표물을 설정해요.
먼저 목표물이 없을 경우의 상황입니다.
(인스턴스가 있는지 없는지를 체크하는 함수는 instance_exists입니다)

 



     //obj_tw1 - Step이벤트

     if !(instance_exists(target)){//목표물인 target이 없는 경우
     if instance_exists(obj_enemy){target=instance_nearest(x,y,obj_enemy);}
     //적 오브젝트가 룸상이 있으면 가장 가까운 적의 ID를 target(목표물 변수)에 할당합니다.
     else{target=noone;}//적 오브젝트가 룸상에 없으면 noone으로 설정합니다.
     }


 

이어서 목표물이 정해졌을 때 상황을 추가하여 작성합니다.
목표물이 범위안에 들어왔을 때는 공격하도록 만들어야 하기 때문에 일단 유닛이 발사할 총알 오브젝트를

만들어야 겠지요.

 

총알에 사용할 오브젝트(obj_att1)를 하나 만들고, Sprite에 해당 스프라이트 이미지를 지정해 주도록 해요.

강좌에선 이 유닛이 발사할 총알은 obj_att1로 사용합니다.

Create 이벤트를 추가하고 공격에 필요한 변수를 선언하도록 해요.

 



     //obj_att1 - Create 이벤트

     att=0;//공격 수치


 

간단하게 공격수치만 선언했습니다.

 

이제 적유닛에 맞추었을 경우의 이벤트를 작성합니다.

 



     //obj_att1 - obj_enemy와의 Collision 이벤트

     if other.hp>att{other.hp-=att;}//other는 충돌 상대를 가리킵니다.
     else{other.hp=0;}
     instance_destroy();


 

이렇게 하면 적과 충돌 했을 때, 상대오브젝트가 총알의 공격수치보다 크면 그 수치대로 체력을 감소시키고,

그렇지않으면 체력을 0으로 만드는 것입니다.

이것은 체력을 0미만으로 만들지 않기 위해 이렇게 작성하는 것이지요.
그리고 자신의 임무를 다한 총알오브젝트를 파기하여 룸 상에서 제거합니다.

다음은 총알이 적오브젝트와 맞지 않을 때를 고려해, 타이머를 작동하여 자동으로 파기하도록 하는 이벤트를

만들어 보아요.
여기선 임의적으로 alarm[5]를 써보도록 하겠습니다.

 



    //obj_att1 - alarm[5] 이벤트



     instance_destroy();

 

총알이 날아갈때 비쥬얼적으로 어떠한 효과를 주면 좋겠지요.
게임메이커는 기본적 간단한 이펙트들이 내장되어있습니다.
이번에는 그것을 한번 써보도록 해요.

 



    //obj_att1 - Step 이벤트



     effect_create_above(ef_flare,x,y,0.5,c_red);
     effect_create_above(ef_flare,x,y,0.2,c_yellow);


 

이렇게 하면 공격 오브젝트가 날아갈 때 이펙트가 오브젝트 위에 생성되게 됩니다.

 

[참고]

기본적으로 게임메이커에서 제공하는 이펙트 함수는 다음과 같습니다.

 

     effect_create_below(kind,x,y,size,color) : 이펙트를 오브젝트들보다 하위에 생성
     effect_create_above(kind,x,y,size,color) : 이펙트를 오브젝트들보다 상위에 생성
     effect_clear() : 모든 이펙트를 화면에서 제거

 

     kind : 이펙트 종류

     x,y : 생성할 좌표

     size : 크기, 1은 이펙트의 기본 크기

     color : 색상

 

kind에 들어갈 이펙트의 종류는 아래와 같습니다.

 

     ef_explosion : 폭발 효과
     ef_ring  : 링 모양
     ef_ellipse : 타원 모양
     ef_firework : 불꽃 모양
     ef_smoke : 연기 효과
     ef_smokeup : 위로 올라가는 연기 효과
     ef_star : 별 모양
     ef_spark : 스파크 효과
     ef_flare : 조명탄 효과
     ef_cloud : 구름 효과
     ef_rain : 비 효과
     ef_snow : 눈 효과

 

이 이펙트는 게임메이커에 기본적인 그래픽으로 구성되어 내장된 이펙트로써, 간단하게 사용하기엔 매우

유용합니다.

 

하지만 단점이라면 기본 그래픽이라 화려하지는 않고, 깊이를 조절할 수 없다는 점입니다.

깊이는 단 2가지로 제공되지요. -100000 또는 100000 깊이에 표시되는 것뿐입니다.

또한 사이즈 역시 가늠하기가 어렵습니다. 그래서 크기를 조절하기 위해선 size에 설정후 크기확인을 해야합니다.

 

그렇기 때문에 좀 더 다양한 설정을 하기 위해서는 직접 스프라이트 이미지를 제작해 오브젝트로 생성하는 것이

좋은 방법이지요.

 

사용예)

     effect_create_above(ef_explosion,x,y,1,c_red);

 

 

(▲기본 내장 이펙트)

 

내장 이펙트는 1가지 써도 되지만, 2가지이상 혼합하여 사용하면 좀 더 멋지 효과를 줄 수도 있습니다.

다음은 다시 플레이어 유닛으로 돌아가서 Step이벤트에 공격 이벤트를 작성하도록 해요.

 



     //obj_tw1 - Step이벤트

     else{
     if distance_to_object(target)<range{//범위안에 들어왔을 때 이벤트를 실행합니다.

     direction=point_direction(x,y,target.x,target.y);//방향을 목표물로 향하게 합니다.

     //공격 시작
     if att_sw=0{
     it=instance_create(x,y,obj_att1);//총알 발사
     it.direction=point_direction(x,y,target.x,target.y);//방향은 당연히 목표물!!!
     it.speed=5;
     it.att=att;//총알의 공격 수치는 유닛의 공격수치를 할당함.
     it.alarm[5]=point_distance(x,y,target.x,target.y)/5;

     //공격 거리가 짧다고 생각되면 좀 더 크게 설정하면 됨.
     //예)it.alarm[5]=(point_distance(x,y,target.x,target.y)+60)/5
     //적에 맞지 않을 경우를 고려해 자동으로 파기되는 시간을 정함.
     alarm[0]=delay;att_sw=1;}//공격 딜레이를 지정하고 공격 토글을 작동시킴.
     //공격 끝

     }
     else{target=noone;}//target이 범위 밖에 있을 때는 noone값으로 되돌립니다.
     }

     if hp<=0{

     hp=0;

     instance_destroy();
     }//체력이 0일때 0으로 설정하고 유닛을 파기합니다.


이 이벤트는 target이 범위 안에 들어왔을 때 공격하도록 하고, 범위 밖이면 target을 인스턴스가 없을 때의

값인 noone으로 설정하는 기능입니다.

공격을 한번 했으니 공격 스위치를 다시 리셋해야겠지요.
Alarm 이벤트를 하나 만들고, 변수를 0으로 리셋합니다.

 

 
      //obj_tw1 - Alarm[0] 이벤트

      att_sw=0;

 

이렇게 하면 한번 공격후 약간의 딜레이 시간이 지난 후에 재공격을 할 수 있게 되지요.

 

다음은 Draw 이벤트를 추가하고 유닛을 화면에 표시합니다.

 

 
     //obj_tw1 - Draw 이벤트

     draw_sprite_ext(spr_tw1,0,x,y,1,1,0,c_white,1);
     draw_sprite_ext(spr_tw1,1,x,y,1,1,direction,c_white,1);//포신은 direction방향으로 회전함.

     //체력바
     _h=32;
     c=c_red;draw_rectangle_color(bbox_left,bbox_top,bbox_left+_h,bbox_top-5,c,c,c,c,0);
     _h=(hp*32)/hp_max;
     c=c_green;draw_rectangle_color(bbox_left,bbox_top,bbox_left+_h,bbox_top-5,c,c,c,c,0);
     _h=32;
     c=c_white;draw_rectangle_color(bbox_left,bbox_top,bbox_left+_h,bbox_top-5,c,c,c,c,1);

     //bbox_left,bbox_right,bbox_top,bbox_bottom 마스크 기준으로 좌측, 우측, 상단, 하단의 좌표입니다.


 

이렇게 하면 아래의 그림처럼 유닛이 표시되고, 그 위에 체력바가 표시됩니다.

 

 

(▲실제 표시되는 체력바)

유닛이 파기 될때 이펙트를 발생하도록 만들어 봅시다. Destroy 이벤트를 만들고,

 

 
     //obj_tw1 - Destroy 이벤트
 
    if hp<=0{

     effect_create_above(ef_explosion,x,y,0.5,c_red);
     effect_create_above(ef_explosion,x,y,0.2,c_yellow);
     }

 

이렇게 하면 플레이어의 타워가 파기될 때 이펙트를 발생하게 됩니다.

 

 

 

 

 

 


◈적 유닛(obj_en1)

 


이제 적 유닛의 이미지를 마련하여 오브젝트를 설정하도록 해요.

 

 

(▲적 유닛)

적 유닛의 Create이벤트를 생성하고

 



     //obj_en1 - Create 이벤트



     hp=50;//체력
     hp_max=hp;//최대 체력
     image_speed=0.2;//애니메이션 속도 1은 기본값이며 1보다 작으면 느려짐.


 

다음은 Step 이벤에서 체력에 관한 이벤트를 작성합니다.

 



     //obj_en1 - Step 이벤트



     if hp<=0{
     hp=0;

     instance_destroy();
     }//체력이 0이면 파기합니다.

 

플레이어의 유닛과 마찬가지로 Destroy 이벤트에서 파기 될때 이펙트를 발생하도록 합시다.
그리고 파기될때 점수나 플레이어의 자금같은 것을 올려주면 좋겠지요.
여기선 플레이어의 자금을 추가하도록 합시다.

강좌에서는 자금 변수로 'global.gold'로 사용하겠습니다.

 

[참고]
global변수는 한번만 선언하게 되면 다른 룸으로 이동해도 변수를 유지 시킬 수 있습니다.

global변수는 일반 변수명 앞에 'global'을 붙이는 것으로, 일반 변수 선언하듯이 오브젝트에서 선언하면

됩니다. 그러나 선언하지 않은 상태에서 더하거나 빼는 계산설정을 하게 되면 오류가 생기게 되기 때문에,

선언해야하는 변수들은 모두 기억해두었다가 꼭 변수를 다시 선언해야합니다.

 

또한 이 global 변수는  변수를 사용하기 전에 아무 때나 선언하면 되지만, 변수 특성상 게임이

시작될때(맨 처음 룸) 선언하거나, 타이틀 화면때 선언하는 것이 가장 좋습니다.

그러면 스테이지가 진행되는 동안 초기화되지 않고, 값을 계속 유지할 수 있게 되지요.

 



     //obj_en1 - Destroy 이벤트
 

     if hp<=0{
     global.gold+=hp_max;//플레이어의 자금을 추가합니다. 값은 적의 체력으로 했으나, 따로 값을 입력해도 됨.

     effect_create_above(ef_explosion,x,y,0.5,c_red);
     effect_create_above(ef_explosion,x,y,0.2,c_yellow);
     }



다음은 플레이어의 타워처럼 적 유닛의 이미지를 화면에 표시하도록 해요.

 

 
    //obj_en1 - Draw 이벤트

    draw_sprite_ext(spr_enemy1,-1,x,y,1,1,direction,c_white,1);//direction 방향에 따라 이미지를 회전


    //체력바
    _h=32;
    c=c_red;draw_rectangle_color(bbox_left,bbox_top-5,bbox_left+_h,bbox_top,c,c,c,c,0);
    _h=(hp*32)/hp_max;
    c=c_green;draw_rectangle_color(bbox_left,bbox_top-5,bbox_left+_h,bbox_top,c,c,c,c,0);
    _h=32;
    c=c_white;draw_rectangle_color(bbox_left,bbox_top-5,bbox_left+_h,bbox_top,c,c,c,c,1);

 

플레이어의 타워표시 방법과 같지요. 어차피 표시방법은 대부분 비슷비슷합니다. 헤헷~

 

이 게임에서 적들의 이동은 패스를 통해 이동 시킬 것입니다.
따라서 패스의 끝에 적이 이동했을때, 즉 적이 본진에 들어왔을 때 이벤트를 작성해야합니다.
이벤트 메뉴에서 other->End of path이벤트를 추가합니다.

 



     //obj_en1 - End of path 이벤트

     if global.hp>hp{global.hp-=hp;}
     else{global.hp=0;}//패스가 끝나면 플레이어의 체력을 감소시킵니다.

     instance_destroy();//패스의 이동이 끝나면 유닛을 파기합니다.



이것은 패스로의 이동이 끝났을 때 발생하는 이벤트에요.

적 유닛이 패스가 끝나면 플레이어의 체력(global.hp)을 갑소하게 됩니다.

그리고 적유닛을 룸 상에서 파기하여 이 이벤트가 반복되는 것을 방지하는 것입니다.

 

뭐, 패스가 끝날 때 여러가지 이벤트를 작성할 수 있겠지요.
이를 테면 기본 점수를 감소하던가, 아니면 플레이어의 통합 체력을 감소시키는 것 말이죠.
여기선 통합 체력을 감소하도록 합시다. 강좌에서 통합체력은 global.hp 전역 변수로 설정했습니다.

 

 

 

 


- 다음 강좌에서 계속 -

 

 

 

 

 

300x250

댓글