Pull to refresh

Как работают векторы. Баскетбол на Unity 3D

Reading time5 min
Views5.7K

Учебные материалы для школы программирования. Часть 16

Предыдущие уроки можно найти здесь:

В этой статье, мы обратим свой взор в прошлое, и вспомним, с чего начиналась детская школа программирования Step to Science. Первоначальная идея проекта состояла в том, чтобы быть не просто кружком технического творчества, а стать для детей ответом на вопрос, "зачем учиться в школе?"

К чему нам физика, алгебра и геометрия, если мы не планируем проектировать космические корабли, если для счета у нас есть калькулятор в телефоне, расплачиваемся мы чаще картой, так что даже сдачу в уме считать не надо.
Я тоже в детстве вела такие рассуждения, и у родителей не было иных способов донести до меня истину, кроме фразы "нет слова не хочу, есть слово надо" и ремня, который без лишней полемики мотивировал садиться за уроки.

С возрастом, перейдя на другую сторону баррикад, я поняла что хочу ребятам объяснить, показать, доказать, что учиться в школе действительно важно! И игровой проект, который мы разберем сегодня - один из цикла занятий по изучению школьных предметов через игры на Unity 3D.

Кроссплатформенный движок Unity дает огромные возможности учителю: через увлекательный процесс создания игр мы изучаем законы физики, геометрии, делаем расчеты, проектируем окружение, используем сторителлинг, сценарные механики. И конечно-же программируем. Вариантов интеграций Unity в другие образовательные и предметные области - бесчисленное множество!

Порядок выполнения

На примере создания 2D игры «баскетбол», рассмотрим векторы (скорости, сил, локальной и глобальной систем координат). Разберем принципы представления систем координат и представления векторов. Также будет затронута работа с LineRenderer и многокамерность.

Поехали!

Создадим новый проект и импортируем в него приложенный ассет.
Ассет содержит в себе все ресурсы, необходимые для создания полноценного 2D приложения.

Для начала создадим небольшую сцену, в качестве фона выберем спрайт «спортзал» и установим на него сетку. Обратите внимание, что необходимо выставить коллайдеры для щита и корзины.

Конечно, необходимо выставить правильный Order in layer у спрайтов. Добавим мяч, применим к нему Circle collider и Rigidbody.

Внутри мяча должен находиться пустой объект с Audio Source, настроенным на воспроизведение звука удара.

Чтобы воспроизводить этот звук, напишем простой скрипт, закинем его на мяч и сконфигурируем.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ball : MonoBehaviour {
    public AudioSource hitSound;
    public Rigidbody2D rig;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void FixedUpdate() {

    }

    private void OnCollisionEnter2D(Collision2D other) {
        if (other.relativeVelocity.magnitude > 1f) {
            hitSound.Play();
            hitSound.volume = Mathf.Clamp01(other.relativeVelocity.magnitude / 10);
            rig.velocity *= 0.8f;
        }
    }
}

В скрипте нет автопоиска Rigidbody, так что придётся закинуть его руками. Если нажать на Play, наш мяч упадёт, издавая звуки. Чтобы мяч отскакивал, создадим физический материал и закинем его на коллайдер мяча.

Теперь подумаем о том, чтобы мяч показывал своё направление. Для этого создадим скрипт, который рисует стрелки: нам понадобятся два пустых объекта с LineRenderer, один в другом.

Создадим материал для стрелки:

И добавим скрипт, который будет выставлять вершины LineRenderer'ов, делая из них стрелки:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Arrow : MonoBehaviour {
   public Vector3 showVector;
    public LineRenderer lrenderer1;
    public LineRenderer lrenderer2;
    Transform myTransform;

    // Use this for initialization
    void Start () {
        //lrenderer1 = GetComponent<LineRenderer>();
        myTransform = transform;
    }

   // Update is called once per frame
    void Update () {
        showVector = new Vector3(showVector.x, showVector.y, 0f);

        lrenderer1.SetPosition(0, myTransform.position);
        lrenderer1.SetPosition(1, myTransform.position + showVector);
  
        if (showVector.magnitude >= 2f) { // длинная стрелка
            lrenderer2.SetPosition(0, myTransform.position + showVector - showVector.normalized);
        } else {
            lrenderer2.SetPosition(0, myTransform.position + showVector * 0.5f);
        }
        lrenderer2.SetPosition(1, myTransform.position + showVector);

        if (showVector.magnitude < 0.1f) {
            lrenderer1.enabled = lrenderer2.enabled = false;
        } else {
            lrenderer1.enabled = lrenderer2.enabled = true;
        }
    }
}

