본문 바로가기

만들고 싶은 QnA

Q. 플레이어를 따라오는 적 만들기

Unity, 2D, 플랫포머.

Enemy, Player, Wall으로 구성되어 있을 때, Enemy는 Player를 쫓아가면서 Wall을 뛰어넘어서 Player에게 다가가고 싶다.

 

    private Rigidbody2D enemyRB;
    private SpriteRenderer enemySprite;

Enemy, 즉 몬스터의 속도는 일정했으면 좋겠으므로, 움직이는 방식은 rigidbody의 velocity 값을 입력해서 구현해주도록 하자. 또, 왼쪽 오른쪽 움직일 때 스프라이트 방향이 달라지므로, SpriteRenderer도 받아와야 한다.

    private void Awake()
    {
        enemyRB = GetComponent<Rigidbody2D>();
        enemySprite = GetComponent<SpriteRenderer>();
    }

Awake에서 이런 값들을 받아오도록 하자.

 

그 다음은 점프. rigidbody를 받아왔으니, 위로 Addforce하는 방식으로 점프를 구현해보자.

    void Jump()
    {
        enemyRB.AddForce(jumpPower * Vector2.up, ForceMode2D.Impulse);
    }

이제 이것으로 y축의 움직임은 끝. 아래로 떨어지는 것은 중력에 의해, 위로 올라가는 것은 점프로만 실행할 것이다.

그럼 x축의 움직임은 어떨까? 꽤 제약을 많이 받는 편이다. 다른 몬스터, 벽, 플레이어 등에 영향을 받기에, 움직일 수 있는 상황인지 아닌지에 대한 bool값을 줄 것이다.

    void DetectMoveXTest()
    {
        Vector2 rayDirection = enemySprite.flipX ? Vector2.left : Vector2.right;
        RaycastHit2D hit = Physics2D.Raycast(gameObject.transform.position, rayDirection, detectMoveXDistance, ~EnemyLayer);
        if(hit.collider != null)
        {
            canMoveX = false;
        }
        else
        {
            canMoveX = true;
        }
    }

 

그런 상황을 테스트하는, DetectMoveXTest 코드가 아래와 같다.

rayDirection은 삼항 연산자를 사용하여 몬스터의 진행 방향이 오른쪽이면 오른쪽, 왼쪽이면 왼쪽을 가르킨다.

이 방향은 RaycastHit2D에 사용되어, 앞에 있는 물체를 찾는다.(단, ~EnemyLayer을 통해 같은 Enemy는 제외) 그래서 물체가 인식되면, canMoveX를 false로 반환한다.

        DetectMoveXTest();
        if (canMoveX)
        {
            Move();
        }
        else
        {
            Vector2 velocity = enemyRB.velocity;
            velocity.x = 0;
            enemyRB.velocity = velocity;
        }

위는 Update의 구문으로, canMoveX가 true라면 움직이고, false라면 움직이지 않도록 x의 속도를 0으로 만들어 y의 이동만을 허용한다.

    private void Move()
    {
        Vector2 velocity = enemyRB.velocity;
        if (targetTransform.position.x > gameObject.transform.position.x)
        {
            //몬스터가 오른쪽으로 이동
            enemySprite.flipX = false;
            velocity.x = speed;
        }
        else
        {
            //몬스터가 왼쪽으로 이동
            enemySprite.flipX = true;
            velocity.x = -speed;
        }
        enemyRB.velocity = velocity;
    }

Move()는 targer, 즉 플레이어의 위치가 몬스터보다 오른쪽에 있으면 오른쪽으로 이동하며 스프라이트가 정면을, 왼쪽에 있으면 왼쪽으로 이동하며 스프라이트가 뒤를 향하게 한다.

 

다음으로는 충돌을 찾는 것보다 조금 더 길게 RaycastHit2D를 사용하여, 앞에 벽이 있을 때 jump를 실행하는 코드이다.

    void DetectJumpTest() //몬스터 앞에 있는 물체 확인
    {
        //물체 방향에 따른 감지 방향
        Vector2 rayDirection = enemySprite.flipX ? Vector2.left : Vector2.right;
        //enemyLayer을 제외하고 감지한다.
        RaycastHit2D hit = Physics2D.Raycast(gameObject.transform.position, rayDirection, detectJumpDistance, ~EnemyLayer); 
        if (hit.collider != null)
        {
            //벽이면 점프
            if (hit.collider.CompareTag("Wall"))
            {
                Jump();
            }
            //플레이어면 공격
            if (hit.collider.CompareTag("Player"))
            {
                //Attack();
            }
        }
    }

여기까지 진행했으면, 물체는 플레이어를 향해 이동하고, 벽을 앞에 두면 점프하여 플레이어를 향해 넘어간다.

 

※ 이때, Pivot값은 SpriteRenderer에서 꼭 설정을 해주도록 하자. 바닥으로 판정해야 나중에 편해진다.

 

여기까지 진행했으면 대부분의 기능은 완성되지만, 몬스터가 여럿 있을 때는 서로 충돌하여 버벅거리는데, 이것은 똑같은 Layer끼리 충돌하지 않도록 하면 해결되는 문제다(Project Setting에서 설정 가능)