Unity3D에서 Rigidbody Jump Force & Bounce Magnitude의 조합 방지 if (boolGetJump && isGrounded

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

내 최근 시도는 jump-rigidbody.velocity.magnitude * 50 을 시도 하여 공이 이동하는 속도로 점프하는 힘을 줄였습니다. 그것은 공의 속도가 속도와 동등한 것으로 보이는 것에 도달 할 때 점프 힘을 0으로 비례 적으로 줄임으로써 바운스 + 점프 문제를 거의 해결했습니다. 그것은 정지 상태에서 일했지만 문제는 공이 접지되는 동안의 크기를 설명하여 공이 최대 속도로 구르고 점프하는 것을 막습니다. 나는 가까웠지만 거기에 없었습니다!

나는 초보자 프로그래머이며, 여기에 갇혀 있습니다. 누구 든지이 문제에 대한 창의적인 해결책을 찾도록 도울 수 있습니까? 플레이어가 지속적으로 튀어 오르고 더 높이 점프 할 수있는 한, 모든 레벨을 속일 수 있기 때문에 어떤 레벨도 디자인 할 수 없습니다. 앞으로 나아가고 싶습니다.이 문제는 오랫동안 저를 뒤로하고 있었기 때문에 조언을 많이 부탁드립니다.



답변

우선, 귀하의 질문이 매우 잘 작성되어 있으며 즐거움입니다 :), 코드 (오디오 소스 등)에 필요하지 않은 것을 제거하면 완벽 할 것입니다. 그것을 위해 건배.

답 을 위해 점프 할 때 속도를 고정 하여 점프 버튼을 누를 때 너무 높은 속도에 도달하지 못하게 할 수 있습니다.


답변

나는 개인적으로 토끼 호핑을 좋아하지만 … 시작점으로 “점프 속도”를 델타 속도로 알아야합니다. 이 그림은 한 번 점프하는 동안의 속도 증가 ( “점프 법선”줄)를 나타냅니다.

플레이어가 이미 점프 노멀과 일치하는 속도는 기존의 “점프 에너지”로 볼 수 있습니다. 즉각적인 델타 속도는 플레이어가 목표 속도 이상으로 가속되지 않도록 제한 될 수 있습니다.

기존 점프 속도를 측정하기 위해 정규화 된 점프 벡터와 플레이어 속도의 내적을 구할 수 있습니다.

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;

이번에는 조정 된 점프 속도가 음이 아닌 것으로 강제됩니다. 플레이어가 점프 할 수있는 것보다 이미 빠르게 상승하는 경우 음의 조정 된 속도에 도달하여 “점프”동작을 브레이크로 사용할 수 있습니다. (즉시 점프 속도를 늦추기 위해!)

참고 : 귀하의 연락처 X와 Y는 이미 쌍으로 표준화되어 있다고 생각합니다. 나는 완전성을 위해 명백한 세부 사항을 포함시켰다.


답변

이 대답은 아마도 당신이 찾고있는 것보다 더 많은 디자인 변화 일 것입니다. 그러나 이것은 어떻습니까? 점프 버튼을 누른 후 공은 바닥에 단단히 고정되어 수직 수직 운동량을 취소합니다. 스프링과 같은 압축을 나타 내기 위해 비트), 기간이 끝난 후 위로 도약. 이것은 바운스의 운동량이 점프에 추가되는 문제를 해결하지만, 플레이어는 바운스 여부를 제어 할 수 있습니다. 또한 점프 기능에 지연을 추가하여 양호 (보다 자연스러운 느낌) 또는 불량 (플레이어가 응답 할 시간이 충분하지 않음)으로 보일 수 있습니다.