การป้องกันการรวมกันของ Rigidbody Jump Force & Magnitude เด้งใน Unity3D


10

ฉันกำลังสร้างเกมแข่งรถหินอ่อนที่ค่อนข้างง่ายใน Unity3D ลูกบอลเป็นวัตถุฟิสิกส์ 3 มิติที่เคลื่อนที่บนแกน X และ Y เท่านั้น มันมีความสามารถในการหมุนไปทางซ้ายและขวาและกระโดด สิ่งพื้นฐานที่น่ารักยกเว้นว่าฉันเคยเจอปัญหาการทำลายเกม: เมื่อล้มและกระทบพื้นความสูงของการตีกลับของลูกบอลสามารถรวมกับแรงกระโดดเพื่อสร้างการกระโดดสูงเป็นพิเศษ ซึ่งหมายความว่าเมื่อกดปุ่มตามเวลาที่กำหนดผู้เล่นสามารถทำให้ลูกบอลกระดอนสูงกว่าแบบทวีคูณได้ถึงความสูงที่ไม่ได้ตั้งใจ ฉันไม่สามารถออกแบบระดับได้อย่างถูกต้องจนกว่าข้อผิดพลาดนี้จะได้รับการแก้ไข ฉันได้แสดงตัวอย่างนี้:

Bouncing Ball vs Bouncing Ball + Jumping

อย่างไรก็ตามการกระโดดไม่ใช่เรื่องง่ายเหมือนยิงลูกขึ้นไปด้านบน เพื่ออำนวยความสะดวกให้กับความซับซ้อนมากขึ้นในการออกแบบระดับฉันได้ตั้งโปรแกรมมุมกระโดดที่จะสัมพันธ์กับพื้นผิวที่ลูกบอลกลิ้งไปมา

การเปรียบเทียบมุมกระโดดของบอล

รูปที่ 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เพื่อลดพลังการกระโดดด้วยความเร็วที่ลูกบอลเคลื่อนที่ มันเกือบแก้ปัญหาการตีกลับ + กระโดดโดยการลดแรงกระโดดลงไปที่ศูนย์อย่างเป็นสัดส่วนเมื่อความเร็วของลูกถึงสิ่งที่ดูเหมือนจะเท่ากับความเร็วในการหมุน มันทำงานได้จากการหยุดนิ่ง แต่ปัญหาคือมันยังคำนึงถึงขนาดในขณะที่ลูกบอลถูกต่อสายดินป้องกันไม่ให้ลูกบอลกลิ้งด้วยความเร็วเต็มที่และกระโดด ฉันสนิท แต่ก็ไม่ค่อยมี!

ฉันเป็นโปรแกรมเมอร์มือใหม่และฉันก็นิ่งงันอยู่ที่นี่ ใครช่วยฉันหาวิธีแก้ปัญหาที่สร้างสรรค์กับปัญหานี้ได้หรือไม่? ตราบใดที่ผู้เล่นสามารถตีกลับและกระโดดได้สูงขึ้นเรื่อย ๆ ฉันไม่สามารถออกแบบด่านต่าง ๆ ได้เพราะพวกเขาจะสามารถโกงได้ ฉันชอบที่จะเดินหน้าต่อไป - ปัญหานี้ทำให้ฉันกลับมาเป็นเวลานานดังนั้นฉันจึงขอขอบคุณคำแนะนำบางอย่าง!


เป็นคำถามที่ดี :) คุณลองเล่นกับวัสดุทางฟิสิกส์เหรอ? คุณสามารถตั้งค่า bounciness ของพื้นดินเป็นศูนย์ (หรือค่าต่ำมาก) อาจจะเป็นผู้เล่นก็ขึ้นอยู่กับ
M156

คำตอบ:


0

ก่อนอื่นผมอยากจะบอกว่าคำถามของคุณเขียนได้ดีมากและมันก็เป็นเรื่องที่น่ายินดี :) คุณต้องลบสิ่งที่ไม่จำเป็นในรหัส (ไฟล์เสียง ฯลฯ ) และมันจะสมบูรณ์แบบ ขอบคุณสำหรับสิ่งนั้น

