Учебные материалы для школы программирования. Часть 16
Предыдущие уроки можно найти здесь:В этой статье, мы обратим свой взор в прошлое, и вспомним, с чего начиналась детская школа программирования Step to Science. Первоначальная идея проекта состояла в том, чтобы быть не просто кружком технического творчества, а стать для детей ответом на вопрос, "зачем учиться в школе?"
К чему нам физика, алгебра и геометрия, если мы не планируем проектировать космические корабли, если для счета у нас есть калькулятор в телефоне, расплачиваемся мы чаще картой, так что даже сдачу в уме считать не надо.
Я тоже в детстве вела такие рассуждения, и у родителей не было иных способов донести до меня истину, кроме фразы "нет слова не хочу, есть слово надо" и ремня, который без лишней полемики мотивировал садиться за уроки.
С возрастом, перейдя на другую сторону баррикад, я поняла что хочу ребятам объяснить, показать, доказать, что учиться в школе действительно важно! И игровой проект, который мы разберем сегодня - один из цикла занятий по изучению школьных предметов через игры на Unity 3D.
Кроссплатформенный движок Unity дает огромные возможности учителю: через увлекательный процесс создания игр мы изучаем законы физики, геометрии, делаем расчеты, проектируем окружение, используем сторителлинг, сценарные механики. И конечно-же программируем. Вариантов интеграций Unity в другие образовательные и предметные области - бесчисленное множество!
Порядок выполнения
На примере создания 2D игры «баскетбол», рассмотрим векторы (скорости, сил, локальной и глобальной систем координат). Разберем принципы представления систем координат и представления векторов. Также будет затронута работа с LineRenderer и многокамерность.Поехали!
Создадим новый проект и импортируем в него приложенный ассет.
Ассет содержит в себе все ресурсы, необходимые для создания полноценного 2D приложения.
Для начала создадим небольшую сцену, в качестве фона выберем спрайт «спортзал» и установим на него сетку. Обратите внимание, что необходимо выставить коллайдеры для щита и корзины.
![c37b4182f8305cc953e3120c9bdc6c79.png](https://habrastorage.org/getpro/habr/upload_files/c37/b41/82f/c37b4182f8305cc953e3120c9bdc6c79.png)
Конечно, необходимо выставить правильный Order in layer у спрайтов. Добавим мяч, применим к нему Circle collider и Rigidbody.
![354d717f8307964edd2d32a80a0647d7.png](https://habrastorage.org/getpro/habr/upload_files/354/d71/7f8/354d717f8307964edd2d32a80a0647d7.png)
![67c3a029e5a5d7c740656850fd2e74a6.png](https://habrastorage.org/getpro/habr/upload_files/67c/3a0/29e/67c3a029e5a5d7c740656850fd2e74a6.png)
Внутри мяча должен находиться пустой объект с Audio Source, настроенным на воспроизведение звука удара.
![1f9c39513fee74aa1547947abb9fd639.png](https://habrastorage.org/getpro/habr/upload_files/1f9/c39/513/1f9c39513fee74aa1547947abb9fd639.png)
![ecfd2883110fc2ca54ff0c3830eef3d3.png](https://habrastorage.org/getpro/habr/upload_files/ecf/d28/831/ecfd2883110fc2ca54ff0c3830eef3d3.png)
Чтобы воспроизводить этот звук, напишем простой скрипт, закинем его на мяч и сконфигурируем.
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, наш мяч упадёт, издавая звуки. Чтобы мяч отскакивал, создадим физический материал и закинем его на коллайдер мяча.
![6932be2f6df1d2cdb587d2e0282bef78.png](https://habrastorage.org/getpro/habr/upload_files/693/2be/2f6/6932be2f6df1d2cdb587d2e0282bef78.png)
Теперь подумаем о том, чтобы мяч показывал своё направление. Для этого создадим скрипт, который рисует стрелки: нам понадобятся два пустых объекта с LineRenderer, один в другом.
![27586a7ece54900b50d557b15293e590.png](https://habrastorage.org/getpro/habr/upload_files/275/86a/7ec/27586a7ece54900b50d557b15293e590.png)
Создадим материал для стрелки:
![b9cc43f269cdc2e2a4bfb4350281ce37.png](https://habrastorage.org/getpro/habr/upload_files/b9c/c43/f26/b9cc43f269cdc2e2a4bfb4350281ce37.png)
И добавим скрипт, который будет выставлять вершины 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;
}
}
}
Закинем скрипт на объект-родитель стрелки и настроим его.
![5a7272244ccea274f18a3ffd0d6be714.png](https://habrastorage.org/getpro/habr/upload_files/5a7/272/244/5a7272244ccea274f18a3ffd0d6be714.png)
![3429e8308d5576a46f498f0302596b38.png](https://habrastorage.org/getpro/habr/upload_files/342/9e8/308/3429e8308d5576a46f498f0302596b38.png)
Теперь надо написать скрипт, который будет вектор скорости передавать в наш скрипт "показывания" стрелки. Он очень простой:
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 на любой привязанный к мячу объект.
![f91bdf9dab761aeae723234e972df905.png](https://habrastorage.org/getpro/habr/upload_files/f91/bdf/9da/f91bdf9dab761aeae723234e972df905.png)
Теперь сделаем так, чтобы мяч можно было кидать. Для этого необходимо выставить ему тип Rigidbody как Kinematic и написать небольшой скрипт.
![eefdd62dc2321b5439befffef6b4275b.png](https://habrastorage.org/getpro/habr/upload_files/eef/dd6/2dc/eefdd62dc2321b5439befffef6b4275b.png)
![01c443d1f6dda0719ff57439f47e2bd8.png](https://habrastorage.org/getpro/habr/upload_files/01c/443/d1f/01c443d1f6dda0719ff57439f47e2bd8.png)
Листинг скрипта:
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 , приложенный в проект.
![86d40b18190ed6dfca9a1de47e31838c.png](https://habrastorage.org/getpro/habr/upload_files/86d/40b/181/86d40b18190ed6dfca9a1de47e31838c.png)
![b4be8ae7206d6b6eed7b57ecaa73fdfb.png](https://habrastorage.org/getpro/habr/upload_files/b4b/e8a/e72/b4be8ae7206d6b6eed7b57ecaa73fdfb.png)
Внутри панели должен лежать спрайт со следующими параметрами (обратите внимание на привязку):
![70c98f5cee1104d0becb67602dd7f057.png](https://habrastorage.org/getpro/habr/upload_files/70c/98f/5ce/70c98f5cee1104d0becb67602dd7f057.png)
![635bf09a0cd5b266ae9cd36496b9e731.png](https://habrastorage.org/getpro/habr/upload_files/635/bf0/9a0/635bf09a0cd5b266ae9cd36496b9e731.png)
Для того, чтобы при компиляции не возникало ошибок из-за отсутствия класса спавнера, данный скрипт приложен отдельным ассетом, и импортировать его можно только после создания спавнера.
Для того, чтобы сделать включение/выключение стрелок, используется скрипт Toggle, который реализован через эвент-систему юнити. Его необходимо закинуть на кнопку и сконфигурировать следующим образом.
![40441d46e0c4dc86e70ab3b856dc1f92.png](https://habrastorage.org/getpro/habr/upload_files/404/41d/46e/40441d46e0c4dc86e70ab3b856dc1f92.png)
![f094f6a7a049d59f9a8273e8cc7bc767.png](https://habrastorage.org/getpro/habr/upload_files/f09/4f6/a7a/f094f6a7a049d59f9a8273e8cc7bc767.png)
Готово!
Источник статьи: https://habr.com/ru/post/553420/