Привет, Хабр!
Холодная питерская осень штабелями укладывает людей в кровать с температурой и прочими прелестями той части вселенной, которая отвечает за болезни. Но всему плохому, к счастью, приходит конец. Поэтому, как вы поняли из вступления, сегодня в нашем курсе от начинающего для начинающих мы поговорим о создании врагов, уровней и физики. Больше физики!
![](https://habrastorage.org/r/w1560/files/1a1/e74/116/1a1e74116ca84389bf8ba8d9e303039d.png)
Осторожно: объемы гифок под катом становятся просто нечеловеческими!
Предыдущие части были опубликованы почти две недели назад, поэтому советую немного освежить знания :)
Дисклеймер: весь показанный в статье код не является образцом для подражания, примером идеального кода и прочих вымышленных и не существующих в природе вещей. Практики, примененные в статье, могут являться одними из множества решений конкретной проблемы. А могут и не являться.
Начнем с конца, добавив максимально простую физическую штуку — коробку. Нам нужны спрайт коробки, rigidbody2D и boxcollider2D. Приступим!
![](https://habrastorage.org/files/6ed/0ca/b13/6ed0cab13d8b4c5ebc5c7c2dfdd1985d.gif)
Как видите, все еще ничего сложного. Приготовим из получившейся коробки префаб и перенесем еще раз на форму. Следите за руками: у одной из коробок поставим галку isKinematic у rigidbody2D и запустим начинающееся веселье:
![](https://habrastorage.org/files/317/ac5/e4b/317ac5e4be35459ba5e6156393a8c9ac.gif)
Коробка с установленным rigidbody2D.isKinematic = true не двигается. Ее нельзя сдвинуть с места применением сил или коллизий, так что эта коробка будет выполнять роль неподвижного препятствия. Идем дальше.
В лучших традициях super meat boy, добавим в нашу пока_еще_не игру врага-пилу. Пила будет крутиться и… всё.
![](https://habrastorage.org/files/396/794/3cd/3967943cd122413c8dc63df7e785a861.gif)
Невероятной сложности скрипт для этого действия выглядит так:
Поясню: transform.rotate вращает спрайт на заданные в vector3 углы вокруг, соответственно, осей x, y и z. В случае с 2D игрой первые две оси мало применимы для нашей задачи, и вот почему:
transform.Rotate (new Vector3(-3f,0f,0f));
![](https://habrastorage.org/files/aaf/469/cf7/aaf469cf7809465998b2723a0c2ff4e1.gif)
transform.Rotate (new Vector3(0f,-3f,0f));
![](https://habrastorage.org/files/c58/ac0/308/c58ac0308fb4416b9e379608ad88fa09.gif)
К слову, о 2D режиме. Внимательный читатель заметил, что пила некрасиво торчит перед платформой и загораживает весь вид. Для того, чтобы это исправить, достаточно знать простую вещь — в 2D режиме объекты на экране упорядочиваются (вот тут не очень уверен насчет терминологии, поправьте) по z-уровню. Вот вам наглядная гифка о том, как это работает.
![](https://habrastorage.org/files/50e/fb1/4d6/50efb14d6bc44cab8ee8fb063cbed769.gif)
Теперь сделаем так, чтобы герой умирал при взаимодействии с пилой. Исправим characterController.cs следующим образом:
Бинго! Теперь, имея звезды, коробки, препятствия и dieCollider'ы давайте попробуем собрать уровень. Делается это очень быстро и легко, так как все объекты уже существуют в виде префабов, и их не нужно каждый раз настраивать заново.
![](https://habrastorage.org/files/ef3/4d0/ebc/ef34d0ebcf8f4b6288e2b7d09422fcea.gif)
Идем дальше. Когда есть один уровень, нужен и второй. Сохраним сцену как scene1.unity и создадим новую. Построим, аналогично примеру выше, еще один уровень и сохраним (уже догадались? молодцы) как scene2. Теперь идем в File -> Build Settings и ставим галки на обеих сценах. Примерно так:
![](https://habrastorage.org/r/w1560/files/cc3/7d2/774/cc37d27749cd4ead876f191b2825655b.png)
Рядом с названием сцены отображается номер — по нему мы можем обращаться к сцене для ее загрузки. Или по имени, кому как удобнее. Создадим пустой объект и запрограммируем его так, чтобы после сбора всех звезд и столкновения с ним (объектом) игрок переходил на вторую сцену. Для этого в методе OnTriggerEnter будем проверять, есть ли еще звезды на сцене.
Вот так он будет выглядеть на сцене. При желании, можно добавить спрайт с помощью компонента sprite renderer.
![](https://habrastorage.org/r/w1560/files/f16/2ba/9d5/f162ba9d55304813b5d3c3cf14314513.png)
На этом основная часть статьи заканчивается и начинается бонус-трек по вашим заявкам.
![](https://habrastorage.org/r/w1560/files/952/11e/8f7/95211e8f7532498fae8e9f1f5fdb0ebc.png)
Соответственно, немного про веселье и про физику! Добавим пару спрайтов — платформу и файрбол из Super Mario, и попробуем сделать из этого машину для разрушения кучи коробок.
![](https://habrastorage.org/files/45e/b39/6bd/45eb396bd0b8452ca10129af87e97236.gif)
В этом нам поможет первый представитель семейства Джойнтов, с которым мы познакомимся — Distance Joint, который, по сути, позволяет превратить что угодно в игре в математический маятник. Добавляем его на объект, выбираем, что будет с другой стороны маятника (здесь пригодится объект с rigidbody2d.isKinematic = true), какое расстояние между ними и в итоге получится то, что получилось выше. Коробки, кстати, все те же, что использовались в нашем платформере. Смотрите!
![](https://habrastorage.org/files/b04/d03/bc4/b04d03bc4cb64f7ab85c82c3aead5bac.gif)
Объект, к которому прицеплен наш разрушающий шар, имеет компонент rigidbody2D со включенным атрибутом isKinematic. Это нужно для того, чтобы он не падал сразу после запуска игры (и вообще никогда).
А вот на этом действительно всё! Спасибо за внимание, приходите еще, задавайте вопросы! В следующей статье я покажу как анимировать героя, звездочки и рисовать нормальные надписи на экране. В общем, займемся всякими украшательствами.
Предыдущие серии:
Часть первая, в которой обаятельный носач учится ходить
Часть вторая, в которой проигрывать — весело.
p.s. Больше веселья с физикой (GIF, 3.1 MB)
Холодная питерская осень штабелями укладывает людей в кровать с температурой и прочими прелестями той части вселенной, которая отвечает за болезни. Но всему плохому, к счастью, приходит конец. Поэтому, как вы поняли из вступления, сегодня в нашем курсе от начинающего для начинающих мы поговорим о создании врагов, уровней и физики. Больше физики!
![](https://habrastorage.org/files/1a1/e74/116/1a1e74116ca84389bf8ba8d9e303039d.png)
Осторожно: объемы гифок под катом становятся просто нечеловеческими!
Предыдущие части были опубликованы почти две недели назад, поэтому советую немного освежить знания :)
Дисклеймер: весь показанный в статье код не является образцом для подражания, примером идеального кода и прочих вымышленных и не существующих в природе вещей. Практики, примененные в статье, могут являться одними из множества решений конкретной проблемы. А могут и не являться.
Начнем с конца, добавив максимально простую физическую штуку — коробку. Нам нужны спрайт коробки, rigidbody2D и boxcollider2D. Приступим!
![](https://habrastorage.org/files/6ed/0ca/b13/6ed0cab13d8b4c5ebc5c7c2dfdd1985d.gif)
Как видите, все еще ничего сложного. Приготовим из получившейся коробки префаб и перенесем еще раз на форму. Следите за руками: у одной из коробок поставим галку isKinematic у rigidbody2D и запустим начинающееся веселье:
![](https://habrastorage.org/files/317/ac5/e4b/317ac5e4be35459ba5e6156393a8c9ac.gif)
Коробка с установленным rigidbody2D.isKinematic = true не двигается. Ее нельзя сдвинуть с места применением сил или коллизий, так что эта коробка будет выполнять роль неподвижного препятствия. Идем дальше.
В лучших традициях super meat boy, добавим в нашу пока_еще_не игру врага-пилу. Пила будет крутиться и… всё.
![](https://habrastorage.org/files/396/794/3cd/3967943cd122413c8dc63df7e785a861.gif)
Невероятной сложности скрипт для этого действия выглядит так:
using UnityEngine;
using System.Collections;
public class sawScriptNew : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.Rotate (new Vector3(0f,0f,-3f));
}
}
Поясню: transform.rotate вращает спрайт на заданные в vector3 углы вокруг, соответственно, осей x, y и z. В случае с 2D игрой первые две оси мало применимы для нашей задачи, и вот почему:
transform.Rotate (new Vector3(-3f,0f,0f));
![](https://habrastorage.org/files/aaf/469/cf7/aaf469cf7809465998b2723a0c2ff4e1.gif)
transform.Rotate (new Vector3(0f,-3f,0f));
![](https://habrastorage.org/files/c58/ac0/308/c58ac0308fb4416b9e379608ad88fa09.gif)
К слову, о 2D режиме. Внимательный читатель заметил, что пила некрасиво торчит перед платформой и загораживает весь вид. Для того, чтобы это исправить, достаточно знать простую вещь — в 2D режиме объекты на экране упорядочиваются (вот тут не очень уверен насчет терминологии, поправьте) по z-уровню. Вот вам наглядная гифка о том, как это работает.
![](https://habrastorage.org/files/50e/fb1/4d6/50efb14d6bc44cab8ee8fb063cbed769.gif)
Теперь сделаем так, чтобы герой умирал при взаимодействии с пилой. Исправим characterController.cs следующим образом:
void OnTriggerEnter2D(Collider2D col){
if ((col.gameObject.name == "dieCollider")||(col.gameObject.name == "saw"))
Application.LoadLevel (Application.loadedLevel);
Бинго! Теперь, имея звезды, коробки, препятствия и dieCollider'ы давайте попробуем собрать уровень. Делается это очень быстро и легко, так как все объекты уже существуют в виде префабов, и их не нужно каждый раз настраивать заново.
![](https://habrastorage.org/files/ef3/4d0/ebc/ef34d0ebcf8f4b6288e2b7d09422fcea.gif)
Краткий гайд по гейм-дизайну
При создании уровня мотивируйте игрока знакомиться с миром. Поставьте перед ним приз, а следующий расположите так, чтобы за ним нужно было, например, прыгнуть. Имея, например, двигающиеся коробки, поставьте их так, чтобы очередную звезду нельзя было достать без них. И так далее.
![](https://habrastorage.org/files/662/c9a/0c9/662c9a0c9fa649fca93886c08d955e83.gif)
Обучайте игрока максимально эффективно: не стоит растягивать введение на несколько уровней. Вспомните классический мир 1-1 из Super Mario Brothers. Его (как правило) достаточно, чтобы познакомиться с основными механиками игры и самыми часто встречаемыми врагами.
![](https://habrastorage.org/files/662/c9a/0c9/662c9a0c9fa649fca93886c08d955e83.gif)
Обучайте игрока максимально эффективно: не стоит растягивать введение на несколько уровней. Вспомните классический мир 1-1 из Super Mario Brothers. Его (как правило) достаточно, чтобы познакомиться с основными механиками игры и самыми часто встречаемыми врагами.
Идем дальше. Когда есть один уровень, нужен и второй. Сохраним сцену как scene1.unity и создадим новую. Построим, аналогично примеру выше, еще один уровень и сохраним (уже догадались? молодцы) как scene2. Теперь идем в File -> Build Settings и ставим галки на обеих сценах. Примерно так:
![](https://habrastorage.org/files/cc3/7d2/774/cc37d27749cd4ead876f191b2825655b.png)
Рядом с названием сцены отображается номер — по нему мы можем обращаться к сцене для ее загрузки. Или по имени, кому как удобнее. Создадим пустой объект и запрограммируем его так, чтобы после сбора всех звезд и столкновения с ним (объектом) игрок переходил на вторую сцену. Для этого в методе OnTriggerEnter будем проверять, есть ли еще звезды на сцене.
if (col.gameObject.name == "endLevel") {
if (!(GameObject.Find("star"))) Application.LoadLevel ("scene2");
}
Вот так он будет выглядеть на сцене. При желании, можно добавить спрайт с помощью компонента sprite renderer.
![](https://habrastorage.org/files/f16/2ba/9d5/f162ba9d55304813b5d3c3cf14314513.png)
Как выглядит переключение уровней (gif, 3.7 MB)![](https://habrastorage.org/files/820/6ca/157/8206ca1572b64edc9a2a97bafec7d5ec.gif)
![](https://habrastorage.org/files/820/6ca/157/8206ca1572b64edc9a2a97bafec7d5ec.gif)
На этом основная часть статьи заканчивается и начинается бонус-трек по вашим заявкам.
![](https://habrastorage.org/files/952/11e/8f7/95211e8f7532498fae8e9f1f5fdb0ebc.png)
Соответственно, немного про веселье и про физику! Добавим пару спрайтов — платформу и файрбол из Super Mario, и попробуем сделать из этого машину для разрушения кучи коробок.
![](https://habrastorage.org/files/45e/b39/6bd/45eb396bd0b8452ca10129af87e97236.gif)
В этом нам поможет первый представитель семейства Джойнтов, с которым мы познакомимся — Distance Joint, который, по сути, позволяет превратить что угодно в игре в математический маятник. Добавляем его на объект, выбираем, что будет с другой стороны маятника (здесь пригодится объект с rigidbody2d.isKinematic = true), какое расстояние между ними и в итоге получится то, что получилось выше. Коробки, кстати, все те же, что использовались в нашем платформере. Смотрите!
![](https://habrastorage.org/files/b04/d03/bc4/b04d03bc4cb64f7ab85c82c3aead5bac.gif)
Объект, к которому прицеплен наш разрушающий шар, имеет компонент rigidbody2D со включенным атрибутом isKinematic. Это нужно для того, чтобы он не падал сразу после запуска игры (и вообще никогда).
А вот на этом действительно всё! Спасибо за внимание, приходите еще, задавайте вопросы! В следующей статье я покажу как анимировать героя, звездочки и рисовать нормальные надписи на экране. В общем, займемся всякими украшательствами.
Предыдущие серии:
Часть первая, в которой обаятельный носач учится ходить
Часть вторая, в которой проигрывать — весело.
p.s. Больше веселья с физикой (GIF, 3.1 MB)