-
최적화 - 9Galaxy Ball/5. 최적화 2024. 10. 9. 17:28
자 그 다음으로 할 것은 이제 인게임속 공이 아닌 스테이지 선택창에 위치한 StageBall이다
이 공의 특징은 넓은 맵을 돌아다니며 플레이어가 원하는 스테이지를 선택하는 역할을 수행한다
그리고 물론 이 StageBall도 최적화를 하여 부드럽게 움직이도록 구현해보겠다
public class StageBallController : MonoBehaviour { Rigidbody2D rb; Vector2 lastVelocity; float deceleration = 2f; public GameObject StageStart; private StageGameManager stageGameManager; private StageBallManager stageBallManager; private bool hasbeenout = false; public static int chooseStage; StageGameManager gameManager = FindAnyObjectByType<StageGameManager>(); private void Update() { if (!stageBallManager.isDragging) { Debug.Log("StageBallController에서 클릭 뗀 것을 인지"); rb.velocity = StageBallManager.shotDirection * StageBallManager.shotDistance; // GameManager에서 값 가져와서 구체 발사 stageBallManager.isDragging = true; } Move(); } void Move() { lastVelocity = rb.velocity; rb.velocity -= rb.velocity.normalized * deceleration * Time.deltaTime; } private void OnCollisionEnter2D(Collision2D coll) { if (coll.contacts != null && coll.contacts.Length > 0) { Vector2 dir = Vector2.Reflect(lastVelocity.normalized, coll.contacts[0].normal); if (rb != null) rb.velocity = dir * Mathf.Max(lastVelocity.magnitude, 0f); // 감속하지 않고 반사만 진행 } } }
StageBall을 움직이는 스크립트이다. 물론 코드를 통째로 가져온건 아니고,
움직임에 관한 코드만 잘라서 가져왔다. 이 부분을 수정해주면 된다
using System.Collections; using Unity.VisualScripting; using UnityEngine; public class StageBallController : MonoBehaviour { private float dragAmount = 1.1f; bool hasBeenLaunched = false; bool isStopped = false; // 공이 완전히 멈췄는지 여부 private float decelerationThreshold = 0.4f; public PhysicsMaterial2D bouncyMaterial; private void Start() { rb.drag = 0f; Collider2D collider = GetComponent<Collider2D>(); if (collider != null && bouncyMaterial != null) { collider.sharedMaterial = bouncyMaterial; } } private void Update() { if (!stageBallManager.isDragging) { LaunchBall(); } if (hasBeenLaunched && !isStopped) { SlowDownBall(); } } void LaunchBall() { Vector2 launchForce = StageBallManager.shotDirection * (StageBallManager.shotDistance * 1.4f); rb.AddForce(launchForce, ForceMode2D.Impulse); stageBallManager.isDragging = true; rb.drag = dragAmount; hasBeenLaunched = true; } void SlowDownBall() { if (rb == null) return; if (rb.velocity.magnitude <= decelerationThreshold) { rb.velocity = Vector2.zero; isStopped = true; } } }
수정한 부분들만 적어보았다. 사실 적 총알에 비하면 훨씬 간단했다
팽창도 하지않고, 고정도 하지 않고 정말 이동하는 로직만 바꿔주면 됐기에 어려울게 없었다
녹화한 동영상에서는 큰 차이가 없지만 실제로는 확실히 더 부드럽게 움직이는것을 확인할 수 있다
그럼 이번엔 스테이지에 플레이어와 똑같이 돌아다니는 다른 구체들의 움직임도 최적화를 해보겠다
using UnityEngine; public class ContinuousRandomMovement : MonoBehaviour { private Vector2 moveDirection; // 이동 방향 void Start() { gameObject.transform.position = new Vector2(Random.Range(-199, 199), Random.Range(-190, 190)); float randomAngle = Random.Range(0f, 360f); moveDirection = new Vector2(Mathf.Cos(randomAngle * Mathf.Deg2Rad), Mathf.Sin(randomAngle * Mathf.Deg2Rad)); moveDirection.Normalize(); } void Update() { transform.Translate(moveDirection * Random.Range(2, 17) * Time.deltaTime); } private void OnTriggerStay2D(Collider2D collision) { StageGameManager gameManager = FindObjectOfType<StageGameManager>(); switch (collision.gameObject.name) { case "Bottom": if (gameManager.StageClearID < 7) { transform.Translate(0, 210, 0); } transform.Translate(0, 170, 0); break; case "Top": if (gameManager.StageClearID < 7) { transform.Translate(0, -210, 0); } transform.Translate(0, -170, 0); break; case "Left": if (gameManager.StageClearID < 7) { transform.Translate(200, 0, 0); } transform.Translate(165, 0, 0); break; case "Right": if (gameManager.StageClearID < 7) { transform.Translate(-200, 0, 0); } transform.Translate(-165, 0, 0); break; } } }
얘네들은 직접 컨트롤 하지도 않고, 잠깐 등장하다 마는 용도이기 때문에 훨씬 더 간단하게 구현된다
하지만 이것도 역시 실제 폰으로 실행했을땐 뚝뚝 끊겼다는 사실... 그렇기에 최적화를 피해갈수 없다
사실 이건 여태 해온 방식대로 코드를 갈아엎는것도 과한것 같으니 방식을 조금 변경해주기로 했다
using UnityEngine; public class ContinuousRandomMovement : MonoBehaviour { private Vector2 moveDirection; private StageGameManager gameManager; private Rigidbody2D rb; public float moveSpeed; public PhysicsMaterial2D bouncyMaterial; void Start() { rb = GetComponent<Rigidbody2D>(); gameManager = FindAnyObjectByType<StageGameManager>(); gameObject.transform.position = new Vector2(Random.Range(-199, 199), Random.Range(-190, 190)); float randomAngle = Random.Range(0f, 360f); moveDirection = new Vector2(Mathf.Cos(randomAngle * Mathf.Deg2Rad), Mathf.Sin(randomAngle * Mathf.Deg2Rad)); moveDirection.Normalize(); // 방향 벡터를 정규화 moveSpeed = Random.Range(2, 17); Collider2D collider = GetComponent<Collider2D>(); if (collider != null && bouncyMaterial != null) { collider.sharedMaterial = bouncyMaterial; } } void FixedUpdate() { rb.velocity = moveDirection * moveSpeed; } }
최종 수정된 코드이다. 이번에도 수정한 부분만 적어보았다
- Rigidbody2D를 사용: transform.Translate 대신 rb.velocity를 사용하여 이동 처리.
- FixedUpdate()에서 이동 처리: 물리 이동을 FixedUpdate()에서 처리해 물리 계산의 정확도를 높임.
- 불필요한 연산 제거: moveSpeed와 같은 값을 Start()에서 한 번만 계산하도록 수정.
- OnTriggerEnter2D 사용: 충돌이 일어날 때 한 번만 위치를 재조정하도록 최적화.
총 4가지를 개선하였고, 여기에 추가로 공끼리 부딫혔을때 자연스럽게 팅기도록 바운스 메터리얼도 넣어주었다
최적화에서 가장 치명적인게 update 메서드안에 많은 양의 코드를 넣는것과 Rigidbody의 기능을
남발하는 것이다. 웬만하면 update 대신 Start 메서드 안에 한번에 몰아넣는게 좋은 방법이다
그리고 Tag 비교 연산과 OnTriggerEnter, 혹은 OnColliderEnter 메서드 안에도 최대한 코드의 양을 줄여
다만 메터리얼이 적용될 공 사이즈가 인게임에 비하면 훨씬 더 크기 때문에 새로운 메터리얼을 만들어
수치를 다시 재조정한뒤 새롭게 부착해주었다
서로 자연스럽게 움직이며 충돌시 마치 탱탱볼이 부딪히듯 팅겨져 나가는것을 볼 수 있다
'Galaxy Ball > 5. 최적화' 카테고리의 다른 글
최적화 - 11 (설정수정★) (1) 2024.10.17 최적화 - 10 (설정 수정★) (0) 2024.10.09 최적화 - 8 (1) 2024.10.01 최적화 - 7 (0) 2024.09.25 최적화 - 6 (1) 2024.09.24