Туториал 5: 2Д игра платформер (урок для начинающих). Часть 2.
Введение:
Это вторая часть туториала о 2Д игре платформере. Вам понадобятся некоторые игровые рессурсы для этого туториала. Скачайте .zip архив здесь. Также вы можете скачать первую часть туториала здесь. Запустите юнити проект с первой частью туториала и загрузите сцену scenePlatformer.Как сделать стену:
Начнем с легкого. Импортируйте картинку wall из скаченного архива.Поместите wall в сцену. Будет создан новый объект. Измените его Z-позицию на 0 (если отличается от 0). Добавьте к нему Box Collider 2D.
Теперь о вопросе, о котором обычно спрашивают на форумах. Щапустите сцену, бегите на стену и прыгните, продолжая удерживать бег. Крыса повиснет на стене. Это происходит из-за стандартного значения трения. Тут много различных путей исправить это. Мы просто добавим новый физический материал с 0 трением к стене (или крысе). Создайте новый Physics Material 2D, назовите его noFriction.
Выберите созданный материал noFriction и измените Friction на 0.
Выберите теперь Rat в hierarchy, посмотрите на Inspector и измените Material в Capsule Collider 2D на noFriction.
Крыса теперь не должна залипать на стенах.
Как собирать и подсчитывать монеты:
Добавим что нибудь для собирания игроком. Пусть это будет монета. Импортируйте картинку монеты в проект. Поместите монету в сцену. Будет созлан новый игровой объект. Выберите coin в иерархии и посмотрите на его Inspector. Измените Z-позицию на 0. Измените Order in Layer на -10 (чтобы монета рисовалась позади крысы). Добавьте Circle Collider 2D и включите IsTrigger (нам понадобится триггер для проверки соприкосновений).Добавьте новый тэг Coin и измените тэг монеты на Coin.
Выделите coin в иерархии на смените название на CoinPrefab. Создайте теперь префаб монеты. (просто перетащите CoinPrefab в Assets).
Нам нужен скрипт для сбора монет. Создайте новый C# скрипт (правый клик в Assets и там найдите этот пункт). Назовите его CoinController.
Мы будем использовать функцию OnTriggerEnter2D для проверки соприкосновения крысы и монеты. Скрипт получится такой:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CoinController : MonoBehaviour {
//звук сбора монеты
public AudioClip CoinSound;
//переменная количества собранных монет
public int coin;
//запустится если collider2D попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверка, имеет ли попавший объект тэг Coin
if (other.tag == "Coin") {
//увеличить счетчик монет
coin = coin + 1;
//проиграть звук поднятия монеты на позиции крысы
AudioSource.PlayClipAtPoint (CoinSound, transform.position);
//удалить монету из сцены
Destroy (other.gameObject);
}
}
}
Добавьте этот скрипт к крысе. Импортируйте звук CoinSound в проект. Выберите крысу в иерархии и поместите CoinSound в поле Coin Sound (чейчас мы используем 3Д позиционирование звука и он будет относительно тихим, так как восприятие звука находится на камере. Мы потом переделаем Audio Listener для более правильного звука).using System.Collections.Generic;
using UnityEngine;
public class CoinController : MonoBehaviour {
//звук сбора монеты
public AudioClip CoinSound;
//переменная количества собранных монет
public int coin;
//запустится если collider2D попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверка, имеет ли попавший объект тэг Coin
if (other.tag == "Coin") {
//увеличить счетчик монет
coin = coin + 1;
//проиграть звук поднятия монеты на позиции крысы
AudioSource.PlayClipAtPoint (CoinSound, transform.position);
//удалить монету из сцены
Destroy (other.gameObject);
}
}
}
Теперь сделаем простой интерфейс для отображения количества монет. Добавьте новый UI - Text. Будет созданно три новых объекта: Canvas, Text, EventSystem.
Выделите Canvas в иерархии. Измените UI Scale Mode на Scale With Screen Size и Screen Match Mode на Expand. С этими параметрами будет неплохое скалирование размера интерфейса на разных экранах.
Сцена и интерфейс теперь находятся в одном экране. Сделайте двойной клик на Canvas в иерархии. Камера сфокусируется на белом прямоугольнике. Этот прямоугольние представляет как будет выглядеть экран в игре.
Выберите Text в иерархии. Сделайте его больше и перетащите на то место, где он должен отображаться. Измените привязку на право-вверх. Измените Text на 0. Alignment на середину. Включите Best Fit (заполнение пространства). Измените Max Size на что-то около 100. Настройте Color по желанию.
Нам нужен скрипт для управления текстом. Откройте снова скрипт CoinController.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//эта библиотека нужна для работы с интерфейсом
using UnityEngine.UI;
public class CoinController : MonoBehaviour {
//ссылка на объект с текстом
public GameObject TextObject;
//ссылка на текстовый компонент
Text textComponent;
//звук поднятия монеты
public AudioClip CoinSound;
//переменная подсчета монет
public int coin;
//запустится один раз при запуске скрипта
void Start () {
//делаем линк на текстовый компонент, который находится на текстовом объекте
textComponent = TextObject.GetComponent <Text> ();
}
//запустится если collider2D попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверка, имеет-ли объект тэг Coin
if (other.tag == "Coin") {
//увеличить переменную подсчета монет
coin = coin + 1;
//записать в текст результат счета монет, преобразованный в текстовую переменную
textComponent.text = coin.ToString();
//проиграть звук поднятия монеты на позиции крысы
AudioSource.PlayClipAtPoint (CoinSound, transform.position);
//удалить монету из сцены
Destroy (other.gameObject);
}
}
}
Сфокусируйте камеру назад в сцену (сделайте двойной клик по крысе в иерархии). Выберите Rat в иерархии. У скрипта CoinController пояаилось новое поле Text Object. Поместите объект Text в это поле. Интерфейс теперь должен отображать значение переменной сбора монет. Запустите игру и проверьте это.using System.Collections.Generic;
using UnityEngine;
//эта библиотека нужна для работы с интерфейсом
using UnityEngine.UI;
public class CoinController : MonoBehaviour {
//ссылка на объект с текстом
public GameObject TextObject;
//ссылка на текстовый компонент
Text textComponent;
//звук поднятия монеты
public AudioClip CoinSound;
//переменная подсчета монет
public int coin;
//запустится один раз при запуске скрипта
void Start () {
//делаем линк на текстовый компонент, который находится на текстовом объекте
textComponent = TextObject.GetComponent <Text> ();
}
//запустится если collider2D попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверка, имеет-ли объект тэг Coin
if (other.tag == "Coin") {
//увеличить переменную подсчета монет
coin = coin + 1;
//записать в текст результат счета монет, преобразованный в текстовую переменную
textComponent.text = coin.ToString();
//проиграть звук поднятия монеты на позиции крысы
AudioSource.PlayClipAtPoint (CoinSound, transform.position);
//удалить монету из сцены
Destroy (other.gameObject);
}
}
}
Как сделать яму:
Передвиньте платформу так, что бы крыса могла упасть между ними.Создайте новый empty gameobject.
Выберите созданный GameObject и назовите его DeadEnd. Включите иконку для лучшей видимости. Включите кнопку перемещения и передвиньте DeadEnd на низ ямы. Смените Z-позицию на 0. Добавьте Box Collider 2D. Включите Edit Collider и измените размер на длину ямы (тяните за зеленые точки). Включите Is Trigger.
Нам нужен скрипт для управления DeadEnd. Мы будем проверять, попала-ли крыса в триггер и просто перезагрузим сцену. Создайте новый C# скрипт и назовите его DeadEndController.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//это библиотека для работы со сценами
using UnityEngine.SceneManagement;
public class DeadEndController : MonoBehaviour {
//запустится если 2D collider попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверка, имеет ли объект тэг Player
if (other.tag == "Player") {
//ппосмотреть название текущей сцены и загрузить её (reload)
SceneManager.LoadScene (SceneManager.GetActiveScene().name);
}
}
}
Выберите DeadEnd в иерархии и добавьте этот скрипт. Создайте префаб DeadEnd (перетащите DeadEnd из иерархии в Assets.)using System.Collections.Generic;
using UnityEngine;
//это библиотека для работы со сценами
using UnityEngine.SceneManagement;
public class DeadEndController : MonoBehaviour {
//запустится если 2D collider попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверка, имеет ли объект тэг Player
if (other.tag == "Player") {
//ппосмотреть название текущей сцены и загрузить её (reload)
SceneManager.LoadScene (SceneManager.GetActiveScene().name);
}
}
}
Как сделать простого врага:
Добавьте Ground и DeadEnd префабы в сцену.Импортируйте картинку гриба из скачанного архива в Assets. Перетащите спрайт гриба в сцену на последнюю платформу. Новый игровой объект mushroom будет создан. Назовите его Enemy. Выберите Enemy и посмотрите на его Inspector. Измените Z-позицию на 0. Добавьте Capsule Collider 2D (это будет тело гриба). Нажмите на кнопку Edit Collider и настройте размер коллайдера (смотрите скриншот). Добавьте Box Collider 2D (будет использоваться как триггер для проверки прыгнула-ли крыса на шляпу гриба). Включите Is Trigger. Нажмите на кнопку Edit Collider и настройте размеры коллайдера (смотрите скриншот). Добавьте Rigidbody 2D. Измените Interpolate на Interpolate (для более плавного движения). Включите Freeze Rotation Z (что бы избежать вращения).
Нам нужен скрипт для управления грибом. Логика гриба будет простая. Гриб будет двигаться между двумя точками и исчезнет, если крыса прыгнет ему на шляпу. Создайте новый C# скрипт и назовите его MushroomController.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//библиотека для управления сценами
using UnityEngine.SceneManagement;
public class MushroomController : MonoBehaviour {
//как далеко гриб может отойти от начальной точки
public float distanceToRun;
//скорость движения
public float speed;
//направление взгляда гриба
public bool isLookingLeft = true;
//стартовая позиция
Vector3 startPos;
//линк на компонент Rigidbody2D
Rigidbody2D rb;
//выполнится 1 раз при старте игры
void Start () {
//делаем линк на Rigidbody2D компонент
rb = GetComponent <Rigidbody2D> ();
//запоминаем стартовую точку гриба
startPos = transform.position;
//будем сравнивать квадрат вектора расстояния с квадратом расстояния
//так как извлечение корня медленный процесс
distanceToRun = distanceToRun * distanceToRun;
}
//выполняется на каждом фиксированном интервале
void FixedUpdate () {
//проверить, смотрит-ли гриб влево
if (isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб слева от стартовой точки
//и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x < startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота гриба
TurnTheMushroom ();
//начать движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
//если проверка была негативной
} else {
//продолжить движение влево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
}
}
//проверить, что гриб смотрит вправо
if (!isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб справа от стартовой точки
///и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x > startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота гриба
TurnTheMushroom ();
//начать движение налево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
//если проверка была негативной
} else {
//продолжить движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
}
}
}
//функция поворота гриба
void TurnTheMushroom ()
{
//инвертировать (изменить на противоположный) указатель направления взгляда
isLookingLeft = !isLookingLeft;
//повернуть гриб
transform.localScale = new Vector3 (transform.localScale.x * -1, transform.localScale.y, transform.localScale.z);
}
//запустится, если коллайдер коснулся другого коллайдера
void OnCollisionEnter2D (Collision2D other) {
//проверить, что у коллайдера тэг Player
if (other.collider.gameObject.tag == "Player") {
//посмотреть имя загруженной сцены и загрузить такую сцену (reload)
SceneManager.LoadScene (SceneManager.GetActiveScene().name);
}
}
//запустится, если другой коллайдер попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверить, что у коллайдера тэг Player
if (other.tag == "Player") {
//удалить гриб
Destroy (gameObject);
}
}
}
Теперь добавим эффект взрыва, если гриб был уничтожен. Используем систему частиц для этого. Добавьте Particle System. Переименуте её в Explosion. Измените Z-позицию на 0. Измените все Rotation на 0, Duration на 1, отключите Looping, Start Lifetime на 1.using System.Collections.Generic;
using UnityEngine;
//библиотека для управления сценами
using UnityEngine.SceneManagement;
public class MushroomController : MonoBehaviour {
//как далеко гриб может отойти от начальной точки
public float distanceToRun;
//скорость движения
public float speed;
//направление взгляда гриба
public bool isLookingLeft = true;
//стартовая позиция
Vector3 startPos;
//линк на компонент Rigidbody2D
Rigidbody2D rb;
//выполнится 1 раз при старте игры
void Start () {
//делаем линк на Rigidbody2D компонент
rb = GetComponent <Rigidbody2D> ();
//запоминаем стартовую точку гриба
startPos = transform.position;
//будем сравнивать квадрат вектора расстояния с квадратом расстояния
//так как извлечение корня медленный процесс
distanceToRun = distanceToRun * distanceToRun;
}
//выполняется на каждом фиксированном интервале
void FixedUpdate () {
//проверить, смотрит-ли гриб влево
if (isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб слева от стартовой точки
//и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x < startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота гриба
TurnTheMushroom ();
//начать движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
//если проверка была негативной
} else {
//продолжить движение влево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
}
}
//проверить, что гриб смотрит вправо
if (!isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб справа от стартовой точки
///и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x > startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота гриба
TurnTheMushroom ();
//начать движение налево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
//если проверка была негативной
} else {
//продолжить движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
}
}
}
//функция поворота гриба
void TurnTheMushroom ()
{
//инвертировать (изменить на противоположный) указатель направления взгляда
isLookingLeft = !isLookingLeft;
//повернуть гриб
transform.localScale = new Vector3 (transform.localScale.x * -1, transform.localScale.y, transform.localScale.z);
}
//запустится, если коллайдер коснулся другого коллайдера
void OnCollisionEnter2D (Collision2D other) {
//проверить, что у коллайдера тэг Player
if (other.collider.gameObject.tag == "Player") {
//посмотреть имя загруженной сцены и загрузить такую сцену (reload)
SceneManager.LoadScene (SceneManager.GetActiveScene().name);
}
}
//запустится, если другой коллайдер попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверить, что у коллайдера тэг Player
if (other.tag == "Player") {
//удалить гриб
Destroy (gameObject);
}
}
}
Раскройте закладку Emission. Измените Rate over Time на 0. Добавьте начальный Burst (нажмите на кнопку +). Разверните закладку Shape и измените Shape на Circle.
Разверните закладку Renderer и измените Order in Layer на 100.
Надо будет удалить Explosion из сцены, после того, как взрыв был показан. Понадобится маленький скрипт. Создайте новый C# скрипт и назовите его ExplosionsDestroyer.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExplosionsDestroyer : MonoBehaviour {
//как долго взрыв будет в сцене
public float timeToDestroy;
//выполнится один раз при старте скрипта
void Start () {
//удалить взрыв из сцены
Destroy (gameObject, timeToDestroy);
}
}
Выберите Explosion в иерархии. Добавьте этот скрипт к Explosion. Измените Time To Destroy на 1. Создайте префаб Explosion. После создания префаба удалите взрыв из сцены (правый клик на Explosion в иерархии и нажать Delete).using System.Collections.Generic;
using UnityEngine;
public class ExplosionsDestroyer : MonoBehaviour {
//как долго взрыв будет в сцене
public float timeToDestroy;
//выполнится один раз при старте скрипта
void Start () {
//удалить взрыв из сцены
Destroy (gameObject, timeToDestroy);
}
}
Теперь добавим взрыв и его звук к скрипту гриба. Откройте скрипт MushroomController.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//библиотека для управления сценами
using UnityEngine.SceneManagement;
public class MushroomController : MonoBehaviour {
//префаб взрыва
public GameObject Explosion;
//звук взрыва
public AudioClip Boom;
//как далеко гриб может отойти от начальной точки
public float distanceToRun;
//скорость движения гриба
public float speed;
//направление взгляда гриба
public bool isLookingLeft = true;
//стартовая позиция гриба
Vector3 startPos;
//линк на компонент Rigidbody2D
Rigidbody2D rb;
//выполнится один раз при старте гриба
void Start () {
//делаем линк на компонент Rigidbody2D
rb = GetComponent <Rigidbody2D> ();
//запоминаем стартовую позицию гриба
startPos = transform.position;
//будем сравнивать квадрат вектора расстояния с квадратом расстояния
//так как извлечение корня медленный процесс
distanceToRun = distanceToRun * distanceToRun;
}
//выполняется на каждом фиксированном интервале
void FixedUpdate () {
//проверить, что гриб смотрит налево
if (isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб слева от стартовой точки
//и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x < startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота
TurnTheMushroom ();
//начать движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
//если проверка была отрицательной
} else {
//продолжить движение налево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
}
}
//проверить, что гриб смотрит направо
if (!isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб справа от стартовой точки
//и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x > startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота
TurnTheMushroom ();
//начать движение налево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
//если проверка была отрицательной
} else {
//продолжить движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
}
}
}
//функция поворота гриба
void TurnTheMushroom ()
{
//изменить указатель направления взгляда на противоположный
isLookingLeft = !isLookingLeft;
//повернуть гриб
transform.localScale = new Vector3 (transform.localScale.x * -1, transform.localScale.y, transform.localScale.z);
}
///запустится, если коллайдер коснулся другого коллайдера
void OnCollisionEnter2D (Collision2D other) {
//проверить, что у коллайдера тэг Player
if (other.collider.gameObject.tag == "Player") {
//посмотреть имя загруженной сцены и загрузить такую сцену (reload)
SceneManager.LoadScene (SceneManager.GetActiveScene().name);
}
}
//запустится, если другой коллайдер попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверить, что у коллайдера тэг Player
if (other.tag == "Player") {
//спавн взрыва
Instantiate (Explosion, transform.position, Quaternion.identity);
//проиграть звук взрыва
AudioSource.PlayClipAtPoint (Boom, transform.position);
//удалить гриб
Destroy (gameObject);
}
}
}
Импортируйте звуковой файл Boom в Assets. Выберите Enemy в иерархии. У Mushroom Controller появилось два новых поля в скрипте. Поместите префаб Explosion в Explosion поле. Поместите аудиофайл Boom в поле Boom. Сделайт префаб Enemy. проверьте сцену.using System.Collections.Generic;
using UnityEngine;
//библиотека для управления сценами
using UnityEngine.SceneManagement;
public class MushroomController : MonoBehaviour {
//префаб взрыва
public GameObject Explosion;
//звук взрыва
public AudioClip Boom;
//как далеко гриб может отойти от начальной точки
public float distanceToRun;
//скорость движения гриба
public float speed;
//направление взгляда гриба
public bool isLookingLeft = true;
//стартовая позиция гриба
Vector3 startPos;
//линк на компонент Rigidbody2D
Rigidbody2D rb;
//выполнится один раз при старте гриба
void Start () {
//делаем линк на компонент Rigidbody2D
rb = GetComponent <Rigidbody2D> ();
//запоминаем стартовую позицию гриба
startPos = transform.position;
//будем сравнивать квадрат вектора расстояния с квадратом расстояния
//так как извлечение корня медленный процесс
distanceToRun = distanceToRun * distanceToRun;
}
//выполняется на каждом фиксированном интервале
void FixedUpdate () {
//проверить, что гриб смотрит налево
if (isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб слева от стартовой точки
//и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x < startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота
TurnTheMushroom ();
//начать движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
//если проверка была отрицательной
} else {
//продолжить движение налево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
}
}
//проверить, что гриб смотрит направо
if (!isLookingLeft) {
//посчитать вектор направления от стартовой точки к грибу
Vector2 dist = transform.position - startPos;
//проверить, что гриб справа от стартовой точки
//и расстояние между грибом и стартовой точкой больше разрешенного удаления
if (transform.position.x > startPos.x && dist.sqrMagnitude > distanceToRun) {
//вызвать функцию поворота
TurnTheMushroom ();
//начать движение налево
rb.velocity = new Vector2 (-speed, rb.velocity.y);
//если проверка была отрицательной
} else {
//продолжить движение направо
rb.velocity = new Vector2 (speed, rb.velocity.y);
}
}
}
//функция поворота гриба
void TurnTheMushroom ()
{
//изменить указатель направления взгляда на противоположный
isLookingLeft = !isLookingLeft;
//повернуть гриб
transform.localScale = new Vector3 (transform.localScale.x * -1, transform.localScale.y, transform.localScale.z);
}
///запустится, если коллайдер коснулся другого коллайдера
void OnCollisionEnter2D (Collision2D other) {
//проверить, что у коллайдера тэг Player
if (other.collider.gameObject.tag == "Player") {
//посмотреть имя загруженной сцены и загрузить такую сцену (reload)
SceneManager.LoadScene (SceneManager.GetActiveScene().name);
}
}
//запустится, если другой коллайдер попал в триггер
void OnTriggerEnter2D (Collider2D other) {
//проверить, что у коллайдера тэг Player
if (other.tag == "Player") {
//спавн взрыва
Instantiate (Explosion, transform.position, Quaternion.identity);
//проиграть звук взрыва
AudioSource.PlayClipAtPoint (Boom, transform.position);
//удалить гриб
Destroy (gameObject);
}
}
}
Восприятие звука:
По стандарту, Audio Listener (компонент отвественный за восприятие звука) прикреплен к Main Camera. Audio Listener можно представить как виртуальные уши. Смотрите Unity Documentation для подробностей. Надо передвинуть этот компонент к крысе. Выберите Main Camera (дочерний объект крысы) ит отключите Audio Listener в Inspector (нам нужен только один такой компонент в сцене).Выьерите Rat в иерархии и добавьте Audio Listener к ней.
Проверьте сцену.
Как сделать движущуюся платформу:
Добавим движущуюся платформу. Поместите спрайт largePlatform в сцену. Будет создан новый игровой объект. Назовите его Platform. Выберите Platform в иерархии. Измените его Z-позицию на 0. Измените Tag и Layer на Ground. Добавьте Rigidbody 2D к нему. Измените Body Type на Kinematic. Поставьте Interpolate на Interpolate. Включите Freeze Position X и Freeze Rotation Z. Добавьте Box Collider 2D.Нам нужен скрипт движения для платформы. САоздайте новый C# скрпт и назовите его PlatformMoving.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlatformMoving : MonoBehaviour {
//скорость движения платформы
public float speed;
//позиция, где платформа должна повернуть назад
public Transform endPoint;
//позиция начала движения
Vector3 startPoint;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//скорость платформы в текущий момент
float currentSpeed;
//выполнится при запуске скрипта
void Start () {
//запомнит стартовую точку платформы
startPoint = transform.position;
//сделать ссыдку на Rigidbody2D
rb = GetComponent <Rigidbody2D> ();
//начальное направление движения
currentSpeed = speed;
}
//выполнятся через интервалы
void FixedUpdate () {
//проверка, находится-ли платформа выше конечной точки
if (transform.position.y > endPoint.position.y)
//скорость для вектора движения вниз
currentSpeed = -speed;
//проверка, находится-ли платформа ниже начальной точки
if (transform.position.y < startPoint.y)
//скорость для вектора движения вверх
currentSpeed = speed;
//направить платформу по вектору движения
rb.velocity = new Vector3 (0, currentSpeed, 0);
}
}
Создайте новый пустой объект (empty).using System.Collections.Generic;
using UnityEngine;
public class PlatformMoving : MonoBehaviour {
//скорость движения платформы
public float speed;
//позиция, где платформа должна повернуть назад
public Transform endPoint;
//позиция начала движения
Vector3 startPoint;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//скорость платформы в текущий момент
float currentSpeed;
//выполнится при запуске скрипта
void Start () {
//запомнит стартовую точку платформы
startPoint = transform.position;
//сделать ссыдку на Rigidbody2D
rb = GetComponent <Rigidbody2D> ();
//начальное направление движения
currentSpeed = speed;
}
//выполнятся через интервалы
void FixedUpdate () {
//проверка, находится-ли платформа выше конечной точки
if (transform.position.y > endPoint.position.y)
//скорость для вектора движения вниз
currentSpeed = -speed;
//проверка, находится-ли платформа ниже начальной точки
if (transform.position.y < startPoint.y)
//скорость для вектора движения вверх
currentSpeed = speed;
//направить платформу по вектору движения
rb.velocity = new Vector3 (0, currentSpeed, 0);
}
}
Назовите его endPoint. Добавьте к нему иконку для лучшего вида. Поместите endPoint над Platform (испольуйте инструмент движения).
Выберите Platform в иерархии. Добавьте скрипт PlatformMoving. Измените Speed на 1. Поместите endPoint в поле End Point.
Запустите игру и проверьте (можете переключить на сцену, пока игра запущена).
Поместите wall в сцену справа от платформы. Выьерите эту стену в иерархии и добавьте Box Collider 2D.
Поместите следующий Dead End префаб в сцену под двигающейся платформой. Нажмите на Edit Collider и настройте размер.
Как добавить физические объекты:
Импортируйте картинку Box из скачанного архива. Поместите спрайт Box в сцену (на движущуюся платформу). Выьерите Box в иерархии. Измените Tag и Layer на Ground. Смените Z-позицию на 0. Добавьте Rigidbody 2D. Измените Interpolate на Interpolate. Добавьте Box Collider 2D.Теперь сможете взаимодействовать с этим объектом.
Конец уровня:
Добавьте Ground префаб в сцену, где платформа перестаёт двигаться наверх (смотрите скриншот). Добавьте последнбб стену (поместите спрайт wall в сцену и добавьте Box Collider 2D ).Импортируйте картинку Exit в Assets. Добавьте спрайт Exit в сцену возле последней стены. Крыса не должна допрыгивать до Exit, если она просто прыгает с пола. Boxпонадобится как подставка. Выберите Exit в иерархии. Добавьте Box Collider 2D. Включите Is Trigger. Добавьте Dead End Controller. У нас сейчас нет следуюшего уровня, поэтому просто перезагрузим сцену.
Как сделать движущийся фон с эффектом параллакс:
С эффектом параллакс мы можем имитировать глубину сцены при движении. Дальние объекты будут двигаться медленнее (или быстрее, если хотите). Сделаем маленький скрипт. Создайте новый C# скрипт и назовите его Parallax.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Parallax : MonoBehaviour {
//ссылочная переменная на игрока
GameObject player;
//позиция игрока в предыдущем кадре
//и разница в позиции между кадрами
Vector3 lastPos, offset;
//скорость движения фона
public float speed;
//выполнится один раз при запуске скрипта
void Start () {
//делаем линк на игрока
player = GameObject.FindWithTag ("Player");
//запоминаем его позицию
lastPos = player.transform.position;
}
//выполняется каждый кадр
void Update () {
//посчитать разницу в позициях между кадрами
offset = player.transform.position - lastPos;
//пересчитать разницу в зависимости от скорости и передвинуть фон по полученному вектору
//Time.deltaTime корректировка для разного фпс
transform.Translate (offset * speed * Time.deltaTime);
//перезаписать позицию в текущем кадре
lastPos = player.transform.position;
}
}
Импортируйте BackGround в Assets. Поместите BackGround в сцену. Измените X и Y Scale на 4. Передвиньте на позицию крысы (смотрите скриншот). Измените Order in Layer на -100. Добавьте Parallaxскрипт. Измените Speed на 60 (потестите разные настройки).using System.Collections.Generic;
using UnityEngine;
public class Parallax : MonoBehaviour {
//ссылочная переменная на игрока
GameObject player;
//позиция игрока в предыдущем кадре
//и разница в позиции между кадрами
Vector3 lastPos, offset;
//скорость движения фона
public float speed;
//выполнится один раз при запуске скрипта
void Start () {
//делаем линк на игрока
player = GameObject.FindWithTag ("Player");
//запоминаем его позицию
lastPos = player.transform.position;
}
//выполняется каждый кадр
void Update () {
//посчитать разницу в позициях между кадрами
offset = player.transform.position - lastPos;
//пересчитать разницу в зависимости от скорости и передвинуть фон по полученному вектору
//Time.deltaTime корректировка для разного фпс
transform.Translate (offset * speed * Time.deltaTime);
//перезаписать позицию в текущем кадре
lastPos = player.transform.position;
}
}
Как добавить фоновую музыку:
Теперь простое. Импортируйте звуковой файл Music. Выберите Rat в иерархии. Перетащите Music на Rat ы иерархии (или добавьте Audio Source и поместите Music в поле AudioClip field). Включите Loop.Проверьте сцену.
Это конец туториала. Знаю, тут очень много вещей, которые можно улучшить (например: например анимация прыжка на углах. Можете пофиксить это используя: Physics2D.OverlapBox) но каждая игра отлична от другой и доработка мелочей индивидуальна.
этот туториал как юнити пакет