#c# #unity3d
#c# #unity3d
Вопрос:
У меня есть скрипт для перехода, но он переходит в зависимости от значения константы JumpFactor. Я бы хотел, чтобы переход произошел с использованием метода JumpToPositionX (float target). Я думаю, мне нужно как-то вычислить JumpFactor в зависимости от значения цели в методе JumpToPositionX. Я нашел статью в Википедии, но я даже не знаю, с чего начать. Я не нашел примеров того, как это сделать с помощью CharacterController.
public class ExampleClass : MonoBehaviour
{
const float Speed = 6f;
const float JumpFactor = 14f;
const float Gravity = 20f;
private Vector3 moveDirection = Vector3.zero;
CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
if (controller.isGrounded)
{
moveDirection = new Vector3(1f, 0f, 0f); // Move X Direction
moveDirection *= Speed;
if (Input.GetButton("Jump"))
moveDirection.y = JumpFactor;
}
moveDirection.y -= Gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
// Method for jump, calling from other script.
void JumpToPositionX(float target)
{
}
}
Ответ №1:
Теория
Я предполагаю, что вы хотите использовать баллистическую физику.
Давайте посмотрим, какую формулу мы можем использовать
Где :
- V: Скорость
- a: Ускорение
- P: Позиция
- t: время с момента запуска
- 0: Начальный
известно, что это
(0f,-9.81f)
или (0f, Gravity)
в вашем случае.
также известно, что это ваша начальная позиция перед переходом.
это конечная целевая позиция.
Разрешение
Вы должны найти время окончания и начальную скорость
. Итак, вот уравнение положения:
Мы можем упростить процесс, просматривая только ось x, потому что ускорения нет.
упрощается до :
Давайте вычленим из формулы позиции x :
Теперь у вас есть общее время перехода. Вам просто нужно найти начальную скорость y
, используя формулу положения y :
Изолировать Vyo :
Итак, теперь у вас есть вся информация для вычисления перехода: начальная и конечная позиция, общее время, начальная скорость и ускорение.
Реализация
Вот пример моноповедения, которое вы можете создать :
public class JumpBehaviour : MonoBehaviour
{
public CharacterController CharacterController;
public Transform TargetPosition;
private bool jumpStarted = false;
private float totalTime = 0f;
private float t = 0f;
private Vector2 V0;
private Vector2 initialPosition;
private bool jumpKeyDown;
private const float xSpeed = 6f;
private const float gravity = -9.81f;
void Update()
{
jumpKeyDown = Input.GetKeyDown(KeyCode.Space);
}
void FixedUpdate()
{
if (jumpStarted)
{
UpdateJumpPosition(Time.fixedDeltaTime);
}
else if (jumpKeyDown )
{
StartJump();
}
}
private void UpdateJumpPosition(float deltaTime)
{
t = deltaTime;
if(t > totalTime)
{
//End of jump
transform.position = TargetPosition.position;
jumpStarted = false;
return;
}
Vector2 newPosition = new Vector2(0f, gravity) * t * t V0 * t initialPosition;
CharacterController.Move(newPosition);
}
private void StartJump()
{
jumpStarted = true;
initialPosition = transform.position;
// Absolute because xSpeed could be positive or negative. We dont want negative time
float delta = TargetPosition.position.x - transform.position.x;
totalTime = Mathf.Abs(delta / xSpeed);
t = 0f;
float yInitialSpeed = (TargetPosition.position.y - transform.position.y - gravity * totalTime * totalTime) / totalTime;
// Using Sign to set the direction of horizontal movement
V0 = new Vector2(xSpeed * Mathf.Sign(delta), yInitialSpeed);
}
}
Заключение
Это всего лишь краткий пример, позволяющий понять, как вычислить начальное значение перехода и перемещения в 2D. Как сказал дерХуго в комментарии, вы не должны использовать transform.position
прямую атрибуцию с помощью Physic.
Для 3D это та же идея, но вы должны вычислить скорость x, z из целевого направления и величины скорости.
Vector3 delta = TargetPosition - transform.position;
delta.y = 0f;
float direction = delta.normalized;
Vector3 initialSpeed = direction * movementSpeed;
Комментарии:
1. Это хорошо и прекрасно.. НО всякий раз, когда в Unity задействована какая-либо
Rigidbody
(физика), вы НЕ должны изменять или получать доступ к каким-либо значениям черезTransform
компонент (в котором вы это делаетеtransform.position = newPosition;
). Это нарушает физику и все обнаружение столкновений и, следовательно, всю цельCharacterController
😉 То, что вы хотите сделать, это скорее пройти черезcontroller.Move
метод2. ДА. Это всего лишь простой пример, если не требуется никаких физических действий. В противном случае он / она должен адаптировать способ перемещения GameObject, но, по крайней мере, у него / нее есть формула для вычисления положения сверхурочно и начальной скорости.
3. @derHugo Я отредактировал, чтобы добавить больше информации. Как вы думаете, это лучше?
4. Вы правы. Возможно, я добавлю пример с CharacterController.
5. @D.B обратите внимание, что вы все равно должны получать пользовательский ввод (
GetKeyDown
) только вUpdate
, поскольку нельзя гарантировать, что он все еще действителен вFixedUpdate
вызове 😉 Кроме того, я бы все равно получил позицию черезvar xyz = GetComponent<Rigidbody>().position
и установил ее черезGetComponent<Rigidbody>().MovePosition(xyz);
, чтобы не нарушать физику 😉 .. конечно, вы кэшируетеRigidbody
ссылку, как обычно