[Unity] 코인 먹기 및 적 AI 만들어보기

이준석·2021년 3월 13일
0

Unity

목록 보기
4/4
post-thumbnail

이전 블로그에서 작성한 글을 옮겼습니다.
읽으실 때 참고하시기 바랍니다.

서론

이번 시간에는 코인 스프라이트를 먹으면 코인이 사라지는 이벤트과 간단한 적 AI 를 만들어보는 시간을 가지도록 할 예정이다. 따라하다보면 여태것 배운 부분들의 응용이니 좀 더 쉽게 따라올 수 있을 것이다.

본론

8. 코인🎱 먹기 이벤트 만들기

우선 맵을 조금 넓혀서 코인을 배치할 수 있도록 여유 공간을 두고, 코인을 스프라이트를 만들어서 배치할 수 있도록 하자. 그리고 코인이 회전할 수 있도록 애니메이션까지 만들어보자.

지금껏 잘 따라왔다면 이 정도까지는 무리없이 해내야 한다.

이 부분까지 했다면 이제 캐릭터가 코인에 충돌하면 코인이 사라지는 코딩을 해보도록 하자. 여기서는 새롭게 Trigger(트리거) 라는 개념이 추가된다.

먼저 각 코인에 Circle Collider 2D를 추가한다. (동전 모양이 동그라미니까 그에 적절한 콜라이더를 선택해준다.)

그리고나서 콜라이더의 크기를 Radius를 조절해서 적절하게 동전의 크기와 비슷하게 맞춰준다. 이렇게 해야지만 자연스럽게 동전에 캐릭터가 닿았을 때 동전이 사라지는 효과를 줄 수 있다.

동전과 멀리 떨어져서 닿지도 않았는데 동전이 사라진다면 이질감이 들 것이다.

그리고 난 뒤에 Circle Collider 2DIs Trigger라는 조건이 있을 것이도 체크박스가 있을 것이다. 따라서 체크를 해주고 각 동전, 즉 아이템들에게 태그를 Item이라고 생성해서 달아주면 기본적인 셋팅은 끝나게 된다.

아이템 태그를 변경해주는 부분

트리거와 콜라이더 반지름 조절해주는 부분

따라서 우리가 생성한 플레이어 스크립트를 더블 클릭해서 켠다. 그리고 새로운 함수를 만들 예정인데, OnTriggerEnter2D이다. 이 부분을 입력하면 자동 완성이 뜨고 엔터키를 누르면 자동으로 함수가 만들어진다. 그리고 자동으로 만들어지면 private가 생성되는데 이 부분은 삭제해준다.

그리고 캐릭터가 이제 동전들과 충돌 할 때만 해당 메서드가 실행되어야 한다. 따라서 동전들이라는 것을 알아보기 위해서 아까전에 태그를 달았던 것이고 Collision을 통해서 부딪힌 스프라이트가 누군지 알 수 있다. 그리고는 먹었을 때는 코인이 사라져야 하기 때문에 코인을 게임뷰에서 비활성화 시키면 플레이어는 코인을 먹었다고 생각할 수 있다.

이 부분을 코딩으로 하면 다음과 같다.

void OnTriggerEnter2D(Collider2D collision) {
    //Tag가 item일 때
	if (collision.gameObject.tag == "Item") {
		//Deactive Item
		collision.gameObject.SetActive(false);
	}
}

그리고 실행해보면 플레이어가 코인 근처에 갔을 때 자동으로 코인이 사라지는 것을 볼 수 있다.

캐릭터가 코인과 부딪히게되면 코인이 사라지는 것을 볼 수 있다.

9. 적😈 AI 만들기

다음에는 적 AI를 만들어볼 예정이다. 따라서 아틀라스에 보면 초록색 캐릭터가 보이는데 귀엽지만 적 스프라이트로 사용해야 한다. 따라서 주인공 캐릭터를 만들듯이 스프라이트를 만들고 Idle 애니메이션 효과와 걷기 애니메이션까지 구현해보도록 하자. (걷기 애니메이션은 일단 만들어서 붙여두기만 하자)

적과의 동침이 시작되었다.

이렇게까지 구현했다면 20프로는 완성한 것과 다름없다. 그리고 아까 캐릭터가 코인과 충돌했을 때 해당 스프라이트가 코인이라는 것을 알게 하기 위해서 태그를 설정해주었는데 이와 마찬가지로 적 스프라이트에도 태그를 Enermy로 설정해서 만들어준다. 그리곤 이제 적 NPC는 스스로 움직여야 하기 때문에 이 부분을 코딩해보도록 하자.

