ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RPG 액션 연습 06. DRAGON! 01 / 02
    연습 프로젝트/RPG 연습

    안녕하세요.

     

    이번엔 멋진 DRAGON을 만들어 봤던 과정을 올려 보겠습니다.

     

    음.. 사실 퀄리티가 높거나 다양한 동작 구현 등이 있는 드래건은 아니지만...

     

    제 첫 하늘을 나는 드래곤 이니 만큼.. 애정이 듬뿍 가는 녀석입니다.

     

     

    등장 신을 좀 더 멋지게 하고 싶어서 이것저것 찾아보던 도중

     

    씨네 머신이란 것을 알게 되어서 현재 학습 중에 있습니다.

     

    아직 적용은 안됐지만 멋진 등장 연출을 기대해 주세요.

     

     

    자 그럼 바로 시작해 보겠습니다!!

    에셋은 유티티 에셋 스토어에서 다운로드를 했습니다.

     

    제가 선택한 드래건입니다!!

     

    우선 전 스크립트를 2개로 나눴습니다.

     

    각 DragonBoss / DragonBoss2로

     

    등장했을 때의 스크립트 / Ground에 도착했을 때의 스크립트

     

    두 개로 나눠 동작 연출을 하였습니다!

     

     

    우선 DragonBoss의 스크립트부터 보겠습니다 

    우선 변수 선언 부분부터 보겠습니다.

     

    바닥의 충돌 부분을 위해 cc변수로 CharacterController를 받아오기 위해 선언했습니다.

    (작성 후 많은 바닥 체크 중 한 가지 방법을 알게 됐는데, Ray방법입니다.

    Ray를 드래건 아래로 쏴, Ground에 충돌 체크가 되면 바닥인지를 감지하게 하는 방법입니다

    -수정 예정 중-)

     

    ani / audi / nab : 각각 / 애니메이터, 오디오 소스, 내비게이션입니다.

     

    dragonBoss : 자기 자신을 미리 받아왔습니다 (드래건)

     

    FlyToIdle_Effect : 하늘에서 떨어지면서 땅에 내려와 Idle로 전환 시

    생성될 이펙트입니다.

     

    isRoar : 땅에 내려와 1번 포효를 합니다. 포효 한지 체크해줄 불 변수 isRoar입니다.

     

    player : 드래건이 추적 및 공격할 대상인 player입니다.

     

    moveSpeed : 드래건의 스피드입니다.

     

    Lava : 드래건의 공격 스킬 중 하늘에서 떨어지는 운석을 연출한 장면이 있는데,

    그 운석입니다.

     

    isLava = faslse : Lava(운석)의 대기시간 (중복)을 갖게 해 줄 불 변수입니다.

     

    Start함수

    1회 실행되는 Start 함수에서 가져온 컴포넌트들입니다.

    cc / ani / audi / nav / dragonBoss는 각각

    CharacterController / Animator / AudioSource / NavMeshAgent / DragonBoss 

    를 받아왔습니다.

     

    Update

    Update함수입니다.

     

    이걸 어디서부터 설명을 해야 할지 정리가 아직 안되는데..

     

    우선 두 번째 if문인 (!(cc.collisionFlags == CollisionFlags.Below)) 조건부터 보겠습니다.

    여기서 저는 수많은 바닥 체크 방법 중 하나인 collisionFlags 변수를 이용했습니다.

    collisionFlags.Below는 충돌 영역 중 바닥을 체크했을 시 true를 반환하며

    Above / Side는 각 위쪽 / 양 옆쪽에 충돌했을 시 true가 반환됩니다.

     

    현재는 Ray를 쏘게 해서 바닥(Ground) 일 시 멈추게 되는 방향으로 수정하겠습니다.

    캐릭터 컨트롤러의 사용을 안 하려고 하는데

    번 외로 바닥을 체크하는 한 가지 더 알게 된 방법으로 cc.isGrounded가 있습니다.

     

    이의 조건문을!(NOT 논리 연산자)를 이용하여 현재 바닥과 닿아 있지 않다면? 의 조건을 만들었습니다.

    그렇다면 cc.Move함수를 이용해 (방향 * 스피드 * Time.deltaTime)으로 아래 방향으로 내려가게 해 줬습니다.

    캐릭터 컨트롤러를 없애고 velocity.y 를 이용할 계획입니다.

     

    이렇게 되면 드래건은 아래로 내려가면서 Play함수를 이용해 "Fly" 애니메이션을 실행하게 됩니다.


    그렇다면 이제 바닥과 충돌이 안됐을 시의 조건문인 else문을 보겠습니다.

    여기서도 1(NOT 논리 연산자) 를이용하여 isRoar(포효를 했는지 체크할 불 변수) 포효를 안 했을 시 실행됩니다.

     

    SetTrigger를 이용해 현재 진행 중인 "Fly" 애니메이션에서

    Idle로 트랜지션 방향의 조건을 성립시켜줬습니다.

    이후 StartCoroutine함수를 이용해 ("IdleToRoar(포효를 구현하는 코 루틴 함수)")를 실행시킵니다.

     

    이제 반대로 else문인 isRoar(포효를 했는지 체크할 불 변수) 포효를 했다면?

     

    StartCorutine으로 DistroyEffect()를 실행합니다.

     

    제가 스타트 코 루틴을 문자열로 받을 때도 있고 함수명으로 받을때도 있는데,

    아직 의미는 없고 손이 가는 대로 적는 것 같습니다.

    다만 ""과 같이 문자열로 받았을 시 오류가 발생했을 때 찾기가 힘들다고 들은 적이 있습니다.

    그 이유는 아직 못 찾았지만 웬만하면 함수명으로 받으며 검색을 통하거나

    혹은 직접 경험? 을 할 기회가 생긴다면 바로 올려 드리겠습니다.

     

    Roar(포효)를 실행한 상태이니 SetTrigger를 이용하여 Roar -> Idle로 애니메이션을 전환하는"RoarToIdle"의 트리거 값을 체크해줘 트랜지션의 방향의 조건이 성립하게 합니다.

     

    마지막으로 StartCorutine를 이용하여 (Enable())의 코 루틴 함수를 실행시켜 줍니다.

     


    이제 코루틴 함수 구현들의 코드 내용을 살펴보겠습니다.

    코 루틴 함수들을 살펴보기에 앞 서 Update문에 첫 번째 if문을 먼저 보겠습니다.

    isLava(운석의 중복 체크를 막기 위한 불 변수입니다)

    !(Not) 논리 연산자를 사용하여 false일 시를 나타냈습니다.

     

    이후 StartCorutine로 Lava_Ins()를 실행하였습니다.

     

    우선 Lava_Ins() 코 루틴 함수부터 살펴보겠습니다.

     

    Lava_Ins() 코 루틴 함수입니다.

     

    isLava = true로 바꿔 주어 중복 실행 방지를 막아줬습니다.

     

    Instanitate를 이용해 (Lava(운석)을 player의 위치 + new Vector3(0, 0,01f, 0)의 위치  , Quaternion.identity로 생성해 주었습니다.

     

    우선 첫 번째 인자인 Lava : gameObject입니다.

    두 번째 / 세 번째는 각각 position / rotation입니다.

     

    우선 Position부터 보자면, 플레이어는 현재 점프 및 y축의 변경이 없기에 값이 0입니다.

    Horizontal의 키 값인 a || d 이거나 ← →

    Vertical의 키 값인 w || s 이거나 방향키 ↑↓ 

    입니다.

    그렇기에 x와 z는 Player의 이동에 따라 값이 변동되는데 

     

    이를 생각하여 Player의 위치 값 + y ( 0.01f)로 생성되게 해 줬습니다.

     

    대기 시간은 yield return new WaitForSeconds(1.5f)로 1.5초의 대기시간을 갖게 해 주었고

    다시 isLava를 false로 바꿔주어 실행이 가능하게 바꿔주었습니다.

     

    이해를 돕기 위한 Lava를 씬 뷰에서 보았을 때입니다.

    Lava

     

    이제 이 라바(운석) 이 어떻게 실행되는지 보겠습니다.


    Speed : Lava의 스피드 값입니다.

     

    cc : CharactorController를 받아올 변수 cc입니다.

     

    lava_Effect : 위에 떠있는 운석이 땅에 떨어질 시 생길 이펙트입니다.

     

    lavaBase : 플레이어가 어디에 운석이 떨어지는지 미리 알려줄 베이스입니다.

     

     

    OnEnable ( 매 활성화 시 호출되는 함수)에서 스피드 값을 Random.Range를 이용해 20f - 35f 랜덤 값을 받아옵니다.

     

    Start함수 ( 최초로 한 번만 실행되는 함수) GetComponent를 이용해 CharactorController를

     

    Update함수입니다.

     

    흠.. 우선 여기서도 collisionFlags를 이용하여 바닥을 체크하였는데

    막상 코딩을 하면서 작업할 땐 몰랐는데

    불필요한 cc 컴포넌트 같습니다.

     

    바닥 체크를 Ray를 생성해서 사용하던가 혹은 다른 방법을 찾아봐서 cc를 없애는 편이 좋을 것 같고

    움직이는 방향은 velocity.Y 를 이용하여 움직이게 해 줄 예정입니다.

    이 보스의 움직임은 NaviMeshAgent를 이용해 움직이는데

    뭐가 더 효율적인지 곰곰이 생각을 해봐야 할 것 같습니다.

    우선 현재 글을 작성하면서 드는 생각은 Ray를 이용한 바닥 체크를 이용할 생각입니다.

     

    DragonBoss와 마찬가지로!(NOT 논리 연산자)로 바닥이 아닐 시엔 cc.Move함수로 (아래 방향 * 20f = 35f랜덤 값 * Time.deltaTime)을 구현해 줬습니다.

     

    반대로 바닥일 시 실행되는 else문에서는gameObject(Lava)를 즉시 비활성화해주며 lava_Effect를 SetActive (true)로 활성화를 시켜줍니다. 이후 가져온 lavaBase에 Disable() 함수를 실행해 줍니다.

     

    lavaBase에 Disable함수는 OnTriggerEnyer함수의 코드를 본 다음 보겠습니다.

    OnTriggerEnyer함수입니다.

     

    우선 OnTriggerEnyer 함수가 실행되려면 두 오브젝트가 Collider를 갖고 있어야 하며

    또한 1 오브젝트 이상은 Rigidbody를 갖고 있어야 합니다.

     

    player에는 현재 충돌 감지를 해 줄 CharactorController를 갖고 있었습니다.

     

    또한 연산 처리속도가 가장 빠른 Collider 순서인 Sphere Collider > Capsule Collider > Box Collider를 생각해

     

    Lava에 Sphere Collider를 붙여 주겠습니다.

     

    OnTriggerEnter는 충돌 이벤트 함수입니다. 다른 용어로는 Call Back function 이라고도 불리기도 하는데

    충돌이 감지되면 시스템(Back)에서 호출(Call) 한다는 것을 의미한다고 합니다.

     

    -메모-

    우선 is Trigger 옵션을 체크하는

    OnTriggerEnter : 두 물체 간 충돌이 일어나기 시작했을 때

    OnTriggerStay : 두 물체 간의 충돌이 지속할 때

    OnTriggerExit : 두 물체가 서로 떨어졌을 때

     

    is Trigger 옵션을 언체크 하는

    OnCollsionEnter : 두 물체 간 충돌이 일어나기 시작했을 때

    OnCollsionStay : 두 물체 간의 충돌이 지속할 때

    OnCollsionExit : 두 물체가 서로 떨어졌을 때

     

    로 Is Trigger를 체크하면 충돌 감지는 되지만 물리적인 충돌은 일어나지 않게 됩니다.

    (주로 감지 센서 등에 이용)

     

    OnTriggerEnter로 is Trigger에 체크를 해 주어 물리적인 충돌은 일어나지 않게 해 주고 충돌 감지만 해주며

    두 물체 간 충돌이 일어나기 시작했을 때를 말합니다.

     

    충돌된 other의 tag를 검색해서 "Player" 라면 DamageAction(5)를 실행해 줍니다.

     

    Player의 DamageAction함수


    lavaBase에 Disable함수를 보겠습니다.

    Lava Base 스크립트입니다.

     

    한 스크립트에 모두 작성을 해도 되지만,

     

    스크립트의 적절한 세분화? 를 조금이나마 연습을 해보기 위해 따로 작성을 하였습니다.

     

    감은 아직 잘 안 잡히지만. 한 코드를 찾으려 할 때는 좀 더 효율적이라고 느끼고 있습니다.

     


    현재 본인이 갖고 있는 AudioSource컴포넌트를 audi 변수에 담아 제어하기 위해 선언한 변수입니다.

     

    Disable 함수에서는 StartCoroutine를 사용하여 코 루틴 함수 Disable_Lava를 실행해 줍니다.

     

    Disable_Lava 에선 PlayOneShot을 이용해 Lava가 Ground에 닿았을 시 발생되는 클립을 실행시켜 줍니다.

    PlayOneShot 함수와 달리 Play함수도 재생 함수인데, 이 함수는 중첩 시 마지막 사운드만 실행되는 단점이 존재합니다.

     

    이후 yield return new WaitForSeconds(1.5f)를 이용해 1.5초의 대기시간을 갖게 해 주고

    Destroy(gameObject)로 파괴시켜줍니다.

     

    Lava는 즉시 파괴되며 LavaBase는 1.5초의 대기시간을 갖게 되고 사라지게 됩니다.

     


    이렇게 드래건이 내려오면서 연출 부분이 비는 것을 활용하여

    플레이어가 떨어지는 운석을 피하는 상황이 연출될 부분인

    Lava 부분이 완성되었습니다.

    이제 바닥이 아닐 경우일 때 

    포효를 했는지 확인할 isRoar 변수로 조건이 성립될

    if - else 문을 보겠습니다.

     

    우선 첫 번째로!(NOT 논리 연산자)를 사용해 isRoar(포효)를 안 했을 시 if(! isRoar) 부분에서

    StartCoroutine으로 실행시켜줄 코 루틴함수 IdleToRoar를 보겠습니다.

    코루틴 함수 IdleToRoar는 

     

    yield return new WaitForSeconds(2f)로 대기시간 2초를 갖게 하고 
            ani.Play("Roar") : Play함수로 "Roar"를 실행해 줍니다.
           

    또한 Roar의 애니메이션의 Events에 

    애니메이션의 동작에 맞춰 사운드 재생 함수인 Roar 함수를 실행해줍니다.

    Roar 함수


            isRoar = true : 포효를 하였으니 true로 바꿔주어 중복을 방지해주고 
            yield return new WaitForSeconds(3f) : 대기시간 3초를 (애니메이션 재생시간)을 기다려줍니다.

    isRoar가 true가 되었으니 실행될 else문입니다.

     

    여기서 실행될 코 루틴 함수

    DistroyEffect와 Enable을 알아봅시다.

     

    또한 포효가 끝났으니 SetTrigger를 통해 "RoarToIdle"로

    애니메이션이 Roar -> Idle로 가는 트랜지션의 조건을 성립하게 만들어 줍니다.

     

    코루틴 함수 DistroyEffect 함수입니다.

    yield return new WaitForSeconds(1f)을 이용해 1초의 대기시간을 갖게 해 주고

    Destroy로 이용해 Fly -> Idle 될 시 발생한 이펙트를 파괴시켜 줍니다.

     

    마지막으로 Enable 코 루틴 함수입니다.

     

    yield return new WaitForSeconds(6f)를 기다린 뒤 

     

    다음 스크립트로 넘어갈 DragonBoss2에서의 상태 값을 Idle로 바꿔주며

     

    현재 실행 중인 dragonBoss의 스크립트는 enabled = false로 비활성화시켜 줍니다.

     

    이로써 DragonBoss의 스크립트 구현과 / 이어질 DragonBoss2의 스크립트 가 남게 되었습니다.

     

     

    00 : 20초

    오늘은 여기서 마치며

    이제 지상에 내려온 드래건이 이제 상태 값에 맞춰 동작 구현을 담당할

    DragonBoss2 스크립트를 작성하겠습니다.

    감사합니다.

     

     

     

     

    댓글

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