Проблема с физикой в местах соединения коллайдеров (отскоки на ровной поверхности)
Есть сцена в 3D с платформами(меши с куб коллайдер), стоят все в ряд одна за одной(образуют сплошную дорогу), по ним катится мяч(сфера с Rigidbody), при переходе с одной на другую платформу мяч иногда подпрыгивает.
При старте сцены у Rigidbody задается velocity для старта движения, в моменты отскоков на мяч кроме физики ничего не действует.
Как убрать эти прыжки, почему так происходит?
Пробовал удлинять коллайдеры у платформ, это не помогло, ставил разные collision detection у Rigidbody мяча - не помогает.
using UnityEngine;
public class SimpleX : MonoBehaviour
{
public GameObject player;
public GameObject cam;
void Start()
{
if (!player){
player = GameObject.CreatePrimitive(PrimitiveType.Sphere);
player.AddComponent<Rigidbody>();
}
player.transform.position = new Vector3(0, 2, 0);
player.GetComponent<Rigidbody>().velocity = Vector3.forward * 200;
if (!cam){
cam = GameObject.Find("Main Camera");
}
}
void Update()
{
cam.transform.position = player.transform.position - (Vector3.forward * 5);
}
int roadSectorCount = 0;
int roadSectorLength = 10;
private void FixedUpdate()
{
while(player.transform.position.z+100 > roadSectorCount * roadSectorLength) {
var roadSector = GameObject.CreatePrimitive(PrimitiveType.Cube);
roadSector.transform.position = new Vector3(0, 0, roadSectorCount * roadSectorLength);
roadSector.transform.localScale = new Vector3(20, 1, roadSectorLength);
roadSector.GetComponent<MeshRenderer>().material.color = new Color(Random.value, Random.value, Random.value, 0);
roadSectorCount++;
}
}
}
Демонстрация проблемного поведения: https://www.youtube.com/watch?v=4A1W0eDaXnA
На данный момент закрыл это созданием невидимой платформы, которая постоянно движется под мячом, следовательно, пересечений с реальными платформами не происходит, но такое решение абсолютно не годится.
UPD
Переопределил у платформ методы OnCollision.
Отскок начинается до срабатывания
OnCollisionEnter(первая фиксирует изменения) следующей платформы.OnCollisionExitпредыдущей платформы отрабатывает только спустя
несколько итераций физики.Получается, шар в моменте стоит на 2 коллайдерах одновременно, хотя и не должен.
Это поведение наблюдается при всех collision detection кроме continuous speculative (при нем прыжки будут почти на каждом переходе и может начаться до OnCollisionEnter, причем unity не может корректно обработать возврат на другой детект без перезапуска)
Можно предположить, что мячик частично проскакивает внутрь платформы(при включенной гравитации он иногда проскальзывает немного внутрь), а затем ударяется о вторую, но нет, я отключил гравитацию и мониторил изменение координаты, даже без изменений координаты эти отскоки происходят.
Ответы (2 шт):
Во-первых убедитесь что реальных зазоров нет, для заметки подскажу тем кто может с этим столкнуться, что можно использовать стыковки обьектов путём зажатия клавиши V и выбрав один из углов и протянуть его к другому необходимому углу.
Также возможно вам поможет решение с Contact Offset у физики, данный глобальный параметр указывает какое значение будет являтся дистанцией касания, попробуйте установить значение равное 0, или поиграть с значением методом пробы:
Во-вторых используйте физическое движение вместо "телепортаций" путём transform если в методе Update() указано движение игрока. Вам поможет движение по нормалям поверхности, для удобства есть наглядный видео урок по данной теме: https://www.youtube.com/watch?v=puPjNRJMmOc (если видео будет доступно к тому времени как Вы это откроете, если нет используйте информацию выше про движение по нормалям поверхности)
(Данный вариант исключает любую возможность падать персонажу внутрь потому что он будет идти строго по поверхности)
В общем, к каким выводам я пришел. По всей видимости, решить данную проблему в каком-то общем виде не выйдет, сама проблема находится в PhysX, то есть, будет актуальна для unity, unreal engine и прочих.
Есть несколько способов ухода от этой проблемы:
Не использовать некинематический
Rigidbodyдля персонажа.Тут все просто, если чего-то нет, то с этим и нет проблем. Используем для своих персонажей
Character Controller, либо делаем полностью все сами черезkinematic Rigidbody. Есть только проблемы с фактически полной реализацией свой физики для персонажа, но из плюсов полный контроль.Попробовать скрыть, уменьшить случаи проблемного поведение
Можно переопределитьOnCollisionEnterи при обнаружении незапланированного начала отскока возвращатьRigidbodyна землю (костыль адовый, но кто-то использует).Простым вариантом является уменьшение
contactOffsetу проблемных коллайдеров и персонажа (myGameObject.GetComponent<SomeCollider>().contactOffset), либо уменьшение Default Contact Offset в настройках проекта (Edit -> Project Settings -> Physics -> Default Contact Offset)Стоит заметить, что при слишком низком значении,
Rigidbodyможет начать трястись на ровной поверхность, поэтому с этим параметром придется экспериментировать, также это не защитит от отскоков от скрытых стен при частичных провалах внутрь коллайдера (при падении с высоты), поэтому придется это как-то дополнительно обрабатывать и исключать (Raycast,SphereCast).Даже при изменении
Contact Offset, при обнаружении коллизий методомcontinuous speculativeотскоки будут наблюдаться.Генерация общего коллайдер меша для дороги
Способ ресурсозатратный, необходимо собрать нужные коллайдеры участков дороги, удалить перекрывающиеся грани и склеить в один единственный меш коллайдер. Для кубов и плейнов работает хорошо, но все меняется на более сложных моделях. В местах множества узких полиговнов, даже если все эти полигоны лежат в одной плоскости, опять вылазят подскоки и дрожания. Поэтому придется для таких моделей отдельно избавляться от таких мест в меш коллайдерах, либо уменьшать
contactOffsetдля всей конструкции и персонажа.
Для большинства случаев наиболее верным решением будет использовать первый вариант.

