ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2D 슈팅게임 05. Enemy Hit 및 아이템 드롭
    유니티 프로젝트/2D.SpaceShooter

    오늘은 날아다니는 Enemy 들을 맞췄을 시 발생하는 Hit 모션과 아이템이 드롭되는 부분을 구현하고

    게임을 완성 시키려고 합니다.

     

    전과 같은 방법으로 Sprite를 애니메이션으로 만들어주어 Hit 모션을 만들어 줬습니다.

     

    애니메이션을 만드는 과정에서

    Has Exit Time 부분을 종종 깜빡하는 경우가 생기는데

    Has Exit Time 를 체크해두면 전 애니메이션의 동작이 완료된 후에 트랜지션대로 전이가 됩니다.

    반대로 Has Exit Time 를 언체크 해두시면 즉시 전이가 되기에

    깜빡하지 않는 습관을 들인다면, 시간을 절약시킬 수 있습니다.

     

    Enemy의 Animator

    Enemy의 Animator 입니다. 

    평상시는 대기상태로 나는 모션을 취하다가, 히트가 됐을 시 Hit모션 재생 후 다시 BirdRed의 대기 상태로 돌아옵니다.

    여기서 조건을 걸어주지 않고 Has Exit Time만 체크를 해 두면 Hit 모션이 완료된 후 트랜지션 방향으로 전이됩니다.

    또한 한 가지 더 알게 된 점을 말씀드리자면

    이렇게 화살표를 자기 자신에게 해 두면 roop가 되어있지 않아도 반복 재생을 하게 됩니다.

    물론 roop설정을 체크하여 반복 재생을 해도 되지만, 특정 구간을 반복한다거나 할 때

    좀 더 생각을 해 보면 다양한 연출이 가능하지 않을까 싶습니다.

    쓰게 되면 한번 더 설명하겠습니다.


     

     

    Enemy의 Move를 담당하는 코드를 작성했던 스크립트입니다.

    OnTriggerEnter2D를 사용하여, 물체가 닿았을 시 를 체크해 두었습니다.

    Trigger / Collider의 함수는 이전에도 설명드렸지만 기억을 되살리기 위해서

    Enter / Stay / Exit 3가지가 존재합니다.

    Eneter : 접촉할 시

    Stay : 매 접촉하고 있을 시

    Exit : 접촉이 해제될 시

     

    이며, Collider / Trigger의 차이점을 보자면

    Collider는 물리연산을 하며 충돌 감지 / Trigger는 물리연산을 하지 않으며 충돌감지

    로 볼 수 있습니다.

     

    OnTriggerEnter2D의 함수에서 충돌된 물체가 Atk(공격 물체) 라면의 조건을 걸어줬습니다.

    이후 Enemy Red의 자식으로 붙어있는 (코인/똥)을 검사하여

    0,1의 랜덤 값을 받아와 Transform child 변수에 넣어줍니다.

     

    받아온 자식을 SetActive로 활성화시켜주는 구현의 함수입니다.

    GetComponent <Animator>(). Play("Hit")로 히트 모션을 실행시켜주고
             transform.localScale = new Vector2(0.4f, 0.4f) 히트 모션 시각화를 더해주기 위해 스케일을 키웠습니다.
                이후 StopCoroutine("BirdMove")을 이용해 코 루틴 함수를 멈춰주어 일시적인 정지 상태를 연출했습니다.

     

    이후 HitEvent 함수를 만들어, Enemy의 스케일을 원래 상태로 되돌려 주고

    Enemy의 스피드 값과 Animator의 변수 speed 값을 6으으로 변경하여

    히트 모션이 끝난 뒤 빠르게 움직이는 것을 구현하였고

     

    OnTriggerEnter2 D 함수에서 StopCorutine으로 멈췄던 BirdMove를 다시 실행시켜 주었습니다.

     

    이 HitEvent함수는 OnTriggerEnter2D에서 Invoke 함수로 0.3f초 후에 실행되며

    0.3f초의 값은 애니메이션의 플레이되는 시간을 체크하여 설정했습니다.

     

    여기서 중요한 child.parent = null입니다.

    parent를 Null로 지정해 주어 빠져나오지 않으면,

    Enemy가 좌/우 방향으로 움직이면서 아이템도 따라 같이 움직이는 

    심각한 오류가 발생하기에

    parent를 null로 지정시켜 주어 생성됐을 시 단독 객체로 지정되게 해 주었습니다.

     

    하지만 단순이 이렇게만 해 두면 Enemy의 위치에서 아이템이 생성되기에,

    아이템이 낙하되도록 구현해 보겠습니다.

    우선 아이템들에게 Capsule Collider와 Rigidbody를 추가시켜 주어 충돌 감지와 중력을 주었습니다.

    이전에도 설명드렸지만

    특별한 일이 아니면 Sphere -> Capsule -> Box의 연산처리속도가 빠른 순서대로 작성하겠습니다.

     

    이렇게 낙하되는 아이템을 OnTriggerEnter2 D 함수에서 구현하며

    tag가 Ground일시 또는 || tag가 Player일 시 에만 작동하게 if조건문을 걸어줍니다.

     

    갑자기 든 생각인데 유니티를 학습하면서 전 또는 || / 그리고 && 를 사용하였는데

    | / & 만 사용하는 경우도 한 번씩 볼 경우가 있었습니다.

    이걸 Bitwise 연산자라고 하는데..

    int x = a && b && c &&

    int y = a &   b &   c &  

    이렇게 다른 두 연산자가 있다고 하면,

    int x는 a가 거짓일 땐 b와 c를 수행하지 않고 바로 false를.

    int y는 a와 b와 c까지 수행하고 하나라도 거짓이 있으면 false를

    반환한다고 하는데,, 특별한 경우가 아니라면 | 또는 & 을 사용할 필요는 없다고 합니다.

    좀 더 학습을 해보고 사용할 때가 찾아오면 바로 알려드리도록 하겠습니다.


    큼큼.. 다시 돌아가서 충돌 처리가 Ground이거나 Playe r면 SetActive(false)를 통해 비활성화를 해 주고

    null로 지정했던 Item을 다시 원래 SetParent를 통해 원래 부모의 자식으로 돌아오게 해 주었습니다.

    item은 OnEnable 함수에서 transform.parent로 지정해 주어 놨습니다.

     

    완료가 된 것 같지만, 아직 해결되지 않은 부분들이 있습니다.

     

    1. Attack버튼을 눌러 공격 시, Atk(공격 물체)가 새를 맞아도 통과하는 점.

    2. 각 아이템들과 충돌 시 player의 상태 변환

    3. jump키의 사용 목적으로 트릭 설치.

     

    천천히 하나씩 진행하겠습니다.

     

    우선 Atk(공격 물체)가 새를 맞아도 통과되는 부분부터 해결하겠습니다.

    Atk 기능을 담당하는 스크립트에서 OnTriggerEnter2D부분입니다.

    태그를 검사하여 "Bird"일 시 작동하는 if 조건문입니다.

    진행 중인 AtkMove의 코 루틴 함수를 Stop 시켜주고

    gameObject.SetActive(Flase)를 사용해 비활성화를 해 줍니다.

    마지막으로 localPosition 값을 Vector2.zero로 원점으로 만들어 줍니다.

     

    2. 각 아이템들의 충돌 시 player의 상태 변환

     

    이 부분은 Player에게 새로운 스크립트를 입혀서 해결하였습니다.

     

     

    OnTriggerEnter2 D 부분입니다.

    Player와 충돌한 물체가 각 코인/스피드/똥 일시 3 분류입니다.

    -코인을 먹게 되면 score에 100점이 추가되며 텍스트로 보이는 부분입니다.

    -스피드를 먹게 되면

    이 어택 버튼들의 스크립트들을 가져와 Atk(공격 물체)의 스피드를 1 추가시켜줍니다.

    -똥을 먹게? 과 부딪히게 되면

    Die()의 함수를 실행합니다.

    Die 함수가 실행되면 제일 처음으로 gameOverText가 SetActive로 활성화가 됩니다.

    이후 동작 버튼들은 SetActive(false)로 비활성화가 되며.

    플레이어가 Hit동작을 취합니다.

     

    이후 Player의 rigidbody와 Collider를 제거하여 충돌 체크가 안되게 하고 게임을 멈춰도 됐지만 

    player만 동작을 멈춘다면 어색함이 연출될 수 있어서, 게임 신을 전체 멈추는 Time.timeScale을 사용하였습니다.

    이 Time.timeScale은 유니티 씬의 시간이 이 실제 시간으로 흐른다는 것을 의미하며

    float값으로 설정이 가능하며 0.5f = 절반의 시간을 의미, 2.0f라면 2배의 속도를 의미 하기에

    몬스터의 Hit모션이나 느린 화면 전환 등에 사용하여 보다 높은 퀄리티 향상에 도움이 될 것 같습니다.


     gameOver텍스트에 스크립트를 추가시켜주어

    게임상의 씬의 속도를 다시 1로 추가시켜 줬으며,

    OnClick 이벤트를 사용해도 되지만

    비활성화될 시 사용되는 OnDisable을 사용해 봤습니다.

    이번 프로젝트를 하면서 설명드렸던 OnDisable 함수인데

    이렇게 빨리 사용하게 될지 몰랐습니다 ㅎㅎ

    이후 UI를 담당하는 MainMenu 스크립트에서 Restart버튼을 누르면 발생시킬 원클릭 이벤트 함수를 만들어주고 

    이렇게 적용을 해 주면!!

     

    끝!!인 줄 알았는데

     

    아직 트릭을 설치를 안 해서 Player의 jump를 필요성이 아직 없습니다..

     

    이제 정말 마지막으로 트릭을 설치해 보겠습니다.

     

    트릭을 전깃줄 방향으로 할지, 데드존처럼 땅에서 일정 시간이 지난 후 불길이 나오는 걸로 할지

    적용을 해봤는데, 배경 이미지가 고정적이어서 그런지 상당히 어색함이 연출되었습니다.

     

    그래서 내린 결론이 Enemy(Bird) 들과 비슷하게 날아다니는 형태로 위치와 스피드를 랜덤 값으로 주어서

    충돌 판정 시 Player가 죽는 모습을 연출했습니다.

    트릭으로 사용될 유니티 에셋 스토어에서 무료로 다운로드하였습니다.

    트릭의 Move 방식도 Enemy와 비슷하게 정해진 Speed값 + 1f - 2f랜덤 값을 더해 

    속도에 변화를 주었으며

    transform의 x축의 위치가 0보다 클 땐 방향을 -1로 반대로 0보다 작을 땐 방향을 1로 설정해 두었고

    SpriteRenderer에 있는 flipX값을 이용해 방향 전환을 하였습니다.

    트릭의 움직임을 매 프레임마다 실행되는 Update가 아닌 코 루틴 함수로 실행하였습니다.

    Translate함수를 사용하여 right의 방향에 * 지정 방향 * 스피드 * Time.deltaTime으로 맞춰 주었고

    Abs를 활용한 절댓값으로 트릭의 위치를 체크해 두어

    일정 방향 이상으로 가면 SetActive(false)로 비활성화를 시키고 StopCorutine로 BirdMove 함수를 종료시켜 줬습니다.

     

    마지막 OnTriggerEnter2 D 함수입니다.

    태그를 체크하여 "Player"라면

    player에 붙은 Die함수를 실행시켜 줍니다.

    트릭이 생성되는 전체 코드입니다.

     

    GameObject []로 미리 생성되어 있는 트릭들을 담아 왔고

    trick_Time의 변숫값을 생성시간으로 인스펙터 창에서 지정하려고 선언했습니다.

     

    Enemy(Bird)와 마찬가지로 랜덤 값을 주어 맵을 벗어난 최소 거리와 최대 거리를 0과 1로 받아

    x == 0 이면 -4

    x == 1 이면 4

    로 생성되는 x축을 지정해 주었고.

    for (int i = 0; i < Tric.Length; i++)로 트릭들을 검사하여

    트릭 하이어라키 참고용

    activeSelf를 이용해 비활성화되어있다면 그 i번째 트릭의 위치를

    지정된 x축과 -2로 고정시켜 활성화되게 해주는 코드입니다.

     

    마지막으로 이 함수 코드를 BirdCreate의 코 루틴 함수에서 실행시켜 줍니다.

    yield return new WaitForSeconds(time)를 사용해 지정된 시간을 멈춰 있도록 해 주었고

    지정된 시간이 끝나면 CreateTrick(birdBox)로 함수를 실행시켜 줬습니다.

     

    테스트 용도의 KeyCode.Q와 W의 입력값을 받아

    ( JumpBtn = q / AttackBtn = w )

    테스트를 진행하였습니다.

     

    댓글

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