Персонаж Gish на Unity 3D
Учебные материалы для школы программирования. Часть 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; // сила передвижения
publicTransform[] bones; // массив костей
public Transform[] go; // массив сфер
public float sphereRadius; // радиус сферы, можно брать автоматически, но в данном случае выставляем вручную
public Transform center; // центральная точка как трансформ
ConstantForce2D[] frc; // все объекты приложения силы
// Use this for initialization
void Start() {
frc = newConstantForce2D[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 = newVector2(Input.GetAxis("Horizontal") * maxForce, 0f);
}
// и центральной точке тоже
ForceObject.force = newVector2(Input.GetAxis("Horizontal") * maxForce, 0f);
// нажали пробел
if (Input.GetKeyDown(KeyCode.Space)) {
foreach(Transformrig ingo) {
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)];
}
}
Теперь при старте уровень приобретёт цвет.
На этом, сборка нашего проекта завершена!