Menu
CoddyTech

Mai piatto

Lezione 10 di 16 del corso Gioco Unity: Rompi-mattoni di Coddy.

Una pallina può finire per volare quasi di lato: un rimbalzo sull'angolo di un mattone o una spinta di un'altra pallina possono lasciarla quasi orizzontale, mentre attraversa il campo avanti e indietro senza scendere. Il gioco si blocca mentre il giocatore aspetta che scenda. La soluzione va applicata alla correzione della velocità: dopo aver reso la direzione lunga 1 unità, se la sua componente y è troppo piccola, imposta y a un minimo e normalizza di nuovo.

Due metodi Mathf fanno il lavoro. Mathf.Abs restituisce il valore assoluto di un numero, senza il suo segno, quindi un solo controllo intercetta le palline che salgono e quelle che scendono. Mathf.Sign restituisce -1 per un numero negativo e 1 altrimenti, quindi la nuova y mantiene il verso della pallina: una pallina che scende continua a scendere.

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

Considera un minimo di 0.3 e la direzione (0.99, -0.12, 0). Il valore assoluto di y, 0.12, è inferiore a 0.3, quindi y diventa -0.3 e la direzione (0.99, -0.3, 0) normalizzata è circa (0.96, -0.29, 0): va ancora verso destra e verso il basso, ora con un'inclinazione sufficiente per tornare indietro. La normalizzazione porta di nuovo y leggermente sotto il minimo e il passaggio successivo la riporta al valore minimo, così resta poco sotto 0.3. Le direzioni più inclinate non vengono modificate.

challenge icon

Sfida

Medio
  1. Aggiungi public float minVertical = 0.3f a Ball.
  2. In FixedUpdate(), ricava la direzione dalla velocità e normalizzala. Se il valore assoluto della sua componente y è inferiore a minVertical, imposta y a minVertical mantenendo il segno di y e normalizza di nuovo la direzione.
  3. Poi imposta la velocità alla direzione moltiplicata per speed, come prima.

Premi Play, poi Check.

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);
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Gioco Unity: Rompi-mattoni