Verhindern einer Kombination aus Starrkörper-Sprungkraft und Sprunggröße in Unity3D


10

Ich baue ein ziemlich einfaches Marmor-Rennspiel in Unity3D. Der Ball ist ein 3D-Physikobjekt, das sich nur auf der X- und Y-Achse bewegt. Es hat die Fähigkeit, nach links und rechts zu rollen und zu springen. Ziemlich einfaches Zeug, außer dass ich auf ein bahnbrechendes Problem gestoßen bin: Beim Fallen und Schlagen auf den Boden kann die Sprungstärke des Balls mit seiner Sprungkraft kombiniert werden, um einen extra hohen Sprung zu erzielen. Dies bedeutet, dass der Spieler bei gut getimten Tastendrücken dazu führen kann, dass der Ball exponentiell höher springt und unbeabsichtigte Höhen erreicht. Ich kann Levels nicht richtig entwerfen, bis dieser Fehler behoben ist. Ich habe dieses Beispiel illustriert:

Ball Bouncing vs Ball Bouncing + Springen

Das Springen ist jedoch nicht so einfach, wie den Ball gerade nach oben zu schießen. Um das Level-Design komplexer zu gestalten, habe ich den Sprungwinkel so programmiert, dass er relativ zur Oberfläche ist, auf der der Ball rollt.

Vergleich des Ballsprungwinkels

Abbildung 3 in dieser Abbildung zeigt, wie mein Spiel bisher funktioniert. nicht Abbildung 4 . Dies macht das Lösen des Bounce + Jump-Problems viel schwieriger, da ich nicht einfach eine genaue Kraft oder Geschwindigkeit auf der Y-Achse messen und einstellen kann. Dies führt zu einem seltsamen Verhalten, das sich dramatisch bemerkbar macht, wenn sich der Ball auf steileren Hängen bewegt.

Bisher war ich in der Lage, eine Lösung für alle anderen Designprobleme in diesem Spiel zu finden und dann herauszufinden, wie man sie programmiert, aber dieses hat mich festgefahren. Ich habe verschiedene Ansätze versucht, aber keiner von ihnen hat funktioniert.

Hier ist das C # -Skript, das das Springen des Balls steuert:

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

Mein letzter Versuch war, Jump - Rigidbody.velocity.magnitude * 50 zu versuchen , um die Sprungkraft um die Geschwindigkeit zu reduzieren, mit der sich der Ball bewegt . Es löste fast das Bounce + Jump-Problem, indem es die Sprungkraft proportional auf Null reduzierte, als die Geschwindigkeit des Balls das erreichte, was der Geschwindigkeit zu entsprechen schien. Es hat aus dem Stand heraus funktioniert, aber das Problem ist, dass es auch die Größe berücksichtigt, während der Ball geerdet ist, wodurch verhindert wird, dass der Ball mit voller Geschwindigkeit rollt und springt. Ich war nah dran, aber nicht ganz da!

Ich bin ein Anfänger Programmierer, und ich bin hier ratlos. Kann mir jemand helfen, eine kreative Lösung für dieses Problem zu finden? Solange der Spieler in der Lage ist, kontinuierlich höher und höher zu springen und zu springen, kann ich keine Level entwerfen, da sie alle nur betrogen werden können. Ich würde gerne weitermachen - dieses Problem hat mich schon lange zurückgehalten, daher würde ich mich über Ratschläge sehr freuen!


Schöne Frage :) Hast du versucht, mit physischen Materialien herumzuspielen? Sie können die Sprungkraft des Bodens auf Null (oder einen sehr niedrigen Wert) setzen. Vielleicht auch der Spieler, darauf kommt es an.
M156

Antworten:


0

Zunächst möchte ich sagen, dass Ihre Frage sehr gut geschrieben ist und es mir ein Vergnügen ist :) Sie müssten nur das entfernen, was im Code nicht erforderlich ist (Audioquellen usw.), und es wäre perfekt. Prost dafür.

Für die Antwort, könnten Sie klemmen Sie Ihre Geschwindigkeit beim Springen, die Sie erreichen zu hohen Geschwindigkeit beim Drücken der Sprungtaste verhindern würden.


0

Während ich persönlich Hasenhüpfen liebe ... Als Ausgangspunkt sollten wir die beabsichtigte "Sprunggeschwindigkeit" als Delta-Geschwindigkeit kennen. Diese Zahl zeigt den Geschwindigkeitsanstieg (in der Linie mit der "Sprungnormal") während des Momentes des einmaligen Springens.

Jede Geschwindigkeit, die der Spieler bereits im Einklang mit der Sprungnormalen hat, kann als bereits vorhandene "Springenergie" angesehen werden. Dies führt zu einer einfachen Lösung: Die momentane Delta-Geschwindigkeit kann so begrenzt werden, dass der Spieler niemals über die Zielgeschwindigkeit hinaus beschleunigt wird.

Um Ihre bereits vorhandene Sprunggeschwindigkeit zu messen, können wir das Punktprodukt Ihres normalisierten Sprungvektors und die Geschwindigkeit Ihres Spielers verwenden:

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

Die "vorhandene Geschwindigkeit" wird auch hier nicht negativ erzwungen; Wenn der Spieler fällt, wird der Sturz durch eine negative vorhandene Sprunggeschwindigkeit ausgeglichen, sodass er in Luft aufspringen kann, wenn er den Sprung beim Fallen auslöst.

Nachdem wir nun wissen, um wie viel die Delta-Geschwindigkeit genau reduziert werden kann, können wir den effektiven "Sprungvektor" berechnen, indem wir die Sprungnormalen auf die Delta-Zielgeschwindigkeit skalieren.

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

Diesmal wird die angepasste Sprunggeschwindigkeit nicht negativ erzwungen. Wenn der Spieler bereits schneller steigt, als er springen sollte, würde er eine negativ eingestellte Geschwindigkeit erreichen, wodurch er die "Sprung" -Aktion als Bremse verwenden kann. (um sofort auf die vorgesehene Sprunggeschwindigkeit zu verlangsamen!)

Hinweis: Ich glaube, Ihr Kontakt X und Y sind bereits paarweise normalisiert. Der Vollständigkeit halber habe ich jedoch explizite Details angegeben.


0

Diese Antwort ist vielleicht eher eine Designänderung als Sie suchen, aber wie wäre es damit - der Ball hat eine kurze Zeit, nachdem der Sprungknopf gedrückt wurde, wo er fest auf dem Boden bleibt und jeglichen vertikalen Aufwärtsimpuls aufhebt (möglicherweise ein Quetschen a Bit, um eine federartige Kompression zu bezeichnen), springt dann nach Ablauf dieser Zeitspanne nach oben. Dies würde das Problem lösen, dass der Schwung des Sprunges zum Sprung beiträgt, obwohl es den Spielern auch ermöglichen würde, zu steuern, ob sie abprallten oder nur sprangen. Außerdem wird die Sprungfunktion um eine Verzögerung erweitert, die als gut (fühlt sich natürlicher an) oder schlecht (lässt den Spielern nicht genügend Zeit, um zu reagieren) angesehen werden kann.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.