Учебные материалы для школы программирования. Часть 11
Spoiler
На сегодняшнем занятии мы познакомимся с физикой на джоинтах движка BOX 2D, на примере создания персонажа, похожего на главного героя Gish или Slime Laboratory.
Порядок выполнения
Создадим новый 2д проект и импортируем в него приложенный ассет. Ассет содержит все необходимые ресурсы, включая спрайты для уровня, скрипты и меш для персонажа.
Для начала, создадим новую сцену и поместим в неё 10 сфер с радиусом 0.5, таким образом, чтобы получилась "ромашка":
Установим на каждую сферу Rigidbody2D массой 0.5 и CircleCollider2D. Центральная сфера имеет массу 0.05 и drag = 1 и не имеет коллайдера.
Добавим между соседними сферами по одному SpringJoint2D. Обратите внимание на параметр Frequency - это частота опроса пружины, чем частота выше, тем пружина будет сильнее возвращаться на своё место. Damping - демпфирование пружины (предотвращение колебаний, смягчающий эффект).
Таким образом, мы не даём нашей заготовке разлетаться на куски или, наоборот, излишне сжиматься. Тем не менее, форму она держать не будет.
Для придания формы используем среднюю точку. От каждой, из 9-и окружающих её сфер, создадим ещё по одному джоинту.
Данная конструкция позволяет нам держать форму, при этом, она может сработать некорректно, если при сильном ударе центр вылетит за пределы круга. Более того, данная модель не учитывает поверхностное натяжение между удалёнными точками. Для этого, создадим систему из джоинтов по такому принципу:
Итоговая система джоинтов должна выглядеть примерно так:
Камеру повесим на центральный объект и протестируем, как себя ведёт наша физическая модель. Изменяя её параметры, можно добиться разной вязкости и плотности.
Теперь придадим "лизуну" очертания. Для этого в ассет приложена 3д-модель со скелетом, каждая из 9-и костей которого управляет по одному вертексу по периметру.
Для неё написан скрипт Goo, который управляет привязкой и отвечает за перемещение нашего главного героя.
Закинем модель на сцену и назначим ей скрипт. Конфигурируем его таким образом. На сцене создадим уровень из спрайтов и назначим ему коллайдеры.
Разберём немного сам скрипт:
using? ?System?.?Collections?;
using? ?System?.?Collections?.?Generic?;
using? ?UnityEngine?;
public?? class ??Goo?: ?MonoBehaviour ?{
public ??ConstantForce2D ?ForceObject; ?// центральная точка как объект приложения силы
public?? float? maxForce ?=?? 4f?; ?// сила передвижения ?public??Transform?[] bones; ?// массив костей
?public ??Transform?[] go; ?// массив сфер
?public?? float? sphereRadius; ?// радиус сферы, можно брать автоматически, но в данном случае выставляем вручную
public?? Transform? center; ?// центральная точка как трансформ
ConstantForce2D?[] frc; ?// все объекты приложения силы ?
// Use this for initialization
void ??Start?() {
frc?? = ??new??ConstantForce2D?[?9?]; ?// инициализируем
// находим все объекты приложения силы
for ?(?int ?i ?= ?0?; ?i? <? 9?; ?i?++?) ?{
frc?[?i?] ?=??go?[?i?].?GetComponent?<?ConstantForce2D?>();
}
}
// Update is called once per frame
void ??Update?() {
for ?(?int ?i ?= ?0?; ?i ?< ?9?; ?i?++?) {
?// выставляем кости по точкам с небольшим смещение
bones?[?i?].?position? ?=? ?go?[?i?].?position? ?+? (?go?[?i?].?position? ?- center?.?position?).?normalized?? * ??sphereRadius? / ?2f?;
// добавляем всем точкам силу по горизонтали
frc?[?i?].?force =? ?new??Vector2?(?Input?.?GetAxis?(?"Horizontal"?) ?* ??maxForce?, 0f?); ?
}
// и центральной точке тоже
ForceObject?.?force = ??new??Vector2?(?Input?.?GetAxis?(?"Horizontal"?) ?* maxForce?, ?0f?);
?// нажали пробел
if? (?Input?.?GetKeyDown?(?KeyCode?.?Space?)) {
foreach?(?Transform?rig ?in??go?) {
rig?.?GetComponent?<?Rigidbody2D?>().?velocity? ?+=? ?new Vector2?(?0?,? 6f?); ?// прыжок
}
}
}
}
После отключения MeshRenderer у сфер, можно увидеть, что всё адекватно работает. Для полноты картины, фон и камеру прикрепляем к центральному объекту. У риджитбади центрального объекта нужно запретить вращение по Z. Можно добавить, на свое усмотрение, пару глаз.
На серые объекты вешаем скрипт RandomColor и выставим ему палитру.
using? ?System?.?Collections?;
using? ?System?.?Collections?.?Generic?;
using? ?UnityEngine?;
public ??class ??RandomColor?: ?MonoBehaviour {
SpriteRenderer ?rndr;
?public ??Color32?[] colors;
// Use this for initialization
void ??Start?() {
rndr? ?=? ?GetComponent?<?SpriteRenderer?>();
?rndr?.?color ??= ??colors?[?Random?.?Range?(?0?, ?colors?.?Length?)];
}
}
Теперь при старте уровень приобретёт цвет.
На этом, сборка нашего проекта завершена!
Dartess
Когда-то во времена java-игр играл в интересный платформер-головоломку с управлением таким вот жидким персонажем (то ли красный, то ли синий шарик такой же). Пытался своим умом тогда понять (только-только знакомился с паскалем в то время), как устроена физика такого персонажа, но ни одной идеи не появилось)) Кстати, если вдруг кто понял, о чём я, и помнит название, напишите, плиз.
Спасибо за статью! Приятно написано. Гифку бы ещё для демонстрации)
Vest
Я давно играл в такую, Gish, называется. Она на Стиме есть.
Dartess
К сожалению, не то, но спасибо)
Alex_Hi
Bounce Tales или просто Bounce?
Помню что-то похожее, да. Там и синий и красный были.
Только не помню где я её запускал(