절대 평평하지 않게
Coddy의 Unity 게임: 벽돌깨기 코스 레슨. 16개 중 10번째.
공이 거의 옆으로 날아갈 수도 있습니다. 벽돌 모서리에 맞고 튀거나 다른 공에 밀리면 공이 거의 수평으로 이동하며, 아래로 내려오지 않은 채 경기장을 계속 가로지를 수 있습니다. 공이 내려오기만 기다리는 동안 게임은 멈춥니다. 해결 방법은 속도 보정에 있습니다. 방향 벡터의 길이를 1로 만든 다음, y 성분이 너무 작으면 y를 최솟값으로 설정하고 다시 정규화하면 됩니다.
두 가지 Mathf 메서드가 이 작업을 수행합니다. Mathf.Abs는 부호를 제외한 숫자의 크기를 반환하므로, 한 번의 검사로 위로 가는 공과 아래로 가는 공을 모두 처리할 수 있습니다. Mathf.Sign은 음수이면 -1을, 그렇지 않으면 1을 반환하므로 새 y 값은 공의 진행 방향을 유지합니다. 아래로 가는 공은 계속 아래로 갑니다.
float drift = -0.12f;
Debug.Log(Mathf.Abs(drift)); // 0.12
Debug.Log(Mathf.Sign(drift)); // -1최솟값을 0.3으로 하고 방향 벡터를 (0.99, -0.12, 0)으로 두어 살펴보겠습니다. y의 크기인 0.12는 0.3보다 작으므로 y는 -0.3이 되고, (0.99, -0.3, 0)을 정규화하면 약 (0.96, -0.29, 0)이 됩니다. 여전히 오른쪽 아래로 이동하지만, 이제 충분히 가파르게 움직여 되돌아옵니다. 정규화하면 y가 다시 최솟값보다 약간 작아지고, 다음 단계에서 이를 조금 보정하므로 계속 0.3보다 약간 작게 유지됩니다. 더 가파른 방향은 그대로 둡니다.
챌린지
중급Ball에public float minVertical = 0.3f를 추가하세요.FixedUpdate()에서 방향을 구하세요. 속도를 정규화한 값입니다. y의 크기가minVertical보다 작으면 y의 부호를 유지하면서 y를minVertical로 설정하고, 방향을 다시 정규화하세요.- 그런 다음 이전과 같이 속도를 방향에
speed를 곱한 값으로 설정하세요.
Play를 누른 다음 Check를 누르세요.
직접 해보기
using UnityEngine;
using UnityEngine.InputSystem;
public class Ball : MonoBehaviour
{
public Transform paddle;
public float speed = 9f;
Rigidbody rb;
bool launched;
void Awake()
{
rb = GetComponent<Rigidbody>();
PhysicsMaterial bouncy = new PhysicsMaterial("Bouncy");
bouncy.bounciness = 1f;
bouncy.dynamicFriction = 0f;
bouncy.staticFriction = 0f;
bouncy.bounceCombine = PhysicsMaterialCombine.Maximum;
bouncy.frictionCombine = PhysicsMaterialCombine.Minimum;
GetComponent<Collider>().material = bouncy;
}
void Update()
{
if (launched) return;
transform.position = paddle.position + Vector3.up * 0.5f;
if (Keyboard.current.spaceKey.wasPressedThisFrame) Launch(new Vector3(0.3f, 1f, 0f));
}
public void Launch(Vector3 direction)
{
launched = true;
rb.linearVelocity = direction.normalized * speed;
}
public void ResetToPaddle()
{
launched = false;
rb.linearVelocity = Vector3.zero;
}
void FixedUpdate()
{
if (!launched) return;
rb.linearVelocity = rb.linearVelocity.normalized * speed;
}
void OnCollisionEnter(Collision collision)
{
if (!collision.gameObject.CompareTag("Paddle")) return;
float offset = transform.position.x - collision.transform.position.x;
float halfWidth = collision.collider.bounds.size.x / 2f;
float x = Mathf.Clamp(offset / halfWidth, -1f, 1f);
rb.linearVelocity = new Vector3(x, 1f, 0f).normalized * speed;
}
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("DeathZone")) GameManager.Instance.BallLost(this);
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.