Menu
CoddyTech

Nunca estático

Lição 10 de 16 do curso Jogo no Unity: Quebra-Tijolos da Coddy.

Uma bola pode acabar voando quase de lado: um quique no canto de um tijolo ou um empurrão de outra bola pode deixá-la quase na horizontal, cruzando o campo várias vezes sem descer. O jogo fica parado enquanto o jogador espera que ela desça. A correção deve ser feita no ajuste da velocidade: depois de deixar a direção com comprimento de 1 unidade, se a parte y for muito pequena, defina y como um valor mínimo e normalize novamente.

Dois métodos Mathf fazem o trabalho. Mathf.Abs fornece o valor de um número sem o sinal, então um único teste detecta bolas subindo e bolas descendo. Mathf.Sign fornece -1 para um número negativo e 1 caso contrário, então o novo y mantém a trajetória da bola: uma bola que está descendo continua descendo.

float drift = -0.12f;
Debug.Log(Mathf.Abs(drift));    // 0.12
Debug.Log(Mathf.Sign(drift));   // -1

Faça o cálculo usando um mínimo de 0.3 e a direção (0.99, -0.12, 0). O valor absoluto de y, 0.12, é menor que 0.3, então y passa a ser -0.3, e (0.99, -0.3, 0) normalizado é aproximadamente (0.96, -0.29, 0): continua indo para a direita e para baixo, agora com inclinação suficiente para voltar. A normalização deixa y um pouco abaixo do mínimo novamente, e a etapa seguinte o aumenta, então ele permanece um pouco abaixo de 0.3. Direções mais inclinadas não são alteradas.

challenge icon

Desafio

Médio
  1. Adicione public float minVertical = 0.3f a Ball.
  2. Em FixedUpdate(), obtenha a direção: a velocidade normalizada. Se o valor absoluto de y for menor que minVertical, defina y como minVertical com o sinal de y e normalize a direção novamente.
  3. Em seguida, defina a velocidade como a direção multiplicada por speed, como antes.

Pressione Play e, em seguida, Check.

Experimente você mesmo

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);
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Jogo no Unity: Quebra-Tijolos