简体   繁体   中英

Unity 2D Jump Height different after first reloading

Recently I got into Unity and I have a weird bug that my character's jump height is only higher after the first reload(respawn) on the first scene I am running.

Scenario 1:

  • Scene 1 is being loaded. Character is jumping at the correct height.
  • Character dies. Scene 1 is reloaded and character is respawned. Character now jumps much higher than intended.
  • Clear Scene 1, moves to Scene 2. Character now behaves normally (even after respawning).

Scenario 2:

  • Scene 2 is being loaded. The exact problem in Scenario 1 occur in Scene 2. (because it is the first scene I run)
  • Clear Scene 2, moves to Scene 3. Character now behaves normally (even after respawning).

I have been on this for hours and I still could not figure out where is the bug.

CharacterController Script

using UnityEngine;
using UnityEngine.Events;

public class CharacterController2D : MonoBehaviour
{
    [SerializeField] private float m_JumpForce = 200f;                          // Amount of force added when the player jumps.
    [Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f;  // How much to smooth out the movement
    [SerializeField] private bool m_AirControl = false;                         // Whether or not a player can steer while jumping;
    [SerializeField] private LayerMask m_WhatIsGround;                          // A mask determining what is ground to the character
    [SerializeField] private Transform m_GroundCheck;                           // A position marking where to check if the player is grounded.
    [SerializeField] private Transform m_CeilingCheck;                          // A position marking where to check for ceilings
    [SerializeField] private Collider2D m_CrouchDisableCollider;                // A collider that will be disabled when crouching

    private System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
    private bool m_Grounded;            // Whether or not the player is grounded.
    const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up
    private Rigidbody2D m_Rigidbody2D;
    private bool m_FacingRight = true;  // For determining which way the player is currently facing.
    private Vector3 m_Velocity = Vector3.zero;

    [Header("Events")]
    [Space]

    public UnityEvent OnLandEvent;

    [System.Serializable]
    public class BoolEvent : UnityEvent<bool> { }

    private void Awake()
    {
        m_Rigidbody2D = GetComponent<Rigidbody2D>();

        if (OnLandEvent == null)
            OnLandEvent = new UnityEvent();
    }
    
    private void FixedUpdate()
    {

        if (!m_Grounded)
        { 
            sw.Start();
        }

        m_Grounded = false;


        // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
        // This can be done using layers instead but Sample Assets will not overwrite your project settings.
        Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
        for (int i = 0; i < colliders.Length; i++)
        {
            if (colliders[i].gameObject != gameObject)
            {
                //sw.Stop();
                m_Grounded = true;
               if (sw.ElapsedMilliseconds > (long)60)
                    OnLandEvent.Invoke(); 
                sw.Reset();
            }
        }
    }


    public void Move(float move, bool jump)
    {

        //only control the player if grounded or airControl is turned on
        if (m_Grounded || m_AirControl)
        {

            // Move the character by finding the target velocity
            Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
            // And then smoothing it out and applying it to the character
            m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing);

            // If the input is moving the player right and the player is facing left...
            if (move > 0 && !m_FacingRight)
            {
                // ... flip the player.
                Flip();
            }
            // Otherwise if the input is moving the player left and the player is facing right...
            else if (move < 0 && m_FacingRight)
            {
                // ... flip the player.
                Flip();
            }
        }
        // If the player should jump...
        if (m_Grounded && jump)
        {
            // Add a vertical force to the player.
            m_Grounded = false;
            m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
        }
    }

    
    private void Flip()
    {
        // Switch the way the player is labelled as facing.
        m_FacingRight = !m_FacingRight;

        // Multiply the player's x local scale by -1.
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }
}

CharacterMovement Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterMovement : MonoBehaviour
{

    public CharacterController2D controller;
    public Animator animator;
    public Joystick joystick;
    public float horizontalMove = 0;
    public float runSpeed = 40f;
    public bool jump = false;
    
    // Update is called once per frame
    void Update()
    {
        
        if(joystick.Horizontal >= .2f){

            horizontalMove = runSpeed;

        }else if(joystick.Horizontal <= -.2f){

            horizontalMove = -runSpeed;

        }else{

            horizontalMove = 0;

        }

        animator.SetFloat("Speed", Mathf.Abs(horizontalMove));
        
        float verticalMove = joystick.Vertical;

        if(verticalMove >= .5f){

            jump = true;
            animator.SetBool("IsJumping", true);

        }

    }

    public void OnLanding() {

        animator.SetBool("IsJumping", false);

    }
    void FixedUpdate() {

        controller.Move(horizontalMove * Time.fixedDeltaTime, jump);
        jump = false;

    }

}

CharacterDeath Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterDeath : MonoBehaviour
{   
    [SerializeField] GameObject DustCloud;
    //To avoid multiple water splash sound playing
    private bool splashed = false;
    public void OnCollisionEnter2D(Collision2D other){

        if(other.gameObject.CompareTag("Enemy")){

            gameObject.SetActive(false);
            Instantiate(DustCloud, transform.position, DustCloud.transform.rotation);
            Invoke("LMRespawn", 2.5f);
            
        }
    }

    public void OnTriggerEnter2D(Collider2D other) {

       if(other.CompareTag("Water") && !splashed){

                AudioManager.instance.PlaySound("WaterSplashSFX");
                splashed = true;

        } 
    }

    //Adds delay before respawning
    void LMRespawn(){

        LevelManager.instance.Respawn();
        splashed = false;

    }
}

LevelManager Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelManager : MonoBehaviour
{
    public static LevelManager instance;
    public Transform respawnPoint;
    public GameObject characterPrefab;
    private void Awake(){

        instance = this;
    }

    public void Respawn(){

        //Instantiate(characterPrefab, respawnPoint.position, Quaternion.identity);
        Scene CS = SceneManager.GetActiveScene();
        SceneManager.LoadScene(CS.name);

    }

}

Please let me know if any more information is needed.

Multiply the jump force with Time.DeltaTime.

Time.DeltaTime is the represents the completion time in seconds since the last frame, so multiplying or jumpForce with it will make sure that we jump the same height no matter of the frame rate we get on different devices, or when the frame rate drops.

Notice that you're also applying force in the CharacterController class inside the Move function: m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM