Menu
CoddyTech

Mai piatto

Lezione 10 di 19 del corso Gioco in Unity: Rompi i mattoni di Coddy.

Un rimbalzo sull’angolo di un mattone può lasciare la palla quasi orizzontale, mentre attraversa il campo ancora e ancora e il giocatore aspetta. La soluzione si applica alla correzione della velocità: se la componente y della direzione è troppo piccola, impostala a un valore minimo e normalizza di nuovo.

Mathf.Abs restituisce il valore assoluto di un numero, senza il segno, quindi un solo controllo intercetta le palle che vanno verso l’alto e verso il basso. Mathf.Sign restituisce -1 per un numero negativo e 1 altrimenti, quindi una palla che scende continua a scendere.

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

Con un valore minimo di 0.4, alla direzione (0.99, -0.12, 0) viene assegnato y -0.4 e, dopo la normalizzazione, si ottiene circa (0.93, -0.37, 0): ancora verso destra e verso il basso, ma ora abbastanza inclinata da tornare indietro. Le direzioni più inclinate restano invariate.

challenge icon

Sfida

Medio

Impedisci alla pallina di attraversare il campo quasi in orizzontale.

  1. In Ball, aggiungi public float minVertical = 0.3f;
  2. In FixedUpdate, prendi Vector3 direction = rb.linearVelocity.normalized;. Se Mathf.Abs(direction.y) < minVertical, imposta direction.y = Mathf.Sign(direction.y) * minVertical; e normalizza di nuovo.
  3. Imposta rb.linearVelocity = direction * speed;

Premi «Gioca»: la pallina non attraversa mai il campo in orizzontale a lungo. Poi premi «Verifica».

Provalo tu

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);
    }
}

Tutte le lezioni di Gioco in Unity: Rompi i mattoni

Esercitati da solo: Playground Unity