Unity3Dでの剛体ジャンプ力とバウンスの大きさの組み合わせの防止


10

Unity3Dでかなりシンプルな大理石のレーシングゲームを構築しています。ボールは、X軸とY軸上でのみ移動する3D物理オブジェクトです。左右に転がったりジャンプしたりする能力があります。ゲームを壊す問題に遭遇したことを除いて、かなり基本的なものです:落下して地面に当たったとき、ボールのバウンスの大きさをそのジャンプ力と組み合わせて、超高ジャンプを作成できます。つまり、適切なタイミングでボタンを押すと、プレーヤーはボールを急激に跳ね上げ、意図しない高さに達する可能性があります。この不具合が修正されるまで、レベルを適切に設計できません。この例を示しました:

ボールバウンスvsボールバウンス+ジャンプ

ただし、ジャンプは、ボールをまっすぐ上向きに発射するほど簡単ではありません。レベルの設計をより複雑にするために、ボールが転がっている表面に対してジャンプ角度をプログラムしました。

ボールジャンプ角度比較

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

私の最近の試みは、ジャンプ-rigidbody.velocity.magnitude * 50を試して、ボールが移動する速度によってジャンプ力を減らすことでした。ボールの速度が速度と同等であると思われる速度に達したときに、ジャンプ力を比例的にゼロまで下げることで、バウンス+ジャンプの問題をほぼ解決しました。それは停止状態から機能しましたが、問題は、ボールが接地している間の大きさも考慮しているため、ボールがフルスピードで回転してジャンプするのを妨げています。私は近くにいましたが、そこにはまったくありませんでした!

私は初心者プログラマーであり、私はここで困惑しています。この問題の独創的な解決策を見つけるのを手伝ってくれる人はいますか?プレイヤーが継続的に跳ね返り、より高くジャンプできる限り、すべてのレベルを設計することはできません。すべてのレベルをだますことができるからです。先に進みたいと思います-この問題は長い間私を抑えてきましたので、アドバイスをいただければ幸いです!


いい質問:)物理的なマテリアルで遊んでみましたか?地面の弾力性をゼロ(または非常に低い値)に設定できます。多分プレイヤーもそうです。
M156 2016

回答:


0

まず第一に、私はあなたの質問が非常によく書かれていてそれが喜びだと言いたいです:)、あなたはコードで必要のないもの(オーディオソースなど)を削除するだけで十分であり、それは完璧です。そのための乾杯。

答えは、ジャンプ時に速度を固定することで、ジャンプボタンを押したときに速度が速すぎないようにすることができます。


0

私は個人的にバニーホッピングが大好きですが...出発点として、デルタ速度として意図された「ジャンプ速度」を知っておく必要があります。この図は、1回のジャンプの瞬間の速度の増加(「ジャンプ法線」と一致)を表しています。

プレイヤーがジャンプノーマルに沿ってすでに持っている速度は、既存の「ジャンプエネルギー」と見なすことができます。これにより、簡単な解決策が導き出されます。瞬間的なデルタ速度を制限して、プレーヤーが目標速度を超えて加速されることがないようにすることができます。

既存のジャンプ速度を測定するために、正規化されたジャンプベクトルとプレーヤーの速度の内積をとることができます。

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;

今回は、Adjusted Jump Speedが負でない値に強制されています。プレーヤーがジャンプできるはずの速度よりも早く上昇している場合、負の調整速度が得られるため、「ジャンプ」アクションをブレーキとして使用できます。(意図したジャンプ速度に瞬時に減速する!)

注:連絡先XとYは既にペアとして正規化されていると思います。ただし、完全を期すために明示的な詳細を含めました。


0

この答えはあなたが探しているよりもデザインの変更の可能性がありますが、これはどうですか-ボールは地面にしっかりと留まり、上向きの垂直方向の勢いを打ち消すジャンプボタンが押された後の短い期間を持ちます(たぶんバネ状の圧縮を示すためにビット)、その後、その期間が終了した後に上方に飛躍。これにより、ジャンプにバウンスの勢いが加わる問題が解決されますが、バウンスするかジャンプするかをプレイヤーが制御することもできます。また、ジャンプ機能に遅延を追加します。これは、良い(より自然な感じ)または悪い(プレイヤーが応答するのに十分な時間を与えることができない)と見なすことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.