Menu
CoddyTech

Nigdy na płasko

Lekcja 10 z 16 w kursie Gra w Unity: Zbijanie klocków w Coddy.

Piłka może zacząć lecieć niemal poziomo: odbicie od rogu cegły lub popchnięcie przez inną piłkę może sprawić, że jej tor będzie prawie równoległy do ziemi, przez co będzie wielokrotnie przelatywać przez boisko, nie opadając. Gra zatrzymuje się, gdy gracz czeka, aż piłka opadnie. Rozwiązaniem jest poprawka prędkości: po ustawieniu długości kierunku na 1, jeśli jego składowa y jest zbyt mała, ustaw y na wartość minimalną i ponownie znormalizuj kierunek.

Dwie metody Mathf wykonują tę pracę. Mathf.Abs zwraca wartość liczby bez uwzględniania jej znaku, więc jeden warunek 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 nowa wartość y zachowuje kierunek piłki: piłka lecąca w dół nadal leci w dół.

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

Prześledź to dla wartości minimalnej 0.3 i kierunku (0.99, -0.12, 0). Wartość bezwzględna y, czyli 0.12, jest mniejsza niż 0.3, więc y zmienia się na -0.3, a znormalizowany wektor (0.99, -0.3, 0) ma w przybliżeniu postać (0.96, -0.29, 0): piłka nadal leci w prawo i w dół, teraz pod wystarczająco stromym kątem, by wrócić. Normalizacja ponownie sprowadza y nieco poniżej wartości minimalnej, a następny krok ją podnosi, więc pozostaje ona nieco poniżej 0.3. Bardziej strome kierunki pozostają bez zmian.

challenge icon

Wyzwanie

Średni
  1. Dodaj public float minVertical = 0.3f do Ball.
  2. W FixedUpdate() pobierz kierunek: prędkość po normalizacji. Jeśli wartość bezwzględna jego składowej y jest mniejsza niż minVertical, ustaw y na minVertical ze znakiem y, a następnie ponownie znormalizuj kierunek.
  3. Następnie ustaw prędkość na kierunek pomnożony przez speed, tak jak wcześniej.

Naciśnij Play, a następnie Check.

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);
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Gra w Unity: Zbijanie klocków