Проблема со столкновениями Unity3d. Передвижение по типу "Tomb Of The Mask". Объект перестаёт двигаться
С помощью туториала написал код, позволяющий управлять персонажем. При нажатии на клавишу объект начинает двигаться в определённом направлении до момента, пока он не встретит препятствие. Но есть проблема, иногда, когда объект передвигается, он может "застрять" в стене, после чего перестаёт двигаться и как-либо отвечать на нажатие клавиш. Нигде в интернете я не нашёл решения данной проблемы.
Скрипт, отвечающий за передвижение:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
enum Direction
{
North,
South,
East,
West
}
[SerializeField]
float speed;
[SerializeField]
LayerMask obstacleMask;
Direction MovingDir;
Rigidbody rb;
bool movingHorizontally, canCheck;
void Start ()
{
rb = GetComponent<Rigidbody>();
}
void Update ()
{
if (movingHorizontally)
canCheck = Physics.Raycast(transform.position, Vector3.left, .6f, obstacleMask) || Physics.Raycast(transform.position, Vector3.right, .6f, obstacleMask);
else
canCheck = Physics.Raycast(transform.position, Vector3.forward, .6f, obstacleMask) || Physics.Raycast(transform.position, Vector3.back, .6f, obstacleMask);
if (canCheck)
{
if (Input.GetAxisRaw("Horizontal") != 0)
{
rb.constraints = RigidbodyConstraints.FreezePositionZ;
rb.freezeRotation = true;
movingHorizontally = true;
if (Input.GetAxisRaw("Horizontal") > 0)
{
MovingDir = Direction.East;
}
else
{
MovingDir = Direction.West;
}
}
else if (Input.GetAxisRaw("Vertical") != 0)
{
rb.constraints = RigidbodyConstraints.FreezePositionX;
rb.freezeRotation = true;
movingHorizontally = false;
if (Input.GetAxisRaw("Vertical") > 0)
{
MovingDir = Direction.North;
}
else
{
MovingDir = Direction.South;
}
}
}
}
void FixedUpdate()
{
switch(MovingDir)
{
case Direction.North:
rb.velocity = new Vector3(0, 0, speed * Time.fixedDeltaTime);
break;
case Direction.South:
rb.velocity = new Vector3(0, 0, -speed * Time.fixedDeltaTime);
break;
case Direction.East:
rb.velocity = new Vector3(speed * Time.fixedDeltaTime, 0, 0);
break;
case Direction.West:
rb.velocity = new Vector3(-speed * Time.fixedDeltaTime, 0, 0);
break;
}
}
}
Ответы (1 шт):
В общих словах, проблема у вас заключается в том, что движение вы делаете физическое, а вот обработку коллизий - в Update(). Все расчеты, связанные с физикой нужно выполнять в FixedUpdate(). В противном случае, возможны рассинхронизации в ваших вычислениях и ожиданиях.
Если чуть конкретней, то проблемы из разряда "застрял в стене" происходят как раз по причине того, что движение происходит по физике, а коллизии считаются вне физике. Update() вызывается с частотой обновления кадров (FPS) в вашей игре, тогда как FixedUpdate() фиксированное количество раз в секунду. И этим двум интервалам обновления никак не обязательно быть синхронизированными между собой, в частности, FPS - совсем не константная величина. Как раз из-за этого вы можете получить информацию о коллизии уже в тот момент, когда она перестала быть актуальна, и объект прошел сквозь стену.
Для большего понимания почитайте, пожалуйста, вопрос про разницу между Update и FixedUpdate.

