부트캠프/본캠프

[내일배움캠프_2025SEP21] 오늘 뭐했지..?

Young_A 2025. 9. 21. 21:57

목차

    오늘 뭐했지..?

     

    오늘 할일

    string 비교 방식 대신 hash 비교 방식을 static 메서드로 구현. (꼭 이곳이 아니라 범용적으로 활용할 수 있도록)

    특수 스킬 우선 구현

     

    그 후에 남으면 기존 코드들을 리팩토링 하는 걸로.

    + transform 기반 이동에서 rigidbody 기반 이동으로 변경하는 것

    + string값 비교에서 해시 값 비교하는 것

     

    이걸로도 충분할 것 같은데, 플레이어와 몬스터 상호작용 부분에서 기획팀의 수정 사항들이 조금 있는 것 같아서 그것들 해결하다보면 리팩토링은 뒤로 미뤄질 것 같긴 하다.


    Utility static method

    Utility에서 자주 쓰는 method들을 추가하며 사용하는게 나을 것 같다는 판단에 생성했다.

    나 혼자 사용하는게 아니라 팀원들끼리 원하는 것 추가하고, 다른 팀원이 만들어놓은것 중에 알맞은게 있으면 사용하고 하는 식으로.

    일단, 몬스터 스킬에서는 애니메이션 normalizedTime에 따라 무언가 체크한 뒤 진행하는 경우가 많아서 관련 메서드를 추가했다.

    IsAnimationPlaying

    Animator를 받고, Hash값을 받으면 해당 애니메이션이 재생되는지 확인하는 메서드 먼저 만들었다.

    그러다가 normalizedTime를 더하게 되면 해당 시간까지만 구한다.

    음.. 여기에 적다보니 startTime과 endTime을 넣으면 더 좋겠다는 생각이 들어서 수정했다.

    public static bool IsAnimationPlaying(Animator animator, int animationHash, float normalizedTime = 1.0f)
    {
        if (animator == null) return false;
    
        AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
        return stateInfo.shortNameHash == animationHash && stateInfo.normalizedTime < normalizedTime;
    }

    TryGetAnimationLengthByNameHash

    public static bool TryGetAnimationLengthByNameHash(Animator animator, int animationHash, out float length)
    {
        if (animator == null)
        {
            length = 0f;
            return false;
        }
    
        RuntimeAnimatorController ac = animator.runtimeAnimatorController;
        foreach (AnimationClip clip in ac.animationClips)
        {
            if (clip.name.GetHashCode() == animationHash)
            {
                length = clip.length;
                return true;
            }
        }
        length = 0f;
        return false; // 애니메이션 클립을 찾지 못한 경우
    }

    Debug.Log 꾸미기

    Debug.Log("<color=yellow>Manager Scene Load Complete.</color>");

    팀원의 화면을 공유하며 보는데, 디버그 로그 컬러가 다른 걸 발견했다.

    바로 물어봤고, 위와 같은 코드로 색상을 변경할 수 있다는 것을 발견했다.


    Transition Duration 동안의 GetCurrentAnimatorStateInfo.IsName()

    상황: 공격이 안되는 상황.

    아래와 같은 코드 상황에서, 공격을 시작한 직후 바로 SetDamages(0)이 되면서, 공격을 하지 않는 상황.

    (AttackController에서 혹시 몰라 데미지가 0이면 공격이 들어가지 않도록 방어 코드를 짜놨었다.)

    if (!skillTriggered)
    {
        lastUsedTime = Time.time;
        FlipCharacter();
        monster.Animator.SetTrigger(AnimatorStrings.MonsterParameter.Shark);
        //todo. player damage 처리
        monster.AttackController.SetDamages(skillData.damage1);
        Debug.Log("[몬스터] Shark Set Damages: " + skillData.damage1);
        skillTriggered = true;
    }
    
    if (Time.time - lastUsedTime < 0.1f) //시작 직후는 무조건 Running
    {
        return NodeState.Running;
    }
    
    bool isSkillAnimationPlaying = IsSkillAnimationPlaying(AnimatorStrings.MonsterAnimation.Shark);
    if (isSkillAnimationPlaying)
    {
        Debug.Log($"Running skill: {skillData.skillName} (ID: {skillData.skillId})");
        state = NodeState.Running;
    }
    else
    {
        Debug.Log($"Skill End: {skillData.skillName} (ID: {skillData.skillId})");
    
        Debug.Log("[몬스터] Shark Reset Damages");
        monster.AttackController.SetDamages(0); //데미지 초기화.
        skillTriggered = false;
        state = NodeState.Success;
    }

    시도: 갓버그로그

    위와 같이 Shark Reset Damages라는 디버그 로그를 찍어봤을때, 애니메이션이 종료되고 출력될 것이라 예상한 것과는 다르게 애니메이션이 시작되자마자 Reset Damages 로그를 출력하는 것을 확인.

     

    비교하는 애니메이션 이름 확인을 해봤을 때 문제가 없음을 확인.

    원인: 애니메이션 트랜지션

    처음에는 Set Damages와 Reset Damages 로그가 동시에 출력되는 줄 알았는데

    보다보니까 미묘하게 시간차를 두고 출력되는 것 같았다.

     

    애니메이션 전환이 되는 동안 한프레임정도 튀는 것을 방지하기 위해 0.1f 동안은 무조건 Running을 반환하도록 했는데,

    이 기간동안만 기다리고 바로 IsAnimationPlaying에서 false를 반환하면서 데미지를 리셋하는 것 같았다.

    각 애니메이션으로 전환하는 Transition을 확인해보니 Fixed Duration이 체크되어있고,

    Transition Duration(s)가 0.25로 되어있었다.

    이는 0.1f 값보다 크므로, 저 기간동안 IsAnimationPlaying이 false를 반환하고 있는 것처럼 보였다.

    실제로 해당 값을 0으로 맞춰주니 의도한 대로 ResetDamages를 애니메이션 마지막에 출력하는 것을 확인할 수 있었다.

    결론

    이번 일로 Transition Duration 동안의 IsName은 false를 반환한다는 점을 배웠다.

     

    코드로 애니메이션 재생 상황을 확인하는 방식으로 구현하고 있다.

    처음의 의도는 애니메이션 이벤트에 따라 행동트리나 상태패턴에 영향을 주지 말자, 였는데

    어느 순간 애니메이션 이벤트를 그냥 쓰지 말자, 가 된 것 같기도 하다.

     

    현재 AttackController에서 SetDamages와 ResetDamages를 호출할 수 있도록 한 상태다.

    행동 자체에 영향을 주지 않고 데미지 값만 변경하는 메서드이다.

    이 경우에는 애니메이션 타이밍을 조절하기 위해서 애니메이션 이벤트를 활용하는 것도 나쁘지 않을 것 같다는 결론을 내렸다.


    느낀점

    오늘 한일

    CounterAttack 제약을 기획팀의 새로운 요청에 맞게 구현하기 위해 플레이어 팀과 함께 협업하여 수정.

    버그 픽스...?

     


    내일 학습 할 것은 무엇인지

    오늘 할일에서 못한 것들을 정리해보자면

    특수 스킬 구현 완성, rigidbody 기반 이동으로 변경하는 것, 해시값 비교(메서드는 구현했고 기존 코드들 수정이 남았음)...

     

    근데 내일 새로운 역할이 분담될 것 같아서 연관된 작업들을 먼저 진행하는 방향으로 작업 우선도를 조정해야겠다.

    또한 2차 모의 면접이 화-수 중에 있을 예정이니, 저녁 먹은 뒤에는 코드리뷰 + 팀 스크럼 중간 시간을 모의면접 준비 시간으로 활용해야겠다.