สำหรับคำตอบคุณสามารถยึดความเร็วของคุณเมื่อกระโดดซึ่งจะป้องกันคุณจากการเข้าถึงความเร็วสูงเกินไปเมื่อกดปุ่มกระโดด


0

ในขณะที่ฉันรักกระต่ายกระโดดเป็นจุดเริ่มต้นเราควรทราบ "ความเร็วกระโดด" ที่ตั้งใจไว้ว่าเป็นความเร็วเดลต้า ตัวเลขนี้แสดงถึงการเพิ่มความเร็ว (ตามด้วย "กระโดดปกติ") ในระหว่างการกระโดดทันทีหนึ่งครั้ง

ความเร็วใด ๆ ที่ผู้เล่นมีในแนวเดียวกันกับ Jump Normal สามารถถูกมองว่าเป็น "Jump Energy" ที่มีอยู่แล้ว สิ่งนี้นำไปสู่การแก้ปัญหาที่ตรงไปตรงมา: ความเร็วของเดลต้าในทันทีสามารถถูก จำกัด ได้ซึ่งมันจะไม่ส่งผลให้ผู้เล่นถูกเร่งความเร็วเกินความเร็วเป้าหมาย

เพื่อวัดความเร็วการกระโดดของคุณที่มีอยู่แล้วเราสามารถนำผลิตภัณฑ์ดอทของ Jump Vector ของคุณและความเร็วของเครื่องเล่นของคุณ:

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

"ความเร็วที่มีอยู่" ก็บังคับให้ไม่ใช่แบบไม่เชิงลบเช่นกัน เมื่อผู้เล่นกำลังล้มความเร็วในการกระโดดที่มีอยู่ติดลบจะชดเชยการล้มของพวกเขาอนุญาตให้พวกเขาเด้งบนอากาศบาง ๆ ถ้าพวกเขาเรียกการกระโดดในขณะที่ตก

ตอนนี้เรารู้แล้วว่าจะลดความเร็วของเดลต้าได้อย่างแม่นยำเพียงใดเราสามารถคำนวณ "Jump Vector" ที่มีประสิทธิภาพได้โดยการปรับขนาดของ Jump Normal ให้เป็นความเร็วของเดลต้าเป้าหมาย

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

เวลานี้การปรับความเร็วการกระโดดถูกบังคับไม่เป็นลบ หากผู้เล่นพุ่งขึ้นเร็วกว่าที่ควรจะสามารถกระโดดได้พวกเขาจะได้รับความเร็วที่ติดลบซึ่งทำให้พวกเขาสามารถใช้แอคชั่น "กระโดด" เป็นเบรค (เพื่อชะลอความเร็วในการกระโดดตามที่ตั้งใจไว้ทันที!)

หมายเหตุ: ฉันเชื่อว่าผู้ติดต่อ X และ Y ของคุณได้รับการทำให้เป็นมาตรฐานแล้วคู่ ฉันรวมรายละเอียดที่ชัดเจนเพื่อเห็นแก่ความสมบูรณ์ด้วย


0

คำตอบนี้อาจเป็นการเปลี่ยนแปลงการออกแบบมากกว่าที่คุณกำลังมองหา แต่วิธีการเกี่ยวกับ - ลูกมีช่วงเวลาสั้น ๆ หลังจากกดปุ่มกระโดดที่มันอยู่อย่างมั่นคงบนพื้นดินและยกเลิกโมเมนตัมแนวตั้งขึ้น (อาจบีบ บิตเพื่อแสดงถึงการบีบอัดเหมือนสปริง) จากนั้นกระโดดขึ้นไปหลังจากช่วงเวลาดังกล่าวได้ข้อสรุป นี่จะช่วยแก้ปัญหาการเพิ่มแรงกระตุ้นของการตีกลับที่เพิ่มขึ้นในการกระโดดแม้ว่ามันจะช่วยให้ผู้เล่นควบคุมได้ว่าพวกเขาจะเด้งหรือกระโดด นอกจากนี้ยังเพิ่มความล่าช้าในฟังก์ชั่นการกระโดดซึ่งสามารถมองเห็นได้ดี (ให้ความรู้สึกเป็นธรรมชาติมากขึ้น) หรือไม่ดี (ไม่อนุญาตให้ผู้เล่นมีเวลาตอบสนองมากพอ)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.