Ngăn chặn sự kết hợp giữa lực lượng cứng nhắc và cường độ nảy trong Unity3D


10

Tôi đang xây dựng một trò chơi đua xe bằng đá cẩm thạch khá đơn giản trong Unity3D. Quả bóng là một vật thể vật lý 3D chỉ di chuyển trên trục X và Y. Nó có khả năng lăn trái và phải, và nhảy. Những thứ khá cơ bản, ngoại trừ việc tôi gặp phải một vấn đề phá vỡ trò chơi: Khi ngã và chạm đất, cường độ nảy của quả bóng có thể được kết hợp với lực nhảy của nó để tạo ra một cú nhảy cực cao. Điều này có nghĩa là, với các lần nhấn nút đúng lúc, người chơi có thể khiến bóng nảy cao hơn theo cấp số nhân, đạt đến độ cao ngoài ý muốn. Tôi không thể thiết kế đúng mức cho đến khi trục trặc này được khắc phục. Tôi đã minh họa ví dụ này:

Bóng nảy vs Bóng nảy + Nhảy

Nhảy, tuy nhiên, không đơn giản như chỉ bắn bóng thẳng lên trên. Để tạo điều kiện cho sự phức tạp hơn trong thiết kế cấp độ, tôi đã lập trình góc nhảy tương đối với bề mặt mà quả bóng đang lăn.

So sánh bóng nhảy

Hình 3 , trong hình minh họa đó, là cách trò chơi của tôi hoạt động cho đến nay; không phải hình 4 . Điều này làm cho việc giải quyết vấn đề nảy + nhảy trở nên khó khăn hơn nhiều, vì tôi không thể đơn giản đo và đặt một lực hoặc vận tốc chính xác trên trục Y. Làm như vậy dẫn đến hành vi kỳ lạ, điều này trở nên đáng chú ý hơn khi quả bóng di chuyển trên các sườn dốc hơn.

Cho đến nay, tôi đã có thể nghĩ ra một giải pháp cho tất cả các vấn đề thiết kế khác trong trò chơi này và sau đó tìm ra cách lập trình chúng, nhưng vấn đề này khiến tôi bế tắc. Tôi đã thử một số cách tiếp cận khác nhau, nhưng không có cách nào trong số chúng có hiệu quả.

Đây là kịch bản C # điều khiển cú nhảy của bóng:

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

Nỗ lực mới nhất của tôi là thử nhảy - Rigidbody.velocity.magnitude * 50 , để giảm sức nhảy bằng tốc độ mà quả bóng đang di chuyển. Nó gần như đã giải quyết được vấn đề nảy + nhảy, bằng cách giảm tỷ lệ lực nhảy xuống 0 khi tốc độ của quả bóng đạt đến mức tương đương với vận tốc. Nó hoạt động từ bế tắc, nhưng vấn đề là, nó cũng chiếm độ lớn trong khi quả bóng được tiếp đất, ngăn không cho bóng lăn ở tốc độ tối đa và nhảy. Tôi đã gần, nhưng không hoàn toàn ở đó!

Tôi là một lập trình viên mới làm quen, và tôi bị bối rối ở đây. Bất cứ ai có thể giúp tôi tìm một giải pháp sáng tạo cho vấn đề này? Miễn là người chơi có thể liên tục nảy và nhảy cao hơn, tôi không thể thiết kế bất kỳ cấp độ nào, bởi vì tất cả họ sẽ chỉ có thể bị lừa. Tôi rất muốn tiến lên - vấn đề này đã kìm hãm tôi trong một thời gian dài, vì vậy tôi rất trân trọng một số lời khuyên!


Câu hỏi hay :) bạn đã thử chơi xung quanh với vật liệu vật lý chưa? Bạn có thể đặt độ nảy của mặt đất thành 0 (hoặc giá trị rất thấp). Có lẽ cũng là người chơi, nó phụ thuộc.
M156

Câu trả lời:


0

Trước hết, tôi muốn nói rằng câu hỏi của bạn được viết rất tốt và đó là một niềm vui :), bạn chỉ cần xóa những gì không cần thiết trong mã (nguồn âm thanh, v.v.) và nó sẽ hoàn hảo. Chúc mừng cho điều đó.

Để trả lời, bạn có thể kẹp tốc độ của mình khi nhảy, điều này sẽ ngăn bạn đạt tốc độ quá cao khi nhấn nút nhảy.


0

Trong khi cá nhân tôi thích nhảy thỏ ... Khi bắt đầu, chúng ta nên biết "Tốc độ nhảy" dự định là vận tốc delta. Hình này biểu thị mức tăng vận tốc (trong dòng có "Nhảy bình thường") trong thời gian nhảy một lần.

Bất kỳ vận tốc nào mà người chơi đã có phù hợp với Jump Bình thường đều có thể được xem là "Nhảy năng lượng" có sẵn. Điều này dẫn đến một giải pháp đơn giản: Vận tốc delta tức thời có thể bị giới hạn sao cho nó không bao giờ dẫn đến việc người chơi bị tăng tốc vượt quá tốc độ mục tiêu.

Để đo Tốc độ Nhảy trước đó của bạn, chúng tôi có thể lấy sản phẩm chấm của Jump Vector đã chuẩn hóa của bạn và vận tốc của người chơi của bạn:

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

"Tốc độ hiện tại" cũng bị buộc không âm ở đây; Khi người chơi ngã, tốc độ nhảy tiêu cực hiện tại sẽ bù cho việc họ rơi, cho phép họ bật lên trên không khí mỏng nếu họ kích hoạt cú nhảy trong khi rơi.

Bây giờ chúng ta đã biết chính xác giảm bao nhiêu vận tốc delta, chúng ta có thể tính toán "Jump Vector" hiệu quả bằng cách nhân rộng Jump bình thường thành vận tốc delta đích.

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

Lần này, Tốc độ nhảy được điều chỉnh bị buộc không âm; Nếu người chơi đã tăng nhanh hơn mức họ có thể nhảy, họ sẽ đạt được tốc độ điều chỉnh tiêu cực, cho phép họ sử dụng hành động "nhảy" làm phanh. (để làm chậm tốc độ nhảy dự định ngay lập tức!)

Lưu ý: Tôi tin rằng liên hệ X và Y của bạn đã được chuẩn hóa thành một cặp. Tôi bao gồm chi tiết rõ ràng cho lợi ích đầy đủ mặc dù.


0

Câu trả lời này có lẽ là một sự thay đổi thiết kế nhiều hơn so với bạn đang tìm kiếm, nhưng về vấn đề này - quả bóng có một khoảng thời gian ngắn sau khi nhấn nút nhảy, nơi nó giữ vững trên mặt đất và hủy bỏ mọi động lượng thẳng đứng hướng lên (có thể đè bẹp bit để biểu thị một nén giống như lò xo), sau đó nhảy lên sau khi khoảng thời gian đó kết thúc. Điều này sẽ giải quyết vấn đề về đà tăng thêm khi nhảy, mặc dù nó cũng sẽ cho phép người chơi kiểm soát xem họ có bật lên hay chỉ nhảy. Nó cũng thêm một độ trễ cho chức năng nhảy, có thể được xem là tốt (cảm thấy tự nhiên hơn) hoặc xấu (không cho phép người chơi có đủ thời gian để phản hồi).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.