ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 최적화 - 11 (설정수정★)
    Galaxy Ball/5. 최적화 2024. 10. 17. 20:10

    2024.10.09 - [Galaxy Ball/5. 최적화] - 최적화 - 10 (설정 수정★)

     

    최적화 - 10 (설정 수정★)

    안좋은 소식이 있다.. 최근에 핸드폰에다 다시 한번 빌드를 해본 결과....달라진게 없다...확실히 컴 유니티에서는 부드러워진게 체감이 되길래 진짜 끝난줄 알았는데 다시 원점이다 하지만 낙

    sangeun00.tistory.com

     

    지난 글에 이어 계속해서 최적화를 해보도록 하겠다

     

     

    • Rigidbody Interpolation:
      • Rigidbody2D의 Interpolation을 Interpolate 또는 Extrapolate로 설정하여 물리 기반 오브젝트의 움직임을 더 부드럽게 만들 수 있습니다.
    • Dynamic Resolution:
      • 모바일 플랫폼에서는 동적 해상도(Dynamic Resolution)를 활용하여 프레임 수를 유지하면서 그래픽 품질을 조정할 수 있습니다.
    • Object Pooling:
      • 많은 게임 오브젝트를 생성하고 파괴하는 대신 오브젝트 풀링을 사용하면 메모리 할당 및 해제를 줄여 성능을 향상시킬 수 있습니다.
    • Profiler 사용:
      • Unity Profiler를 사용하여 어떤 부분에서 성능이 저하되고 있는지 분석해보세요. CPU, GPU, 메모리 사용량을 확인할 수 있습니다.
    • Update 호출 최적화:
      • Update 메서드 내의 연산을 최소화하고, 필요하지 않은 경우에는 Coroutine이나 이벤트를 사용하여 성능을 개선하세요.
    • UI 최적화:
      • Canvas의 설정을 확인하고, 불필요한 UI 요소를 줄이는 것도 좋습니다. UI 요소가 많을 경우 성능 저하를 일으킬 수 있습니다.

    남은 부분들. 이번엔

    • Rigidbody Interpolation:
      • Rigidbody2D의 Interpolation을 Interpolate 또는 Extrapolate로 설정하여 물리 기반 오브젝트의 움직임을 더 부드럽게 만들 수 있습니다.

    를 알아보자. 

     

    Rigidbody2D의 Interpolation 설정을 통해 물리 기반 오브젝트의 움직임을 더 부드럽게 만들 수 있다.

    특히, 저사양 장치나 프레임이 끊기는 경우에 도움이 되며, 주로 시각적으로 움직임을 더 매끄럽게 표현하는 데 사용된다

     

    Interpolation에는 3가지의 옵션이 있다.

     

    • None (기본값): 이 옵션은 Interpolation을 사용하지 않는 상태입니다. 이 경우, 물리 시뮬레이션이 프레임마다 바로 적용되며, 빠르게 변하는 오브젝트의 움직임에서 끊기는 현상이 나타날 수 있습니다. 특히 프레임 속도가 물리 업데이트 속도와 다를 때 더 두드러집니다.
    • Interpolate: 이 옵션은 이전 프레임의 물리 상태를 사용하여 현재 프레임의 물리적 위치를 부드럽게 연결합니다. Interpolate는 렌더링 프레임이 물리 프레임보다 많을 때 유용하며, 움직임이 자연스럽게 보이도록 도와줍니다. 특히 저속으로 움직이는 오브젝트나 카메라에 따라 화면이 흔들리는 상황에서 많이 사용됩니다.
    • Extrapolate: Extrapolate는 현재 프레임의 물리 상태를 바탕으로 다음 프레임의 위치를 예측합니다. 이 방식은 물리 프레임이 렌더링 프레임보다 적을 때 유용합니다. 즉, 물리 연산이 프레임 업데이트보다 느릴 때도 부드러운 움직임을 유지할 수 있습니다.

    그리고 또 이게 이전글에서 배웠던 Fixed TimeStep과 연관이 있다. 거기서 맞춰준 수치에 따라

    물리계산이 여기서도 적용이 되기 때문에 그것과 잘 연계를 시켜줘야 한다

     

     

    그래서 둘 중 어떤것을 사용하는것이 더 좋을까? 당연한 말이지만 상황에 따라 다르며 차이점을 알아보았다

    1. Interpolate

    • 사용 시기:
      • 게임이 프레임 속도가 높고 물리 계산보다 렌더링이 빠른 경우. 즉, 물리 업데이트와 렌더링 업데이트가 잘 맞지 않을 때, 움직임을 부드럽게 하기 위해 사용합니다.
      • 느리게 움직이는 물체나 카메라와의 상호작용이 중요한 게임에서 적합합니다.
      • 예를 들어, 슬로우 모션 효과를 내고 싶거나 부드러운 캐릭터 움직임을 원할 때 Interpolate를 사용하는 것이 좋습니다.

    2. Extrapolate

    • 사용 시기:
      • 물리 프레임이 렌더링 프레임보다 느린 경우에 적합합니다. 물체의 위치가 더 빨리 변할 때 예측하여 부드럽게 보이도록 해줍니다.
      • 빠르게 움직이는 물체에 대해 적용할 수 있으며, 이론적으로 더 나은 반응성을 제공할 수 있습니다.
      • 다만, 빠른 움직임이 일어날 때 방향 전환이 급작스럽다면 정확도가 떨어질 수 있습니다.

    대부분의 경우가 Interpolate를 사용하긴 한다. 특정 상황에 따라 Extrapolate도 사용할 수 있다

     

     

    변경하는법은 간단하다. Rigidbody2D가 적용된 오브젝트 Inspector창에서 변경해주면 된다

    다른 오브젝트들은 차이가 크게 느껴지지 않았는데

     

    저속으로 움직이는 오브젝트나 카메라에 따라 화면이 흔들리는 상황에 많이 쓰이는 

     

    Player는 확실한 차이가 체감된다 히히 Fixed Timestep 0.3으로 올려줘도 부드럽게 움직이는 모습을 확인할 수 있다

     

     

    다른 씬에서 한번 더 확인해봤는데 확실한 차이가 보인다. 

    그래서 RigidBody2D가 부착된 모든 오브젝트의 설정을 Interpolate로 변경해주었다

     

     

    이번엔 UI를 개선해보도록 하자

     

    UI 최적화:

    • Canvas의 설정을 확인하고, 불필요한 UI 요소를 줄이는 것도 좋습니다. UI 요소가 많을 경우 성능 저하를 일으킬 수 있습니다.

    당연한 얘기지만 캔버스안에는 최대한 적은 양이 들어가는게 최적화에 효과적이며

    가능한 한개의 캔버스안에서 모든 UI 요소들이 들어가있는게 좋다고 한다

     

    추가로 캔버스 설정 > Render Mode > Screen Space - Overlay가 가장 성능 향상에 좋다고 한다

    하지만 이미 기본값으로 모두 들어가있으니 넘어가겠다

     

    UI 요소의 위치를 변경할 때는 RectTransform을 직접 수정하는 것이 좋다.

    Transform을 변경하면 전체 객체가 다시 계산되어 성능이 저하될 수 있다.

     

    캔버스 요소의 투명도가 0이 되면 비활성화 하겠냐는 옵션이다. 체크해두자

     

    그러니 최대한 하나의 캔버스 안에 한씬에서 쓰이는 모든 UI 요소들을 넣어주는것이 중요하다

     

    • 렌더링 효율성: Unity는 각 캔버스를 개별적으로 렌더링하므로, 여러 개의 캔버스를 사용하면 그만큼 렌더링 오버헤드가 발생합니다. 하나의 캔버스에 UI 요소를 집합시키면 이러한 오버헤드를 줄일 수 있습니다.
    • 업데이트 최적화: UI 요소가 변경될 때마다 해당 캔버스 전체가 다시 렌더링되므로, 가능한 한 적은 수의 캔버스를 사용하면 전체적인 성능을 향상시킬 수 있습니다. UI 요소가 많은 경우, 불필요한 렌더링을 방지하기 위해 가능한 한 같은 캔버스에 배치하는 것이 좋습니다.
    • 관리 용이성: 모든 UI 요소를 하나의 캔버스에 배치하면 계층 구조가 단순해지고, 관리와 유지보수가 용이해집니다. 여러 캔버스를 사용하는 경우 각 캔버스의 상태를 관리하는 것이 더 복잡해질 수 있습니다.

     

     

    그리고 나서 인게임 요소를 보자 굉장히 이상하게 배치를 해두었었다.

    도대체 왜 이렇게 한건지 이해가 안가지만 배워가는 과정에서 만들었으니 그려려니 하고 수정해주자

     

     

    가장 먼저 다른 캔버스에 있는 튜토리얼용 UI부터 하나의 캔버스에 통합해주었다. 왜 따로 만든건지는 모르겠다

    튜토리얼은 StageClearID의 값에 따라 나와야할때만 나오는 방식인데 StageClearID의 값이 1,7이 아니어도

    비활성화가 되질 않아 마지막 else문에 추가해주었다

     

    튜토리얼 마지막 이미지가 비활성화 되어도 오브젝트 자체가 함께 비활성화 되도록 코드를 수정해주었다

     

     

    그렇게 총 3개가 쓰이던 캔버스를 하나 안에 통합해주었다

     

    그리고 중간에 우연히 설정창에 들어가보았는데

    여기서 움직이는 공들은 왜 이렇게 뚝뚝 끊기나 싶어 봤더니

    언제적 구식 코드를 사용하고 있었다..

     

    using System.Collections;
    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    using UnityEngine.UIElements;
    
    public class SCBallController : MonoBehaviour
    {
        Rigidbody2D rb;
        BGMControl bGMControl;
        bool hasBeenLaunched = false;
        public bool isExpanding = false; // 공이 팽창 중인지 여부
        bool isStopped = false; // 공이 완전히 멈췄는지 여부
        private float decelerationThreshold = 0.4f;
        private float dragAmount = 1.1f;
        private float expandSpeed = 1f; // 팽창 속도
        private Vector3 initialScale; // 초기 공 크기
        private Vector3 targetScale; // 목표 크기
        private int durability; // 공의 내구도
        public PhysicsMaterial2D bouncyMaterial;
        private TextMeshPro textMesh;
    
        public int fontsize;
        public int PlusScale;
    
    
        void Start()
        {
            bGMControl = FindAnyObjectByType<BGMControl>();
            rb = GetComponent<Rigidbody2D>();
    
            GameObject textObject = new GameObject("TextMeshPro");
            textObject.transform.parent = transform; // 구체의 자식으로 설정
            durability = Random.Range(1, 6);
    
            textMesh = textObject.AddComponent<TextMeshPro>();
            textMesh.text = durability.ToString();
            textMesh.fontSize = fontsize;
            textMesh.alignment = TextAlignmentOptions.Center;
            textMesh.autoSizeTextContainer = true;
            textMesh.rectTransform.localPosition = Vector3.zero; // 구체 중심에 텍스트 배치
            textMesh.sortingOrder = 1; // 레이어 순서를 조정하여 구체 위에 배치
    
            rb.drag = 0f;
            rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
            rb.interpolation = RigidbodyInterpolation2D.Interpolate;
    
            Collider2D collider = GetComponent<Collider2D>();
            if (collider != null && bouncyMaterial != null)
            {
                collider.sharedMaterial = bouncyMaterial;
            }
    
            initialScale = transform.localScale;
        }
    
        void Update()
        {
            if (!hasBeenLaunched)
            {
                LaunchBall();
            }
    
            if (hasBeenLaunched && !isStopped)
            {
                SlowDownBall();
            }
    
            if (isExpanding)
            {
                ExpandBall();
            }
        }
    
        void LaunchBall()
        {
            Vector2 launchForce = SCGameManager.shotDirection * (SCGameManager.shotDistance * 1.4f);
            rb.AddForce(launchForce, ForceMode2D.Impulse);
    
            rb.drag = dragAmount;
            hasBeenLaunched = true;
        }
    
        void SlowDownBall()
        {
            if (rb == null) return;
    
            if (rb.velocity.magnitude <= decelerationThreshold)
            {
                rb.velocity = Vector2.zero;
                isStopped = true;
                StartExpansion();
            }
        }
    
        void StartExpansion()
        {
            bGMControl.SoundEffectPlay(1);
            targetScale = initialScale * PlusScale;
            isExpanding = true;
        }
    
        void ExpandBall()
        {
            if (Vector3.Distance(transform.localScale, targetScale) > 0.01f)
            {
                transform.localScale = Vector3.Lerp(transform.localScale, targetScale, Time.deltaTime * expandSpeed);
            }
            else
            {
                transform.localScale = targetScale; // 목표 크기에 도달하면 팽창 완료
                isExpanding = false; // 팽창 중단
            }
        }
    
        private void OnCollisionEnter2D(Collision2D collision)
        {
            if (!isExpanding)
            {
                bGMControl.SoundEffectPlay(0);
            }
            if (!collision.collider.isTrigger && isExpanding)
            {
                isExpanding = false; // 팽창 중단
                transform.localScale = transform.localScale; // 현재 크기에서 멈춤
                DestroyRigidbody(); // Rigidbody 제거
            }
    
            if ((collision.collider.tag == "P1ball" || collision.collider.tag == "P2ball") && rb == null)
            {
                TakeDamage(1);
                textMesh.text = durability.ToString();
            }
        }
    
        void TakeDamage(int damage)
        {
            durability -= damage;
            if (durability <= 0)
            {
                Destroy(gameObject);
            }
        }
    
        void DestroyRigidbody()
        {
            if (rb != null)
            {
                Destroy(rb);
                rb = null;
            }
        }
    }

     

    그래서 코드도 싹 고쳐주고 다시 달아주었다

     

    더보기

    1. Build Settings 열기

    • File > Build Settings 메뉴로 이동합니다.
    • 또는 단축키 Ctrl + Shift + B (Cmd + Shift + B on macOS)를 사용하여 Build Settings 창을 엽니다.

    2. 플랫폼 선택

    • Build Settings 창에서 플랫폼을 선택합니다. (예: Android, iOS)
    • Switch Platform 버튼을 눌러 선택한 플랫폼으로 전환합니다.

    3. Development Build 옵션 비활성화

    • Build Settings 창에서 Development Build 체크박스를 비활성화합니다.
      • 이 옵션을 끄면:
        • Debug.Log 호출이 제거됩니다 (특히 DEBUG_MODE와 같은 조건부 컴파일을 사용하는 경우).
        • 디버깅 기능이 제거되어 성능이 최적화됩니다.

    4. Player Settings 조정 (최적화)

    • Player Settings 버튼을 클릭하여 추가적인 빌드 최적화를 할 수 있습니다.
    • Configuration 섹션에서:
      • Scripting Backend: IL2CPP를 선택하는 것이 더 좋은 성능을 제공합니다.
      • Managed Stripping Level: Low, Medium, 또는 High를 선택하여 불필요한 코드를 제거합니다. 일반적으로 Medium이 적합합니다.
      • Strip Engine Code: 체크하면 Unity 엔진의 사용되지 않는 코드를 제거합니다.
    • Other Settings 섹션에서:
      • Optimization: Enable Incremental GC를 활성화하여 더 효율적인 메모리 관리를 할 수 있습니다.

    5. Proguard 및 IL2CPP (Android 전용)

    • Android에서는 IL2CPP 백엔드를 사용하는 것이 더 좋습니다.
    • Proguard 옵션을 활성화하면 코드 난독화 및 최적화가 추가로 이루어집니다:
      • Player Settings > Publishing Settings > Minify 옵션에서 Release를 Proguard로 설정합니다.

    6. Release 빌드 시작

    • Build 또는 Build and Run 버튼을 클릭하여 빌드를 시작합니다.
      • Build는 APK나 iOS 프로젝트 파일을 생성합니다.
      • Build and Run은 생성된 빌드를 직접 모바일 기기에 설치하고 실행합니다.
Designed by Tistory.