Закинем скрипт на объект-родитель стрелки и настроим его.

Теперь надо написать скрипт, который будет вектор скорости передавать в наш скрипт "показывания" стрелки. Он очень простой:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class VectorVelocity : MonoBehaviour {
    public Rigidbody2D rig;
    public Arrow arrow;

    // Use this for initialization
    void Start () {
 
    }

    // Update is called once per frame
    void Update () {
        if (rig.bodyType == RigidbodyType2D.Dynamic) {
            arrow.showVector =  rig.velocity / 5f;
        }
    }
}

Закинем его на мяч, в скрипте укажем риджибади мяча и объект со скриптом стрелки.

Теперь вектор скорости показывается верно. Вектор скорости уменьшен в 15 раз, чтобы его было хорошо видно. А для того, чтобы было видно траекторию мяча - добавим ему Trail Renderer на любой привязанный к мячу объект.

Теперь сделаем так, чтобы мяч можно было кидать. Для этого необходимо выставить ему тип Rigidbody как Kinematic и написать небольшой скрипт.

Листинг скрипта:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class Spawner : MonoBehaviour {

    public Rigidbody2D ball;
    public TrailRenderer tr;

    Quaternion oldRotation;
    Vector3 oldPosition;

    public bool readyToShoot = true;

    // Use this for initialization
    void Start () {
        oldPosition = ball.transform.position;
        oldRotation = ball.transform.rotation;
    }

    // Update is called once per frame
    public void Respawn () {
        ball.transform.position = oldPosition;
        ball.transform.rotation = oldRotation;

        ball.velocity = Vector3.zero;
        ball.angularVelocity = 0;
        ball.bodyType = RigidbodyType2D.Kinematic;

        readyToShoot = true;
        tr.Clear();
    }

    public void Shoot(Vector3 speed) {
        if (!readyToShoot) {
            return;
        }

        ball.bodyType = RigidbodyType2D.Dynamic;
        ball.velocity = speed;
        readyToShoot = false;
    }
}

Скрипт выкладываем на пустой объект в мире и устанавливаем ему наш мяч в качестве риджитбади и его трейл.

Этот скрипт сам по себе ничего не делает. Чтобы он работал, необходимо организовать ввод. Создадим UI -> Panel на сцене, выставим панели нулевую альфу и установим на него скрипт TouchPanel.cs , приложенный в проект.

Внутри панели должен лежать спрайт со следующими параметрами (обратите внимание на привязку):

Для того, чтобы при компиляции не возникало ошибок из-за отсутствия класса спавнера, данный скрипт приложен отдельным ассетом, и импортировать его можно только после создания спавнера.

Для того, чтобы сделать включение/выключение стрелок, используется скрипт Toggle, который реализован через эвент-систему юнити. Его необходимо закинуть на кнопку и сконфигурировать следующим образом.

Готово!

P.S. Делитесь ссылкой на статью с коллегами, друзьями и любопытными учениками. Будет здорово, если вы попробуете провести один из уроков в своей школе или в кружке детского технического творчества, и напишите пару слов обратной связи о том, как прошел урок по Unity 3D. Успехов!

Only registered users can participate in poll. Log in, please.
Понравилась статья? Выкладывать еще?
84.62% Да!11
15.38% Нет :(2
13 users voted. 2 users abstained.
Tags:
Hubs:
Total votes 6: ↑6 and ↓0+6
Comments1

Articles