ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 팀업 프로젝트 01. 디자인과 상태구현
    팀업 프로젝트/Night Raid

    01. 팀업 프로젝트 디자인과 상태 구현

    플레이어, 일반 몬스터, 보스 몬스터, 인벤토리 구현에서 일반 몬스터를 맡게 되었습니다.

     

    앞으로 진행될 프로젝트들의 과정과 개인 프로젝트의 진행 과정을 블로그를 이용해 기록을 할 예정입니다.

     
     
     
     

    일반 몬스터인 Enemy로 플레이어와 마을의 느낌에 어색하지 않게 반 실사적인 휴먼로이드의 캐릭터를 에셋에서 찾아 무료로 다운로드를 했습니다.

     

    [ Enemy의 상태 구현 ]

     

    Idle인 기본 상태, Move인 이동 상태, Attack인 공격 상태, Return인 복귀 상태, Damged인 대미지 받는 상태, Die인 죽음 상태로 총 Enemy의 상태는 6가지입니다.

     

    public EnemyState enemyState : 초기 상태 및 상태 값을 체크하기 위해 변수로 선언했습니다.

     

    Enemy가 가지고 있는 상태 값을 주기적으로 업데이트에 맞춰 상태에 맞는 동작을 하게 하기 위해 Update 함수에서 처리를 했습니다.

    Update

    번째 상태인 Idlkkkke

    단순 Enemy가 Idle인 상태는 밋밋해 보이기도 하고 하나가 아닌 여러 Object를 배치했을 때 어색함을 느꼈습니다. 그리 하여 Idle 상태에서도 맵을 자유롭게 돌아다니는 초기와 플레이어가 추적 범위에 들어왔을 시

    Idle -> Move로 넘어가는 상황인 2가지 상황으로 나누었습니다.

     
     

    Enemy가 죽고 되살아났을 시 를 생각하여 활성화될 시엔 맵을 자유롭게 돌아다녀야 했기에

    최초로 한 번만 실행하는 Start함수에서는 제가 현재 가지고 있는 역량으로는 부족하다고 여겨 활성화될 때마다 실행하는 함수인 OnEnable 함수에서 코 루틴 함수를 실행하게 하였습니다.

     

    또한 Enemy가 자유롭게 필드를 돌아다닐 때 필요한 Animator 컴포넌트를 ani 변수에 담아 두었습니다.

     

    프로젝트를 할 때면 항상 보는 Start 함수와 Update 함수지만 제대로 된 사용 기능은 모른 체 단순히 지나가는 경우가 많았습니다. 이번 검색으로 통해 알게 된 사실은


    Awake() : 해당 스크립트가 등록된 오브젝트 (&스크립트)가 최초로 활성화될 때 불리는 함수.

     

    Start() : Awake()와 마찬가지로 최초로 활성화 될 때 불리는 함수. (Awake보다는 늦게 호출됨)

     

    Update() : 활성화 상태일 때 한 프레임에 한 번씩 호출되는 함수

    (게임 프레임 1초에 60 프레임이 나온다면 1초에 60번씩 호출)

     

    FixedUpdate() : Update()와 마찬가지로 활성화 상태일 때 지속적으로 호출되지만, 1초에 고정 횟수만큼 호출하는 함수. (따로 설정하지 않았다면 기본 물리 시간인 0.02초에 한 번씩 호출)

     

    OnEnable() : 활성화될 때마다 호출되는 함수. (Awake/Start와 달리 활성화 될 때마다.)

     

    OnDisable() : 이 함수는 처음 봤는데 비활성화될 때마다 호출되는 함수라고 합니다.

    (OnEnable() 함수와 마찬가지로 요긴하게 사용될 것 같습니다,)


     

    OnEnable() 함수에서 실행되는 코 루틴 함수입니다. gameObject.tag!= "Dead"가 아닐 때의 조건을 추가시켜 Enemy가 죽었을 시 움직이는 상황과 예기치 못한 상황을 방지해 주었습니다.

    Animator를 담은 변수 ani의 Play 함수를 이용해 "Move" 동작을 Play 하도록 해주었습니다.

     
     

    orizinDis : OrizinPos(초기 위치 값)에서부터 현재 얼마나 떨어져 있는지 크기를 담을 변수

    targetDis : 내가 움직일 거리에서 얼마나 떨어져 있는지 크기를 담을 변수

    inCombat : 전투 중인지 확인할 변수 불

     

    다시 EnemyAI 코 루틴 함수로 들어가서

    While 문을 통하여 지속해서 orizinDis와 targetDis 값을 탐색해 줍니다.

    이후 전투 중이 아닌 상태라면, Move_NinCombat() 함수를 실행시켜 줍니다.



    Enemy가 목표와의 거리가 3 이하 이거나 같다면 OnMove를 false로 바꿔주어 재 탐색하는 if문의 조건문을 실행시켜 주고, 중복 방지를 위해 바로 true로 바꿔주었습니다.

    Enemy의 움직임을 위해 OnEnable 함수에서 변수에 NavMeshAgent 컴포넌트를 받아 오고

     

    이 전에 작업된 orizinPos로 Enemy의 초기값과 OrizinRot으로 Enemy의 초기 회전 값을 받아왔습니다.

    Move_NonCombat() 함수에서 경로를 재 탐색하는 부분인 if(! onMove)에서 nav의 speed는 비전투 중 속도인 notMovSpeed변수로 바꿔 주었고, target을 Random.Range 함수를 사용해

    vector(랜덤 (움직일 수 있는 최소 ~ 움직일수 있는 최대 ,0,움직일수 있는 최소 ~ 움직일수 있는 최대)

    로 바꿔 주고 Destination(목적지)를 target으로 정해 주었습니다.

     

    이후 if(orizinDis >= notMoveDis)의 조건문을 통해

    랜덤으로 이동하다 시작 위치에서 과도하게 멀어지게 된다면, 초기 위치인 orizinPos를 target에 대입시켜주고 target으로 이동하도록 했습니다. (target = 초기위치)

     

    이로써 자유롭게 필드를 이동하는 Enemy의 Idle 상태와

    마지막 Idle -> Move로 넘어가는 상태 구현만 남은 상태입니다.

     

    Idle() 함수를 살펴보기 전에 먼저 Start 함수와 추가 선언 변수들을 보겠습니다.

     

    moveDis : Enemy가 최대 움직일 수 있는 거리

    notMoveDis : 비 전투 중 Enemy가 최대 움직일수 있는 거리

    findDis : Player가 이 거리 안에 오면

    추적할 거리

    atckDis : Enemy의 공격 범위

    movSpeed : Enemy의 기본 이동 속도 값

    notMovSpeed : Enemy의 비 전투중

    이동 속도 값

     

    Start() 함수 :

    enmyState 값을 Idle로 변경해 줬습니다.

     

    마지막으로 OnEnable 함수에서 player 변수에 GameObject를 Find 하여 "Player"를 찾았고,

    ?. 를 통한 Null 조건부 연산자를 통해 "Player"가 Null이 아니라면 transform을 가져오게 했습니다.

     

    Idle() 함수를 통해 Vector3.Distanceg함수를 통해 Enemy의 위치와 player의 위치의 거리를 체크하였고, 그 거리가 findDis(추적할 범위) 보다 작다면 nav의 스피드는 movSpeed로 바꿔주고 상태를 Move로 바꿔주었습니다. Animator가 어떠한 동작을 하고 있을지 몰라, SetTrigger로 Animator 트랜지션의 방향을 확실히 정해 주었습니다.

     

    현재 Enemy의 Animator 상태입니다.

    파라미터를 트리거 형태로 Idle -> Move로 가는 방향을 IdleToMove로 지정해 주었고,

    반대로 Move -> Idle로 오는 파라미터 트리거 형태는 MoveToIdle로 지정해 주었습니다.

     
     

    두 개의 값 모두 Has Exit Time을 체크 해제하여 호출이 되면 즉시 변경되게 하였습니다.

    반대로 Has Exit Time이 체크가 되어 있으면, 트랜지션의 방향이 붙어 있더라도 즉시 변경이 안되고 기존의 애니메이션이 모두 재생 한 뒤 방향으로 전환이 됩니다.

     
     

    이로써 Idle 상태에서 자유롭게 필드를 돌아다니는 Enemy구현을 완성시켰습니다.

     

    책을 통하여 지식을 얻게 된 점인데. 씬 뷰에서 거리 측정을 시각적으로 보여주는 OnDrawGizmos를 사용하면 보다 거리감을 쉽게 알 수 있다는 장점을 알았습니다.

    Disable 함수와 함께 이 OnDrawGizmos 함수도 상당히 요긴하게 쓰일 것 같습니다!

    댓글

김효겸 / Tel. 010-7735-0580 / E-mail. dollzzang2@hanmail.net