@j1mie

Как сделать проверку на землю под ногами(Unity 2d)?

Я новичек в C# и у меня не получается сделать проверку на землю под персонажем, чтобы игрок не мог бесконечно прыгать. Логически я понимаю как ее сделать, но знаний самого языка не хватает. Помогите пожалуйста
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    Rigidbody2D rb;
    [SerializeField] public float speed = 10f;
    [SerializeField] public float jumpForce = 14f;
    

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

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            Jump();
        }

        
    }

    void FixedUpdate()
    {
        rb.velocity  = new Vector2(Input.GetAxis("Horizontal") * speed, rb.velocity.y);
    }

    void Jump()
    {
        rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
    }

   


}
  • Вопрос задан
  • 423 просмотра
Решения вопроса 1
@Ezekiel4
Охотник на пиратов и сборщик монолитов
Способов проверить наличие земли много, вопрос в конкретной игре. Самый простой - проверить столкновение коллайдеров.
иллюстрация1
63d2302016761335903485.png

Стандартные скрипты сверху имеют сигнатуру вида
public class [название] : MonoBehaviour.
MonoBehaviour - это специальный скрипт, дающий возможность нашему использовать некоторые стандартные методы, например:
void OnCollisionEnter2D(Collision2D c) {
	Debug.Log(c.gameObject.name); // выводит в консоль название объекта, с которым владелец скрипта столкнулся
}

Минус подхода в том, что ваш объект будет считать столкновениями в том числе и удары головой о потолок, что не очень сходится с задачей. В таком случае поступают иначе - создают в иерархии персонажа пустую точку, затем вокруг неё в коде ищут определённые поверхности. Выглядит обычно как-то так или так:
иллюстрация2
63d231f8302fc690248078.png

Код же будет выглядеть как-то так:
код
// поля класса
public Transform groundCheckPoint;
public float range;
public LayerMask groundLayers;

// сама инструкция
bool isGrounded = Physics2D.OverlapCircle(groundCheckPoint.position, range, groundLayers);

// в вашем коде имеет смысл как-то так сделать
void Jump() {
	if(Physics2D.OverlapCircle(groundCheckPoint.position, range, groundLayers))
		rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
}


Пара непрошенных советов для начинающему коллеге по цеху

Инструкции вида
[SerializeField] public float speed = 10f;
[SerializeField] public float jumpForce = 14f;

Не имеют смысла, так как оператор доступности public и так делает вашу переменную видимой в инспекторе, поэтому использование атрибута избыточно. Хуже не делает, просто бессмысленно. Атрибуты больше нужны, чтобы задать специфическое поведение для удобства редактирования игры. Например, вы не хотите давать другим классам прямой доступ к изменению скорости бега и силы прыжка персонажа - ставите приват, но чтобы в редакторе можно было потестить и выставить нужные значения (вы же не экстрасенс, чтобы с первого раза угадать), добавляют атрибут и получается:
[SerializeField] private float speed = 10f;
[SerializeField] private float jumpForce = 14f;


Второе уже относится больше к здравому смыслу - все запросы ввода лучше делать внутри Update, а обеспечением их доступности для метода FixedUpdate должна заниматься внутренняя переменная класса, типа:
private float xInput;

private void Update() {
	xInput = Input.GetAxis("Horizontal");
	// code
}

private void FixedUpdate() {
	rb.velocity = new Vector2(xInput * speed, rb.velocity.y);
}

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

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

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