관리 메뉴

도드넷

게임 개발 일지#10 - 유니티 체력바를 만들어보자 + 쉴드 매커니즘 본문

창고/게임 제작 [시즌2]

게임 개발 일지#10 - 유니티 체력바를 만들어보자 + 쉴드 매커니즘

도드! 2016. 10. 11. 21:22
반응형




You are my pony waifu :3


게임 개발 일지#10 - 유니티 체력바를 만들어보자



#1 체력바 만들기


체력바는 총 2개의 스프라이트로 구성된다


하나는 비어있는 체력바 하나는 차있는 체력바.


차있는 체력바의 크기를 조절함으로 체력 상태를 표시한다.


차있는 체력바는 세부적으로


1) 일반


2) 팔로우


3) 쉴드


로 나뉜다.


팔로우는 체력이 빠진것을 비주얼적으로 표시하는걸로 리그오브레전드에서 발견할 수 있다.



3D 공간에서 보면 이런모양이다.


차있는 체력바는 크기조절이 오른쪽에서 왼쪽으로 줄어들어야하므로 피봇이 왼쪽끝에 오도록 만든다.


스프라이트 피봇 설정은 부모 요소안에 넣고 위치를 조절하는 방법으로 만든다.


#2 체력바가 캐릭터 머리위에 떠다니게 하기


사실상 자식요소로 만드는게 가장 쉬운 방법이지만 그렇게 할경우 스프라이트 크기조절이나 플립이 일어날경우 체력바도 같이 뒤집어지는 현상이 발생한다. 고로 체력바는 유닛과 분리되어야한다.


체력바에 체력바를 사용하는 유닛정보를 전달되면

체력바는 유닛의 체력바위치를 계속 따라다니게 만들면된다.


그전에 체력바를 그러면 어떻게 생성해야할까?


#2-1. 체력바 생성하기


        GameObject HPBAR = Instantiate(Prefab_HPBAR) as GameObject;
        HPBAR.GetComponent<HPBAR_Handler>().HPBAR_User = gameObject;


스타트함수에 들어가서 유닛이 활성화되면 즉시 체력바가 생성된다.

그리고 만들어낸 체력바에 사용 유닛정보를 전달해서 서로 통신할수있게 해준다.


#3 생성순간 자식요소 찾기


        if (HPBAR_User && !Registered)
        {
            // 여러가지 요소 찾아서 등록해놓기.
            User_Stat = HPBAR_User.GetComponent<Stats>();
            HPBAR_Positioner_Transform = HPBAR_User.transform.FindChild("HPBAR_Here").gameObject.GetComponent<Transform>();
            GameObject HPBAR_FULL = transform.FindChild("HPBAR_Full_Container").gameObject;
            HPBAR_FULL_END_Transform = HPBAR_FULL.transform.FindChild("HPBAR_Full_EndPoint").gameObject.GetComponent<Transform>();

            // 체력바 크기설정
            Vector3 newvec;
            newvec = This_Transform.localScale;
            newvec.x = newvec.x * User_Stat.HPBAR_Size_Ratio;
            This_Transform.localScale = newvec;

            Registered = true;
        }


생성된 순간사이에 갭이 발생할 수 있으므로 start 함수에서 레퍼런싱을 하는게 아닌

반복문에 넣고 if문으로 전달된 유닛정보가 있으면 레퍼런싱을 시작하게 한다.


