Предотвращение сочетания силы прыжка твердого тела и величины отскока в Unity3D

10

Я строю довольно простую гоночную игру на мраморе в Unity3D. Шар - это трехмерный физический объект, который движется только по осям X и Y. Имеет возможность катиться влево и вправо и прыгать. Довольно простые вещи, за исключением того, что я столкнулся с проблемой, разрушающей игру: при падении и ударе о землю, величина отскока мяча может быть объединена с его силой прыжка, чтобы создать сверхвысокий прыжок. Это означает, что при своевременном нажатии кнопки игрок может заставить мяч отскочить в геометрической прогрессии выше, достигнув непреднамеренной высоты. Я не могу правильно проектировать уровни, пока этот глюк не исправлен. Я проиллюстрировал этот пример:

Отскок мяча от прыгающего мяча + прыжки

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

Сравнение углов прыжка

На рисунке 3 показано, как моя игра работает до сих пор; не рисунок 4 . Это делает решение проблемы прыжок + прыжок гораздо более сложным, потому что я не могу просто измерить и установить точную силу или скорость на оси Y. Это приводит к странному поведению, которое становится значительно более заметным, когда мяч движется по более крутым склонам.

До сих пор мне удавалось придумать решение всех других проблем дизайна в этой игре, а затем узнать, как их программировать, но я застрял в этой. Я пробовал несколько разных подходов, но ни один из них не сработал.

Вот скрипт C #, который контролирует прыжок мяча:

using UnityEngine;
using System.Collections;

public class BallJumping : MonoBehaviour {

    public System.Action onJump;
    public Rigidbody objRigidbody; // Set this to the player
    public bool isGrounded; // Determines whether or not the ball is on the ground
    public Transform groundChecker; // A child object that's slightly larger than the ball
    public float groundRadius = 0.6f;
    public LayerMask whatIsGround; // Determines what layers qualify as ground
    public AudioClip jumpSFX;
    public AudioClip stickyJumpSFX;
    private float p_WillJumpTimeRemaining; // Grace periods before/after hitting the ground to trigger jump
    private float p_CanJumpTimeRemaining;
    public float earlyJumpToleranceDuration = 0.2f;
    public float lateJumpToleranceDuration = 0.2f;
    public float jump = 500f; // Jumping power
    private float halfJump = 250f; // Used for the sticky puddles
    public bool stuck = false; // Used for sticky materials
    private float contactX;
    private float contactY;


    // Input for jumping
    void Update () {
        if (Input.GetButtonDown ("Jump") && isGrounded == true) {
            ProcessJump();
        }
    }


    // Continuously checks whether or not the ball is on the ground
    void FixedUpdate () {
        if (Physics.CheckSphere (groundChecker.position, groundRadius, whatIsGround) == true) {
            isGrounded = true;
        } else {
            isGrounded = false;
        }
    }


    // Sets a grace period for before or after the ball contacts the ground for jumping input
    void ProcessJump () {
        bool boolGetJump = Input.GetButtonDown("Jump");

        if (boolGetJump && isGrounded == false) {
            p_WillJumpTimeRemaining = earlyJumpToleranceDuration;
        } else {
            if (p_WillJumpTimeRemaining > 0) {
                p_WillJumpTimeRemaining -= Time.fixedDeltaTime;
            }
        }

        if (isGrounded) {
            p_CanJumpTimeRemaining = lateJumpToleranceDuration;
        }

        if (isGrounded || p_WillJumpTimeRemaining > 0) {
            Jump();
        }

        if (p_CanJumpTimeRemaining > 0) {
            p_CanJumpTimeRemaining -= Time.fixedDeltaTime;
        }
    }


    // Sticky puddles script -- hinders jumping while in the puddle
    void OnTriggerEnter (Collider collision) {
        if (collision.gameObject.tag == "Sticky") {
            stuck = true;
        }
    }

    void OnTriggerExit (Collider collision) {
        if (collision.gameObject.tag == "Sticky") {
            stuck = false;
        }
    }


    // Calculates the normals for the jump angle
    void OnCollisionStay (Collision collision) {
        Debug.Log ("Collision.");
        foreach (ContactPoint contact in collision.contacts) {
            contactX = contact.normal.x;
            contactY = contact.normal.y;
        }
    }


