Prevenire una combinazione di forza di salto del corpo rigido e magnitudo di rimbalzo in Unity3D


10

Sto costruendo un gioco di corse in marmo abbastanza semplice in Unity3D. La palla è un oggetto fisico 3D che si muove solo sugli assi X e Y. Ha la capacità di rotolare a sinistra ea destra e di saltare. Roba piuttosto semplice, tranne per il fatto che ho riscontrato un problema di rottura del gioco: quando cadi e colpisci il terreno, l'entità di rimbalzo della palla può essere combinata con la sua forza di salto per creare un salto extra-alto. Ciò significa che, con una pressione dei pulsanti tempestiva, il giocatore può far rimbalzare esponenzialmente la palla, raggiungendo altezze non intenzionali. Non riesco a progettare correttamente i livelli fino a quando questo problema tecnico non viene risolto. Ho illustrato questo esempio:

Ball Bouncing vs Ball Bouncing + Jumping

Il salto, tuttavia, non è così semplice come sparare la palla verso l'alto. Per facilitare una maggiore complessità nella progettazione del livello, ho programmato che l'angolo di salto sia relativo alla superficie su cui sta rotolando la palla.

Confronto dell'angolo di salto della palla

La figura 3 , in quella illustrazione, mostra come funziona il mio gioco finora; non figura 4 . Questo rende la risoluzione del problema bounce + jump molto più impegnativa, perché non riesco semplicemente a misurare e impostare una forza o velocità esatta sull'asse Y. In questo modo si ottiene un comportamento strano, che diventa notevolmente più evidente quando la palla viaggia su pendenze più ripide.

Finora sono stato in grado di concepire una soluzione a tutti gli altri problemi di progettazione in questo gioco e poi scoprire come programmarli, ma questo mi ha bloccato. Ho tentato una serie di approcci diversi, ma nessuno di loro ha funzionato.

Ecco lo script C # che controlla il salto della palla:

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();
        }
    }
}

Il mio ultimo tentativo è stato quello di provare a saltare - rigidbody.velocity.magnitude * 50 , per ridurre la potenza di salto della velocità con cui la palla sta viaggiando. Ha quasi risolto il problema di rimbalzo + salto, riducendo proporzionalmente la forza di salto fino a zero quando la velocità della palla ha raggiunto quello che sembrava essere l'equivalente in velocità. Ha funzionato da fermo, ma il problema è che spiega anche la grandezza mentre la palla è messa a terra, impedendo alla palla di rotolare a tutta velocità e saltare. Ero vicino, ma non del tutto lì!

Sono un programmatore alle prime armi, e sono perplesso qui. Qualcuno può aiutarmi a trovare una soluzione creativa a questo problema? Finché il giocatore è in grado di rimbalzare continuamente e saltare sempre più in alto, non posso progettare alcun livello, perché saranno tutti in grado di essere imbrogliati. Mi piacerebbe andare avanti - questo problema mi ha trattenuto per molto tempo, quindi apprezzerei molto alcuni consigli!


Bella domanda :) hai provato a giocare con materiali fisici? È possibile impostare lo zero del terreno a zero (o un valore molto basso). Forse anche il giocatore, dipende.
M156,

Risposte:


0

Prima di tutto, voglio dire che la tua domanda è scritta molto bene ed è un piacere :), dovrai solo rimuovere ciò che non è necessario nel codice (fonti audio, ecc.) E sarebbe perfetto. Saluti per quello.

Per la risposta, potresti bloccare la velocità quando salti, il che ti impedirebbe di raggiungere velocità troppo elevate quando premi il pulsante di salto.


0

Mentre io personalmente adoro il bunny hopping ... Come punto di partenza dovremmo conoscere la "Jump Speed" come velocità delta. Questa figura rappresenta l'aumento di velocità (in linea con "Jump Normal") durante l'istante di salto una volta.

Qualsiasi velocità che il giocatore ha già in linea con il Jump Normal può essere vista come una "Jump Energy" preesistente. Questo porta a una soluzione semplice: la velocità delta istantanea può essere limitata in modo tale da non accelerare il giocatore oltre la velocità target.

Per misurare la tua velocità di salto preesistente, possiamo prendere il prodotto punto del tuo vettore di salto normalizzato e la velocità del tuo giocatore:

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

Anche la "velocità esistente" è forzata in modo non negativo; Quando il giocatore sta cadendo, una velocità di salto esistente negativa compenserà la sua caduta, permettendo loro di rimbalzare sul nulla se innescano il salto durante la caduta.

Ora che sappiamo quanto ridurre con precisione la velocità delta, possiamo calcolare l'effettivo "Jump Vector" ridimensionando il Jump Normal alla velocità delta target.

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

Questa volta la velocità di salto adattata viene forzata non negativa; Se il giocatore si sta già alzando più velocemente di quanto dovrebbe essere in grado di saltare, otterrebbero una velocità regolata negativa, che consente loro di usare l'azione "salta" come freni. (per rallentare istantaneamente alla velocità di salto prevista!)

Nota: credo che i tuoi contatti X e Y siano già normalizzati in coppia. Ho incluso dettagli espliciti per completezza però.


0

Questa risposta è forse più un cambiamento di design di quello che stai cercando, ma che ne dici di questo - la palla ha un breve periodo dopo che il pulsante di salto è premuto dove rimane saldamente a terra e annulla qualsiasi momento verticale verso l'alto (forse schiacciando un un po 'per indicare una compressione simile a una molla), quindi salta verso l'alto dopo che quel periodo si è concluso. Ciò risolverebbe il problema del momento del rimbalzo che si aggiunge al salto, anche se consentirebbe anche ai giocatori di controllare se sono rimbalzati o semplicemente saltati. Aggiunge anche un ritardo alla funzione di salto, che può essere vista come buona (sembra più naturale) o cattiva (non consente ai giocatori abbastanza tempo per rispondere).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.