플레이어 캐릭터와 똑같이 RigidBody가 추가되어 있기 때문에 물리력으로 적 NPC를 이동시키면 되는데 우선 Enermy에 쓰일 스크립트를 하나 추가해보도록 하자.

캐릭터를 방향키로 움직였을 때 움직일 수 있도록 한 AddForce를 이용해서 코딩을 해보면 다음과 같다.

    Rigidbody2D rigid;

    void Awake()
    {
        this.rigid = GetComponent<Rigidbody2D>();

        Think();
    }

    void Think() 
    {
        //Move
        this.rigid.velocity = new Vector2(-2, rigid.velocity.y);
    }

우선적으로 왼쪽으로 2만큼 이동하라고 임의로 내가 값을 주었다. 이렇게 코딩하고 실행해보면 적 NPC가 이와같이 움직이게 된다. (추후에는 랜덤값으로 변경할 것이다.)

적 NPC가 왼쪽으로 2의 속도만큼 움직이는 모습이다.

지금은 캐릭터가 막고 있었기 때문에 물리력에 의해 적 NPC가 멈췄는데 캐릭터가 없었다면 아마 낭떠러지로 떨어졌을 것이다. 따라서 지금 여기까지만 코딩을 하게 되면 적 NPC는 앞으로 전진밖에 못하는 멍청한 AI에 불과할 것이다. 이 문제를 해결하기 위해서 우리가 캐릭터가 점프하고 바닥에 착지 했을 때를 파악하기 위한 Raycast를 적 AI에도 추가할 것이다.

로직은 간단하다. 적 NPC가 밑으로 레이저를 쏴서 플랫폼이 있으면 전진하는데, 만약에 빛이 플랫폼이 없는 부분과 맞닥뜨리게 되면 행동을 멈추고 그 즉시 반대방향으로 이동하는 것으로 하면 될 것 같다. 따라서 점프할 때 사용한 Raycast를 그대로 가져와서 Enermy 스크립트의 FixedUpdate 부분에 붙여넣어주자. 그리곤 필요한 부분만 고쳐서 사용할 수 있도록 한다. (Awake 마지막줄에 Invoke("Think", 5); 를 추가해서 Think가 불릴 수 있도록 해주자)

 void FixedUpdate()
    {
        //Move
        this.rigid.velocity = new Vector2(nextMove, rigid.velocity.y);
        //자기 한수 앞
        Vector2 frontVector = new Vector2(rigid.position.x + nextMove * 0.3f, rigid.position.y);
        //Platform Check
        Debug.DrawRay(frontVector, Vector3.down, new Color(0, 1, 0));
        //빔을 쏘고 빔을 맞은 오브젝트에 대한 정보 (여기서는 layer가 Platform인 오브젝트만 받겠다.)
        RaycastHit2D rayhit = Physics2D.Raycast(frontVector, Vector3.down, 1, LayerMask.GetMask("Platform"));
        if (rayhit.collider == null) {
            Turn();
        }
    }

    //재귀함수
    void Think() {
        nextMove = Random.Range(-1, 2);
        //방향
        if (nextMove != 0) {
            render.flipX = nextMove == 1;
        }

        //재귀함수 호출
        float nextThinkTime = Random.Range(2f, 6f);
        Invoke("Think", nextThinkTime);
    }

    void Turn() {
        //방향 바꾸기
        nextMove *= -1;
        //캐릭터 뒤집기
        render.flipX = nextMove == 1;
        //생각 취소
        CancelInvoke();
        //다시 생각
        Invoke("Think", 5);
    }

nextMove라는 변수를 int로 전역 변수 선언을 해준다. 위에서부터 차례대로 설명하면 Raycast는 점프하는 부분에서 한 번 다뤘으니 점프와 다른 부분을 다루자면 빛이 적 NPC의 한 발 앞에서 쏘고 있는 부분을 볼 수 있다. (0.3f) 왜냐하면 적 NPC가 떨어지기 전에 바닥이 없다는 것을 파악하기 위해서이기 때문이다. 따라서 해당 값은 본인이 조금씩 조정하면서 적절한 값을 찾으면 된다. 그리고 점프와는 다르게 Collisionnull일 때 조건을 실행하는데, 바닥이 없으면 null값이 들어오기 때문에 이 부분만 주의해서 하면 될 것 같다.

그리고 Think 함수는 말 그래도 자기가 자기를 계속해서 호출하는 함수(=재귀함수)이다. 따라서 nextMove라고 적 NPC가 왼쪽으로 갈 지 (-1), 가만히 있을지 (0), 오른쪽으로 움직일 지(1)를 랜덤값으로 호출해주는데 min값은 포함되지만 max값은 포함되지 않기 때문에 2로 설정해준다.

