В первой части мы добавили нашему игроку некоторые базовые прыжки и движения, а теперь мы добавим несколько трюков к нашим прыжкам, чтобы убедиться, что они красивые и отточенные.

Буферизация перехода

Буферизация прыжка — это метод, при котором мы сохраняем время, когда игрок в последний раз нажимал кнопку прыжка, и если мы касаемся земли меньше, чем, скажем, за несколько кадров, мы выполняем команду, так что игроку предоставляется некоторая свобода действий.

Для начала мы хотим добавить в наш предыдущий скрипт движения персонажа следующие переменные:

public float jumpBufferTime;
...
private float lastJmpTime;

Наш jumpBufferTime будет содержать, сколько времени в секундах может пройти между игроком, нажимающим прыжок, и фактическим выполнением действия. lastJmpTime — это время, когда мы последний раз нажимали кнопку прыжка. Что касается кода, после строки groundedPlayer = valid_colliders > 0; добавьте следующий код, чтобы установить время, когда мы последний раз нажимали кнопку перехода:

if (Input.GetButtonDown("Jump")) {
    lastJmpTime = Time.time;
}

Затем сразу после if (groundedPlayer) { замените if (Input.GetButtonDown("Jump")) { в следующей строке на if (lastJmpTime > Time.time — jumpBufferTime) { . Это, по сути, вопрос: больше ли время между последним нажатием кнопки прыжка и текущим моментом, чем jumpBufferTime?, где время буфера прыжка — это, очевидно, переменная, которую мы установили как максимальное время между прыжками.

Внутри инспектора (обратите внимание, я установил гравитацию -13,5 и высоту прыжка 5), установите большое значение, например 1, чтобы вы могли проверить, работает ли оно, а затем установите его на что-то более низкое (я предлагаю 0,1 или 0,2), чтобы он не заметно, но щадящий эффект все же присутствует.

Переменная высота прыжка и ускорение вершины

Сначала давайте создадим несколько логических значений, чтобы отслеживать, на каком этапе прыжка мы находимся, а также создадим значение с плавающей запятой, чтобы отслеживать, как далеко мы прыгнули в данный момент:

public float minJumpHeight; // minimum height to jump
public float apexBoost; // amount by which to boost player at apex
public float apexBoostTime; // How much time our boost lasts
public float apexDamping; // how much we damp a premature jump release
...
private float jmpHeight; // what our current jump height is
private bool startedJump; // have we started our jump
private bool releasedJump; // have we released the jump button
private bool finishedJump; // did we finish the jump
private bool apex; // have we reached the apex

Сразу после if (groundedPlayer) { добавляем startedJump = false;, так как мы только что закончили прыжок.

Затем внутри блока if (lastJmpTime > …) {добавьте следующий код:

releasedJump = false; // it's as if we just clicked jump
finishedJump = false; // we just started our jump
startedJump = true; // yes, the jump has started

В разделе else нашего if (groundedPlayer) { нам нужно добавить следующий код после playerVel.y += gravity * Time.deltaTime;:

jmpHeight += playerVel.y * Time.deltaTime; // add by how much we changed our y
// if we release the button, set the boolean
if (!releasedJump && Input.GetButtonUp("Jump")) 
    releasedJump = true;
}
// if we reached max height
if (!finishedJump && jmpHeight >= jumpHeight) {
    finishedJump = true;
    playerVel.y = 0f; // antigrav moment, no damping as true height reached
    apex = apexBoostTime; // apex reached
}
// we released jump prematurely, and we have already reached minimum height
if (releasedJump && !finishedJump && jmpHeight > minJumpHeight) {
    releasedJump = false; // reset our jump release
    finishedJump = true;
    playerVel.y = apexDamping; // moment of antigravity with some damping
    apex = apexBoostTime; // lower apex, but apex reached nonetheless
}

Затем нам нужно воздействовать на наше повышение вершины, что мы сделаем в верхней части нашей функции обновления выше gameObject.transform.position += playerVel.x…как часть следующего кадра:

if (apex > 0) {
    playerVel.x *= apexBoost;
    apex -= Time.deltaTime; // decrease by time on frame
}

Теперь в инспекторе установите значения по своему вкусу. Я использовал минимальную высоту прыжка 1, ускорение вершины 1,2, время ускорения вершины 0,1 и демпфирование вершины 5.

время койота

Время койота, названное в честь определенного мультяшного персонажа, — это время, когда мы позволяем пользователю ввести действие прыжка после того, как он покинет платформу. Это еще раз обеспечивает снисходительность к пользователю и помогает облегчить игровой процесс.

Для начала добавим наши переменные:

public float coyoteTime; // how much time after leaving the platform
...
private float lastLeaveTime; // time we last left a platform
private bool lastGrounded; // where we grounded in the last frame?

Затем в верхней части нашего оператора else для if (groundedPlayer) { добавьте

if (lastGrounded) {
    lastLeaveTime = Time.time;
}

Это установит время нашего последнего ухода через кадр после того, как мы покинули землю. Затем нам нужно проверить, была ли кнопка перехода нажата сразу после этого утверждения. Мы не используем буфер перехода, потому что он никогда не понадобится. Мы проверяем, нажата ли она и меньше ли разница во времени между текущим моментом и временем нашего последнего ухода, чем наше coyoteTime, и делаем то же самое, что и обычно:

if (Input.GetButtonDown("Jump") && lastLeaveTime > Time.time - coyoteTime) {
    releasedJump = false;
    finishedJump = false;
    startedJump = true;
    playerVel.y += Mathf.Sqrt(jumpHeight*-2.0f*gravity);
}

Наконец, установите lastGrounded = groundedPlayer; под всеми операторами if в нижней части нашей функции обновления.

Не забудьте установить coyoteTime в инспекторе (я установил его на 0,2). И вот мы идем! Время койота подошло к концу!

Прохождение через платформы

Наконец, мы должны добавить код для прохождения через платформы снизу, так как в настоящее время простой прыжок вверх приводит к тому, что персонаж застревает в платформе и набирает обороты.

Во-первых, добавьте переменную public float passThroughOffset; в начало вашего моноповедения.

Для начала давайте добавим следующий код под if (collider.gameObject.tag != “platform”) continue; внутри нашего цикла foreach:

// current gameobject
GameObject platform = collider.gameObject;
// the platforms size
Vector2 psz = platform.transform.localScale;
// The platform's collider's size
Vector2 csz = platform.GetComponent<BoxCollider2D>().size * psz;
// the platform's collider's offset
Vector2 off = platform.GetComponent<BoxCollider2D>().offset * psz;
// the platform's collider top y position
float ypos = platform.transform.position.y + off.y + csz.y/2;

Затем мы хотим проверить платформу только в том случае, если проверка земли нашего персонажа находится выше ее нижнего края: if (groundCheck.position.y <= ypos — csz.y) continue;

Затем мы проверяем, не застряли ли мы внутри коллайдера объекта, и, таким образом, телепортируем нас так, чтобы мы отдыхали поверх коллайдера, а не внутри, мы сбрасываем наш lastJmpTime и возвращаем текущий кадр, поэтому пропускаем его. :

if (groundCheck.position.y < ypos) {
    // preserve the current x and z coordinates:
    gameObject.transform.position =     gameObject.transform.position.x*Vector3.right + gameObject.transform.position.z*Vector3.forward;
// teleport such that our groundCheck is barely above the top
    // edge of the collider:
    gameObject.transform.position += Vector3.up * (ypos + (transform.position.y - groundCheck.position.y) + passThroughOffset);
    // NOTE that throughout we have multiplied with Vector3.up etc, so that only the x, y or z value gets added respectively.
    lastJmpTime = 0;
    return;
}

Не забудьте установить для passThroughOffset значение по вашему выбору (я использовал 0,1). И теперь мы должны иметь возможность проходить через платформы, как это часто бывает в файтингах!

Наконец, я добавил несколько (ненужных) анимаций, чтобы сделать движение более плавным. Несмотря на то, что позже они будут заменены реальными спрайтами персонажей, я оставляю читателю в качестве упражнения попробовать и выяснить, как это сделать:

Приближается…

В части 3 мы (надеюсь) добавим:

  • Мульти-прыжок
  • захват уступа
  • Лихой

Мы надеемся, что драки появятся в 4-й части этой серии. А пока, пожалуйста, делитесь, ставьте лайки, комментируйте и подписывайтесь на меня, чтобы я знала, как сделать больше из этой серии!