ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 몬스터 상태 구현
    연습 프로젝트/2D로그라이크 게임

     

     

     

    몬스터의 상태 구현과 애니메이션 작업 과정 입니다.

     

    public enum MonsterState
    {
        Idle, Walk, AttackReading, Attack
    }
    
    public MonsterState monsterState = MonsterState.Walk;

    현재 몬스터의 상태는 대기, 걷기, 공격대기중, 공격 으로 총 4가지 상태가 있으며 초기 상태는 걷기 상태 입니다.

     

    switch (monsterState)
    {
        case MonsterState.Idle:
            monsterAnimator.SetTrigger("Idle");
            if (player.position.x < transform.position.x)
            {
                Vector3 localScale = transform.localScale;
                localScale.x = -1;
                transform.localScale = localScale;
            }
            else
            {
                Vector3 localScale = transform.localScale;
                localScale.x = 1;
                transform.localScale = localScale;
            }
    
            timerStart = true;
    
            break;
        case MonsterState.Walk:
            monsterAnimator.SetTrigger("Walk");
    
            float targetX = startingPosition.x + distance * direction;
    
            monsterRigidbdy2D.velocity = new Vector2(speed * direction, monsterRigidbdy2D.velocity.y);
    
            if (direction == 1 && monsterRigidbdy2D.position.x >= targetX)
            {
                transform.localScale = new Vector2(-1, 1);
                direction = -1;
            }
            else if (direction == -1 && monsterRigidbdy2D.position.x <= startingPosition.x - distance)
            {
    
                transform.localScale = new Vector2(1, 1);
                direction = 1;
            }
            break;
        case MonsterState.AttackReading:
            elapsedTime += Time.deltaTime;
    
            float t = Mathf.Clamp01(elapsedTime / duration);
            transform.localScale = Vector3.Lerp(Vector3.one, new Vector3(2, 2, 2), t);
    
            if (elapsedTime >= duration)
            {
                elapsedTime = 0.0f;
                monsterState = MonsterState.Attack;
            }
            break;
        case MonsterState.Attack:
            break;
    }

    상태 구현은 Swith문 에서 각 상태에 맞게 동작을 구현해 주었습니다.

     

    하나씩 살펴 보겠습니다.

     

    case MonsterState.Walk:
        monsterAnimator.SetTrigger("Walk");
    
        float targetX = startingPosition.x + distance * direction;
    
        monsterRigidbdy2D.velocity = new Vector2(speed * direction, monsterRigidbdy2D.velocity.y);
    
        if (direction == 1 && monsterRigidbdy2D.position.x >= targetX)
        {
            transform.localScale = new Vector2(-1, 1);
            direction = -1;
        }
        else if (direction == -1 && monsterRigidbdy2D.position.x <= startingPosition.x - distance)
        {
    
            transform.localScale = new Vector2(1, 1);
            direction = 1;
        }
        break;

    먼저 상태가 Walk일 시 실행되는 case 입니다.

     

    초기 상태에 Walk 애니메이션을 실행 시켜주었으며 speed를 설정해 rigidbody2dvelocity를 이용해 이동 구현을 해주었습니다.

     

    최대 이동 거리는 Distance 로 3.0f 거리 이며 최대 및 최소 이동 거리에 도달 했을시 반대 방향으로 이동 합니다.

     

     

    public void BeDamaged(float damage, Vector2 dir, float force)
    {
        if (monsterState != MonsterState.AttackReading)
        {
            monsterState = MonsterState.Idle;
    
            monster_Hp -= damage;
            monsterRigidbdy2D.AddForce(dir * -force * recoilFactor);
        }
    }

    피격을 받을때 실행되는 BeDamaged 함수에서 피격을 받을 시 잠시 몬스터의 상태가 Idle로 되게 해주었습니다.

     

    case MonsterState.Idle:
        monsterAnimator.SetTrigger("Idle");
        if (player.position.x < transform.position.x)
        {
            Vector3 localScale = transform.localScale;
            localScale.x = -1;
            transform.localScale = localScale;
        }
        else
        {
            Vector3 localScale = transform.localScale;
            localScale.x = 1;
            transform.localScale = localScale;
        }
    
        timerStart = true;
    
        break;

    몬스터의 상태가 Idle 일 시 Idle 파라미터의 조건을 가진 애니메이션을 실행 시켜줍니다.

     

    다음 플레이어를 받아와 로컬 스케일 x를 이용하여 플레이어를 바라보게 해주었습니다.

     

    마지막 bool 변수인 timerStarttrue가 되면

     

    if (monsterState == MonsterState.Idle && timerStart == true)
    {
        readytimer += Time.deltaTime;
        while (readytimer > readytime)
        {
            monsterState = MonsterState.AttackReading;
            readytimer = 0;
            timerStart = false;
        }
    
    }

    타이머가 실행 됩니다.

     

    현재 설정한 값은 10초로  타이머에 도달할 때까지 잠시 대기시간을 갖게 되며 몬스터의 상태는 AttackReading 상태가 됩니다.

     

    case MonsterState.AttackReading:
        elapsedTime += Time.deltaTime;
    
        float t = Mathf.Clamp01(elapsedTime / duration);
        transform.localScale = Vector3.Lerp(Vector3.one, new Vector3(2, 2, 2), t);
    
        if (elapsedTime >= duration)
        {
            elapsedTime = 0.0f;
            monsterState = MonsterState.Attack;
        }
        break;

    이 후 마지막으로 몬스터의 로컬 스케일이 (1, 1, 1) 에서 (2, 2, 2)로 증가하는 로직을 구현해 주었으며

     

    아래 조건문을 보시면 타이머를 이용하여 elapsedTime duration(2.0f) 값 보다 크다면 더이상 스케일을 증가시키지 않고   몬스터는 Attack 상태가 됩니다.

     

    현재 몬스터의 애니메이터 창 입니다.

     

    코드에서 Settrigger를 보면 알 수 있듯이, 전이 되는 조건을 트리거로 설정해 주었습니다.


    비하인드 스토리..

     

     readytimer += Time.deltaTime; 과 같이 타이머를 설정해 주는곳 에서

     

     readytimer + Time.deltaTime; 로 설정하여 엉뚱한 곳을 수정하는 일이 발생했었습니다.

     

    무언가 잘 안되거나 오류가 발생할땐 무턱대고 유추하여 수정하지 말고, 차근차근 하나씩 살펴 봅시다..

     

    '연습 프로젝트 > 2D로그라이크 게임' 카테고리의 다른 글

    UI 정보 패널 & 미니맵  (0) 2024.06.08
    UI 기획 (1차)  (0) 2024.06.08
    몬스터 상태 구현 (Update)  (0) 2024.06.08
    플레이어 공격  (0) 2024.06.07
    플레이어 이동 로직  (0) 2024.06.06

    댓글

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