Как сделать плавным прыжок С# unity?

Пытаюсь сделать плавный прыжок для своего персонажа. Сам прыжок делаю с помощью AddForce.

if (Input.GetKeyDown(KeyCode.Space) && !inAir)  // !inAir служит проверкой на земле ли персонаж или нет, условие проходит, проблема именно в прыжке
        {
            inAir = true;
            rb.AddForce(force, ForceMode2D.Impulse); // force - переменная типа Vector2
        }


Пробовал разные способы которые нашёл в интернете, умножение на Time.deltaTime, пробовав изменить импульс на Time.deltaTime, отслеживал нажатие в FixedUpdate() вместо Update() и используя Time.FixedDeltaTime. Впрочем, ни один из способов не увенчался успехом. Подскажите как исправить данную проблему?
  • Вопрос задан
  • 743 просмотра
Решения вопроса 2
@Unitizer
У персонажа в Rigidbody поле Mass если увеличить не помогает? Чтобы потяжелее был.
Видел совет ещё менять силу притяжения в настройках физики Edit\Project Settings, вкладка Physics поле Gravity. Если 2D игра то вкладка Physics 2D.

Еще посоветую поглядеть ролики на ютуб канале "Eccentric Games".
Там хороший цикл роликов про физику, разбираются какие-то проблемы.
Также есть ролики "ПОЧЕМУ ВСЕ ТРЯСЕТСЯ в UNITY ?" и "Эффект растяжения-сжатия в Unity", возможно тоже полезные идеи там будут.
Ответ написан
Комментировать
@Ezekiel4
Охотник на пиратов и сборщик монолитов
Главный вопрос в том, что вы подразумеваете под плавностью прыжка?

Вы можете задать траектории прыжка с помощью AnimationCurve и в IEnumerator плавно применять нужные силы или смещения - таким образом у вас будет удобный внешний интерфейс, где вы сможете сделать просто что угодно.
Вот тут пример, как такое можно сделать - https://www.youtube.com/watch?v=zprbOhxHPXE

С другой стороны, возможно, сейчас ваш прыжок ведёт себя как-то не так. Не видя остального кода, могу лишь предположить, что, например, персонаж прыгает аномально быстро, почти телепортируясь, а падает крайне медленно. Если у вас всё действительно так, то проблема не в прыжке, а в движении, а точнее вертикальной его координате. Возможно, вы используете что-то типа:
rb.velocity = Vector2.right * xInput * movementSpeed;

или
rb.velocity = new Vector2(xInput * movementSpeed, 0);

Если я угадал, то тут проблема в обнулении Y координаты движения. Типа вы перегружаете X, что даёт движение, а всё Y движение обнуляется (гравитация, прыжок). Можно сделать вот так:
rb.velocity = new Vector2(xInput * movementSpeed, rb.velocity.y);


Непрошенный совет

Пробовал разные способы которые нашёл в интернете, умножение на Time.deltaTime, пробовав изменить импульс на Time.deltaTime, отслеживал нажатие в FixedUpdate() вместо Update() и используя Time.FixedDeltaTime. Впрочем, ни один из способов не увенчался успехом. Подскажите как исправить данную проблему?

1. Параметр Time.deltaTime - это временной промежуток между последним и текущим кадром. Умножая на него, например, скорость, вы говорите коду, что хотите сделать привязку скорости не к кадрам (столько-то метров за кадр), а к секундам (столько же метров, но уже за секунду). Это довольно удобно, когда вы делаете физическую симуляцию игре.
2. У прыжка есть два режима (Force и Impulse). Force обычно используется для продолжительных воздействий. Например, с её помощью можно реализовать занос в гонках. А Impulse нужна для разового приложения силы - разгон пули, удар по мячу, прыжок, и т.д.
3. Функция отслеживания нажатий. Используйте для этого всегда Update, вместо FixedUpdate. Дело в том, что класс Input предоставляет информацию, которая опирается именно на период обновления экрана (ему соответствует Update). Например, вот в этом кадре вы нажали пробел и продолжаете удерживать кнопку вправо. FixedUpdate же лучше использовать для применения постоянных сил (вроде движения).
Просто из-за разного периода работы вполне может быть такая ситуация, что ваш ввод просто потеряется или, наоборот, данные о нём останутся на следующую итерацию приложения сил, когда игрок уже перестал нажимать. Чтобы переносить данные между ними, воспользуйтесь полем класса.

Вот примерно так будет выглядеть простое движение с Rigidbody2D:
using UnityEngine;

[RequireComponent(typeof(Rigidbody2D))]
[DisallowMultipleComponent]
public class PlayerMovementDemo : MonoBehaviour {

	private Rigidbody2D _Controller;
	private float _MovementInput;

	public float movementSpeed;
	public float jumpingForce;
	[Space(10)]
	public Transform groundCheckPoint;
	public float groundCheckDistance;
	public LayerMask groundIdentity;

	private void Start() {
		_Controller = GetComponent<Rigidbody2D>();
	}

	private void Update() {
		_MovementInput = Input.GetAxis("Horizontal");

		if (Input.GetButtonDown("Jump") && IsGrounded())
			_Controller.AddForce(Vector2.up * jumpingForce, ForceMode2D.Impulse);
	}

	private void FixedUpdate() {
		_Controller.velocity = new Vector2(_MovementInput * movementSpeed, _Controller.velocity.y);
	}

	private bool IsGrounded() {
		return Physics2D.OverlapCircle(groundCheckPoint.position, groundCheckDistance, groundIdentity);
	}
}

Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы