Menu
CoddyTech

Nigdy na płasko

Lekcja 10 z 19 w kursie Gra w Unity: Brick Breaker w Coddy.

Odbicie od narożnika cegiełki może sprawić, że piłka będzie lecieć niemal poziomo, wielokrotnie przemierzając pole, podczas gdy gracz czeka. Rozwiązanie należy wprowadzić w poprawce prędkości: jeśli składowa y kierunku jest zbyt mała, ustaw ją na wartość minimalną i ponownie znormalizuj kierunek.

Mathf.Abs zwraca wartość liczby bez jej znaku, więc jeden test obejmuje piłki lecące w górę i w dół. Mathf.Sign zwraca -1 dla liczby ujemnej, a w pozostałych przypadkach 1, więc piłka lecąca w dół nadal będzie lecieć w dół.

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

Przy wartości minimalnej równej 0.4 kierunek (0.99, -0.12, 0) otrzymuje składową y równą -0.4, a po normalizacji wynosi około (0.93, -0.37, 0): piłka nadal leci w prawo i w dół, ale teraz pod wystarczająco stromym kątem, by wrócić. Bardziej strome kierunki pozostają bez zmian.

challenge icon

Wyzwanie

Średni

Nie pozwól, aby piłka przez dłuższy czas przemieszczała się po boisku niemal poziomo.

  1. W Ball dodaj public float minVertical = 0.3f;
  2. W FixedUpdate pobierz Vector3 direction = rb.linearVelocity.normalized;. Jeśli Mathf.Abs(direction.y) < minVertical, ustaw direction.y = Mathf.Sign(direction.y) * minVertical; i ponownie znormalizuj.
  3. Ustaw rb.linearVelocity = direction * speed;

Naciśnij „Graj”: piłka nie będzie długo przemieszczać się po boisku poziomo. Następnie naciśnij „Sprawdź”.

Spróbuj swoich sił

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

Wszystkie lekcje w sekcji Gra w Unity: Brick Breaker

Poćwicz samodzielnie: Edytor online Unity