그리고는 nextMove가 0이 아닐 때, 즉 가만히 있는 것이 아닐 경우에는 nextMove 값에 따라서 flipX를 통해서 바라보는 방향을 바꿔준다. 마지막으로 Invoke 함수가 있는데 해당 메서드를 설정한 초 간격씩 호출할 수 있는 기능을 제공한다. 따라서 메서드 이름을 적고, 그 옆에 숫자를 적으면 그 시간마다 한 번씩 호출하게 된다. 따라서 함수 호출이 곧 AI의 방향을 결정짓는 부분이기 때문에 시간 또한 랜덤값으로 설정하고 Invoke에 넣어주었다.

마지막으로 Turn은 FixedUpdate 안에 넣어두어도 되지만 가독성을 위해서 따로 분리해두었다. 그리고 나머지 설명은 주석을 통해서 살펴보면 될 것 같다.

이와같이 실행하면 적 NPC가 다음과 같이 움직인다.

왼쪽으로 갔다가 땅에 안떨어지고 오른쪽으로 방향을 바꾼다.

왼쪽으로 움직였다가 땅에서 떨어질 때 쯤 방향을 반대로 바꿔서 이동한다. 그리고는 랜덤값에 따라서 가만히 멈춰있는 부분도 살펴볼 수 있다.

이렇게하고 마지막으로 걷는 애니메이션 효과를 주면 되는데, 여기서 조금 다른 부분이 있다. 예전에는 bool값으로 걷는지 점프하는지를 파악했는데, 이 부분은 우리가 조작을 통해서 해당 버튼이 눌리는지에 대한 여부만 파악하면 되었기 때문에 bool로 가능했다. 하지만 적 NPC는 모든 값이 랜덤값으로 들어가고, 눌리는 버튼 또한 없다. 따라서 이전과는 다른 int 변수를 선언해서 Transition에 추가한다. 그리고는 0일 때는 idle, 0이 아닐 때는 Walk로 조건을 설정해준다.

그리고는 다음과 같이 코딩하면 걷는 애니메이션이 실행된다. (추가된 부분만 넣겠습니다.)

	//재귀함수
    void Think() 
    {
        nextMove = Random.Range(-1, 2);
        //애니메이션
        animator.SetInteger("WalkSpeed", nextMove);
        //방향
        if (nextMove != 0) {
            render.flipX = nextMove == 1;
        }

        //재귀함수 호출
        float nextThinkTime = Random.Range(2f, 6f);
        Invoke("Think", nextThinkTime);
    }

애니메이션을 설정하고 기존 코드에서 Think 부분에 animator만 선언해주면 된다. (물론 Awake에서 animator를 초기화해주어야 한다.)

이렇게 하면 적 NPC가 다음과 같이 움직이는 것을 알 수 있다.

랜덤값에 의해서 적 NPC가 움직인다.

결론

여기까지가 오늘의 목표 과제다. 코인 먹었을 때 코인이 사라지는 이벤트와 간단한 적 NPC AI 구현하기를 마쳤다.

아마 다음 시간에 한 두 가지만 더 하면 이번 플랫포머 게임 프로젝트 포스팅은 끝날 것 같다.

물론 나밖에 안보고 내가 쓰고싶을 때 쓰는 블로그라서 건성 건성 할 수 있지만, 나 나름대로 해당 포스팅을 위해서 다시 복습하고 직접 해보면서 캡쳐하고 있기 때문에 공부하는데 많은 도움이 되고 있다.

따라서 빠르게 다음 포스팅을 마치고나서 쯔구르 형식의 게임 만드는 부분까지는 공부를 해보고나서 내가 만들고 싶은 게임을 만들려고 생각중에 있다.

여기서 다시 한 번, 남을 가리키기 위한 포스팅이 아닌 내가 다시금 복습하면서 간단하게 적어보는 부분이다. 그런데 내 포스팅을 보고 배움이 있다면 다행이지만 좀 더 체계적인 배움을 위해서는 다른 블로그 글을 보시는 것이 더 좋을 수도 있다.

그리고 유니티를 생각보다 내가 잘 따라가고, 버그없이 진행되는 모습이 뿌듯하다.

그럼 오늘 포스팅은 여기서 마치겠습니다.

바바~🖐🖐

profile
호주 워홀중

1개의 댓글

comment-user-thumbnail
2021년 3월 15일

와! 유니티도 하시네요!

답글 달기