#4 체력바 크기 조절하기 [코어]



        if (Registered)
        {
            // 위치 업데이트
            Vector3 newvec2;
            newvec2 = HPBAR_Positioner_Transform.position;
            newvec2.z = newvec2.z - 1.0f;
            This_Transform.position = newvec2;

            // 쉴드위치는 무조건 현재체력 끝자락에 위치하게 된다.
            HPBAR_Shield_Transform.position = HPBAR_FULL_END_Transform.position;

            // 쉴드 퍼센트에 따라 쉴드바 길이조정
            Vector3 newvec6;
            newvec6 = HPBAR_Shield_Transform.localScale;

            // 쉴드는 항상 최대 체력기준으로 표시된다.
            newvec6.x = User_Stat.Current_Shield / User_Stat.Max_HP;

            // 쉴드가 최대체력을 초과하면 1 꽉찬 상태로 표시한다.
            if (User_Stat.Current_Shield > User_Stat.Max_HP)
            {
                newvec6.x = 1;
            }

            // 쉴드와 최대체력 비율을 저장한다.
            float Shield_Ratio = newvec6.x;
           
            // 최대 체력과 현재 체력비율로 체력바 길이 조정
            Vector2 newvec;
            newvec = HPBAR_FULL_Transform.localScale;
            newvec.x = User_Stat.Current_HP / User_Stat.Max_HP;

            if (User_Stat.Current_HP <= 0)
            {
                newvec.x = 0;
            }

            // 만약 쉴드길이와 체력길이 둘다 합쳐서 1을 초과하면,
            if (newvec.x + Shield_Ratio > 1)
            {
                // 초과값 만큼 체력바를 밀어낸다.
                newvec.x = newvec.x - (newvec.x + Shield_Ratio - 1);

                if (newvec.x < 0)
                {
                    newvec.x = 0;
                }
            }

            // 체력바 길이 설정.
            HPBAR_FULL_Transform.localScale = newvec;
            HPBAR_Shield_Transform.localScale = newvec6;


// 스케일이후 위치 재업데이트

            HPBAR_Shield_Transform.position = HPBAR_FULL_END_Transform.position;


            // 팔로워 헬스 길이 조정
            Vector2 newvec3;
            newvec3 = HPBAR_FF_Transform.localScale;
            float Speed = 0.003f; // 팔로워 기본 속도는 0.003 입니다.

            // 길이 차이에 따라 감소속도 비율설정.
            float Diff_Ratio = HPBAR_FF_Transform.localScale.x / HPBAR_FULL_Transform.localScale.x;

            Speed = Speed * Diff_Ratio;

            // x 크기가 FULL 보다 더 크면 (데미지를 받으면) 줄여줍니다.
            if (HPBAR_FF_Transform.localScale.x > HPBAR_FULL_Transform.localScale.x)
            {
                newvec3.x = newvec3.x - Speed;
            }

            // 작으면 그냥 FULL에 맞춰줍니다. (힐같은 경우)
            if (HPBAR_FF_Transform.localScale.x < HPBAR_FULL_Transform.localScale.x)
            {
                newvec3.x = HPBAR_FULL_Transform.localScale.x;
            }

            // 빼는 과정에서 음수가 되는것을 방지하기 위한 메커니즘
            if (newvec3.x < 0)
            {
                newvec3.x = 0;
            }

            HPBAR_FF_Transform.localScale = newvec3;

        }



일반 체력바는 기본적으로 [자신의 현재체력 / 자신의 최대체력] 값을 X 축 스케일에 적용함으로써 구현된다.


팔로우는 일반 체력바가 팔로우의 X 스케일 보다 작아지면

차이값에 따른 비율을 일반 속도에 곱해 이를 기반으로 서서히 감소함으로

피가 줄어드는것을 비쥬얼적으로 표현한다.


쉴드는 만들기 좀 까다로운데..흠


#5 유니티 쉴드 만들기


쉴드는 체력의 일종인데 체력대신 데미지를 흡수하는 역할을 한다.


고로 이놈은 일반 체력바의 끝에 붙어있어야 한다. (막는 역할)


그리고 체력바는 기본적으로 일반체력과 최대체력을 표시하는것이

주 목표이므로 쉴드양은 최대체력의 크기에 상대 비례해야한다.


            newvec6.x = User_Stat.Current_Shield / User_Stat.Max_HP;


그런데 생각해보면 체력양보다 쉴드량이 많으면 쉴드량이 체력바를 뚫고가지 않을까?


현재 체력의 X 스케일 길이 + 현재 쉴드 량의 X 스케일 길이가 1을 초과할경우가 바로 그 경우에 해당하게 된다. 


그러면 초과값 만큼 일반 체력바를 뒤로 밀면된다.


            // 만약 쉴드길이와 체력길이 둘다 합쳐서 1을 초과하면,
            if (newvec.x + Shield_Ratio > 1)
            {
                // 초과값 만큼 체력바를 밀어낸다.
                newvec.x = newvec.x - (newvec.x + Shield_Ratio - 1);

                if (newvec.x < 0)
                {
                    newvec.x = 0;
                }
            }


이외에 쉴드가 최대체력을 초과하는 경우, 무조건 쉴드의 X 스케일을 1로 잡아준다.

(어짜피 체력기반의 상대표시가 되야하므로)


이외에 일반적인 상황에서는 일반 체력의 앞에 쉴드가 오고 쉴드는 데미지를 대신흡수하는 방패역할을 수행하게 된다.


#6 쉴드에 의한 데미지 흡수


            if (This_Stat.Current_Shield > 0)
            {
                float saved_dmg = Total_Dmg;
                Total_Dmg = Total_Dmg - This_Stat.Current_Shield; // 데미지 감소
                This_Stat.Current_Shield = This_Stat.Current_Shield - saved_dmg; // 쉴드 감소

                if (Total_Dmg < 0)
                {
                    Total_Dmg = 0;
                }
            }


일단 데미지를 저장하고


일단 보유 쉴드량 만큼 데미지를 감소시킨다.

만약 데미지가 0이하기 되면 그냥 0이된다.


저장된 데미지 만큼 쉴드를 깎는다.


만약 1000이라는 데미지를 받았고

쉴드가 500 있다고 하면

데미지는 500이 되고 쉴드는 깨져서 0 이 될것이다. 

(스탯 스크립트에서 쉴드가 음수일경우 0 으로 조정함)

이후 체력에 500 데미지가 들어간다.


만약 1000이라는 데미지를 받았고

쉴드가 1500 이면

체력이 받게되는 데미지는 0이될거고

쉴드는 500으로 감소한 상태가 될것이다.








반응형
Comments