Mencegah Kombinasi Kekuatan Lompat Tegak & Besar Bouncing di Unity3D


10

Saya sedang membangun game balap marmer yang cukup sederhana di Unity3D. Bola adalah objek fisika 3D yang hanya bergerak pada sumbu X dan Y. Ia memiliki kemampuan untuk berguling ke kiri dan ke kanan, dan untuk melompat. Hal-hal yang cukup mendasar, kecuali bahwa saya telah memecahkan masalah: Ketika jatuh dan menyerang tanah, bouncing magnitude bola dapat dikombinasikan dengan kekuatan lompatnya untuk menciptakan lompatan ekstra tinggi. Ini berarti bahwa, dengan penekanan tombol yang tepat waktu, pemain dapat menyebabkan bola memantul secara eksponensial lebih tinggi, mencapai ketinggian yang tidak diinginkan. Saya tidak dapat mendesain level dengan baik sampai kesalahan ini diperbaiki. Saya telah menggambarkan contoh ini:

Bola Memantul vs Bola Memantul + Melompat

Melompat, bagaimanapun, tidak sesederhana hanya menembakkan bola lurus ke atas. Untuk memfasilitasi lebih banyak kerumitan dalam desain level, saya telah memprogram sudut lompatan agar relatif terhadap permukaan tempat bola bergulir.

Perbandingan Sudut Lompat Bola

Gambar 3 , dalam ilustrasi itu, adalah bagaimana permainan saya bekerja sejauh ini; bukan Gambar 4 . Ini membuat pemecahan untuk masalah bouncing + lompat jauh lebih menantang, karena saya tidak bisa hanya mengukur dan mengatur kekuatan atau kecepatan yang tepat pada sumbu Y. Melakukannya menghasilkan perilaku aneh, yang menjadi jauh lebih terlihat ketika bola bergerak di lereng yang lebih curam.

Sejauh ini, saya sudah bisa memikirkan solusi untuk semua masalah desain lainnya dalam game ini dan kemudian mencari tahu bagaimana memprogramnya, tetapi yang satu ini membuat saya macet. Saya telah mencoba sejumlah pendekatan yang berbeda, tetapi tidak satupun yang berhasil.

Inilah skrip C # yang mengontrol lompatan bola:

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

Upaya terakhir saya adalah mencoba melompat - rigidbody.velocity.magnitude * 50 , untuk mengurangi kekuatan lompatan dengan kecepatan bola melakukan perjalanan. Itu hampir memecahkan masalah bouncing + lompatan, dengan secara proporsional mengurangi gaya lompat turun ke nol ketika kecepatan bola mencapai apa yang tampaknya setara dalam kecepatan. Ini bekerja dari macet, tetapi masalahnya adalah, ia juga menghitung besarnya saat bola di-ground, mencegah bola bergulir dengan kecepatan penuh dan melompat. Saya dekat, tetapi tidak cukup di sana!

Saya seorang programmer pemula, dan saya bingung di sini. Adakah yang bisa membantu saya menemukan solusi kreatif untuk masalah ini? Selama pemain dapat terus melambung dan melompat semakin tinggi, saya tidak bisa mendesain level apa pun, karena mereka semua hanya bisa ditipu. Saya ingin terus maju - masalah ini telah menahan saya sejak lama, jadi saya sangat menghargai beberapa saran!


Pertanyaan yang bagus :) apakah Anda mencoba bermain-main dengan materi fisik? Anda dapat mengatur guncangan tanah ke nol (atau nilai yang sangat rendah). Mungkin juga pemainnya, itu tergantung.
M156

Jawaban:


0

Pertama-tama, saya ingin mengatakan bahwa pertanyaan Anda ditulis dengan sangat baik dan menyenangkan :), Anda hanya perlu menghapus apa yang tidak perlu dalam kode (sumber audio, dll.) Dan itu akan menjadi sempurna. Sorakan untuk itu.

Untuk jawabannya, Anda bisa menjepit kecepatan Anda saat melompat, yang akan mencegah Anda mencapai kecepatan terlalu tinggi saat menekan tombol melompat.


0

Sementara saya pribadi suka kelinci melompat ... Sebagai titik awal kita harus tahu "Kecepatan Lompat" yang dimaksudkan sebagai kecepatan delta. Angka ini mewakili peningkatan kecepatan (sejalan dengan "Lompat Normal") selama lompatan instan satu kali.

Kecepatan apa pun yang sudah dimiliki pemain sesuai dengan Jump Normal dapat dilihat sebagai "Energi Langsung" yang sudah ada sebelumnya. Ini mengarah ke solusi langsung: Kecepatan delta sesaat dapat dibatasi sehingga tidak pernah mengakibatkan pemain dipercepat melampaui kecepatan target.

Untuk mengukur Kecepatan Lompat Anda yang sudah ada sebelumnya, kami dapat mengambil produk titik dari vektor Lompat Anda yang dinormalisasi, dan kecepatan pemain Anda:

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

"Kecepatan Yang Ada" juga dipaksa non-negatif di sini; Ketika pemain jatuh, kecepatan lompatan negatif yang ada akan mengkompensasi jatuh mereka, memungkinkan mereka untuk bangkit di udara tipis jika mereka memicu lompatan saat jatuh.

Sekarang kita tahu berapa banyak untuk mengurangi kecepatan delta secara tepat, kita dapat menghitung "Jump Vector" yang efektif dengan menskalakan Jump Normal ke kecepatan delta target.

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

Kali ini Kecepatan Lompat Disesuaikan dipaksa non-negatif; Jika pemain sudah naik lebih cepat dari yang seharusnya bisa melompat, mereka akan mencapai kecepatan yang disesuaikan negatif, yang memungkinkan mereka untuk menggunakan aksi "melompat" sebagai rem. (untuk memperlambat ke kecepatan lompatan yang dimaksudkan secara instan!)

Catatan: Saya yakin kontak Anda X dan Y sudah dinormalisasi sebagai pasangan. Saya menyertakan detail eksplisit demi kelengkapan.


0

Jawaban ini mungkin lebih merupakan perubahan desain daripada yang Anda cari, tetapi bagaimana dengan ini - bola memiliki periode singkat setelah tombol lompatan ditekan di mana ia tetap kokoh di tanah dan membatalkan momentum vertikal ke atas (mungkin menekan sebuah bit untuk menunjukkan kompresi seperti pegas), lalu melompat ke atas setelah periode tersebut selesai. Ini akan memecahkan masalah momentum pantulan yang menambah lompatan, meskipun itu juga akan memungkinkan pemain untuk mengontrol apakah mereka melambung atau hanya melompat. Ini juga menambahkan penundaan pada fungsi lompatan, yang dapat dilihat sebagai baik (terasa lebih alami) atau buruk (tidak memberikan waktu yang cukup bagi pemain untuk merespons).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.