    // Controls jumping
    void Jump() {
        Debug.Log ("Jump.");
        p_WillJumpTimeRemaining = 0.0f;
        p_CanJumpTimeRemaining = 0.0f;
        halfJump = jump * 0.5f; // Cuts jumping force in half while in a sticky puddle

        GetComponent<AudioSource>().volume = 1;
        GetComponent<AudioSource>().pitch = Random.Range (0.9f, 1.1f);

        if (stuck == false) {
            objRigidbody.AddForce (contactX * jump, contactY * jump, 0);
            GetComponent<AudioSource>().clip = jumpSFX;
            GetComponent<AudioSource>().Play ();
        }
        else if (stuck == true) {
            objRigidbody.AddForce (contactX * halfJump, contactY * halfJump, 0);
            GetComponent<AudioSource>().clip = stickyJumpSFX;
            GetComponent<AudioSource>().Play ();
        }


        if (onJump != null) {
            onJump();
        }
    }
}

Моя последняя попытка состояла в том, чтобы попробовать прыжок - solidbody.velocity.magnitude * 50 , чтобы уменьшить силу прыжка на скорость, с которой движется мяч. Он почти решил проблему прыжок + прыжок, пропорционально уменьшив силу прыжка до нуля, когда скорость мяча достигла того, что казалось эквивалентным по скорости. Он работал с нуля, но проблема в том, что он также учитывает величину, когда мяч заземлен, не давая мячу катиться на полной скорости и прыгать. Я был близко, но не совсем там!

Я начинающий программист, и я в тупике. Может ли кто-нибудь помочь мне найти творческое решение этой проблемы? Пока игрок может непрерывно подпрыгивать и прыгать все выше и выше, я не могу проектировать какие-либо уровни, потому что все они будут в состоянии быть обманутыми. Я хотел бы двигаться дальше - эта проблема долго сдерживала меня, поэтому я был бы очень признателен за некоторые советы!

выкуп
источник
Хороший вопрос :) Вы пробовали играть с физическими материалами? Вы могли бы установить бодрость земли на ноль (или очень низкое значение). Может быть, также игрок, это зависит.
M156

Ответы:

0

Прежде всего, я хочу сказать, что ваш вопрос очень хорошо написан, и это приятно :), вам просто нужно удалить то, что не нужно в коде (аудиоисточники и т. Д.), И это было бы идеально. Приветствия для этого.

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

Bluk
источник
0

В то время как я лично люблю прыжки кролика ... В качестве отправной точки мы должны знать предполагаемую «скорость прыжка» как дельта-скорость. Эта цифра представляет увеличение скорости (в линии с «нормальным прыжком») в момент прыжка один раз.

Любая скорость, которую игрок уже имеет в соответствии с нормой прыжка, может рассматриваться как существующая «энергия прыжка». Это приводит к прямому решению: мгновенная дельта-скорость может быть ограничена так, что она никогда не приводит к ускорению игрока сверх целевой скорости.

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

Vector2 JumpNormal = Vector2(contactX, contactY).normalized;
Vector2 PlayerVelocity = objRigidbody.velocity;
float ExistingSpeed = Vector2.Dot(PlayerVelocity, JumpNormal);
if (ExistingSpeed < 0) ExistingSpeed = 0;

«Существующая скорость» также здесь принудительно неотрицательна; Когда игрок падает, существующая отрицательная скорость прыжка компенсирует его падение, позволяя ему подпрыгивать на воздухе, если он запускает прыжок во время падения.

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

float AdjustedSpeed = JumpSpeed - ExistingSpeed;
if (AdjustedSpeed < 0) AdjustedSpeed = 0;
Vector2 JumpVector = JumpNormal * AdjustedSpeed;
objRigidbody.velocity += JumpVector;

На этот раз скорректированная скорость прыжка принудительно неотрицательна; Если игрок уже поднимается быстрее, чем он должен быть в состоянии прыгнуть, он достигнет отрицательно скорректированной скорости, что позволяет ему использовать действие «прыжка» в качестве тормоза. (чтобы мгновенно замедлиться до намеченной скорости прыжка!)

Примечание: я считаю, что ваши контакты X и Y уже нормализованы как пара. Я включил явные детали для полноты ради хотя.

MickLH
источник
0

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

Bynine
источник