Menu
CoddyTech

Не стоим на месте

Урок 10 из 16 курса Игра в Unity: арканоид на Coddy.

Мяч может полететь почти горизонтально: отскок от угла кирпича или толчок другого мяча может направить его почти параллельно земле, и он будет снова и снова пересекать поле, не опускаясь. Игра замирает, пока игрок ждёт, когда мяч опустится. Исправление нужно внести в исправление скорости: после того как направление сделано длиной в 1 единицу, если его составляющая y слишком мала, задайте для y минимальное значение и снова нормализуйте направление.

Для этого нужны два метода Mathf. Mathf.Abs возвращает модуль числа без учёта его знака, поэтому одной проверкой можно охватить мячи, летящие вверх и вниз. Mathf.Sign возвращает -1 для отрицательного числа и 1 в остальных случаях, поэтому новое значение y сохраняет направление движения мяча: летящий вниз мяч по-прежнему летит вниз.

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

Проверим это на примере с минимальным значением 0.3 и направлением (0.99, -0.12, 0). Модуль y, равный 0.12, меньше 0.3, поэтому y становится равным -0.3, а нормализованное направление (0.99, -0.3, 0) составляет примерно (0.96, -0.29, 0): мяч по-прежнему летит вправо и вниз, но теперь под достаточно крутым углом, чтобы вернуться. После нормализации значение y снова становится чуть меньше минимального, и на следующем шаге оно увеличивается до нужного значения, поэтому остаётся немного меньше 0.3. Более крутые направления не меняются.

challenge icon

Задание

Средне
  1. Добавь public float minVertical = 0.3f в Ball.
  2. В FixedUpdate() получи направление: нормализуй скорость. Если абсолютное значение y меньше minVertical, установи y равным minVertical со знаком y и снова нормализуй направление.
  3. Затем, как и прежде, установи скорость равной направлению, умноженному на speed.

Нажми Play, затем Check.

Попробуйте сами

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 iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Игра в Unity: арканоид