Nunca plano
Lección 10 de 16 del curso Juego en Unity: Rompebloques de Coddy.
Una pelota puede acabar volando casi de lado: un rebote en la esquina de un ladrillo o un empujón de otra pelota pueden dejarla casi horizontal, cruzando el campo una y otra vez sin bajar. El juego se atasca mientras el jugador espera a que baje. La solución va en la corrección de velocidad: después de hacer que la dirección mida 1 unidad, si su componente y es demasiado pequeña, establece y en un mínimo y vuelve a normalizar.
Dos métodos de Mathf hacen el trabajo. Mathf.Abs da el valor de un número sin su signo, así que una prueba detecta tanto las pelotas que suben como las que bajan. Mathf.Sign da -1 para un número negativo y 1 en los demás casos, así que la nueva y mantiene el sentido de la pelota: una pelota que baja sigue bajando.
float drift = -0.12f;
Debug.Log(Mathf.Abs(drift)); // 0.12
Debug.Log(Mathf.Sign(drift)); // -1Haz el cálculo con un mínimo de 0.3 y la dirección (0.99, -0.12, 0). El valor absoluto de y, 0.12, es menor que 0.3, así que y pasa a ser -0.3, y (0.99, -0.3, 0) normalizado es aproximadamente (0.96, -0.29, 0): sigue yendo a la derecha y hacia abajo, ahora con la inclinación suficiente para regresar. Al normalizar, y vuelve a quedar un poco por debajo del mínimo, y el siguiente paso lo eleva, así que se mantiene un poco por debajo de 0.3. Las direcciones más inclinadas no cambian.
Desafío
Intermedio- Añade
public float minVertical = 0.3faBall. - En
FixedUpdate(), toma la dirección: la velocidad normalizada. Si el valor absoluto de su componente y es menor queminVertical, establece y enminVerticalcon el signo de y y vuelve a normalizar la dirección. - Después, establece la velocidad como la dirección multiplicada por
speed, como antes.
Pulsa Play y después Check.
Pruébalo tú mismo
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);
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.