简体   繁体   中英

2D Character not jumping issue in Unity

I'm new to Unity and C#, trying to make a 2D game. The animator controller screenshot with all the transition is attached, the ( isGrounded ) bool from idle to jump is false, from jump to idle is true, and from run to jump is false, but in this case, the character doesn't jump, it shakes in its place transitioning from idle to jump very quickly. When I remove the jump animation the character moves normally but of course no jumping. What could be the problem here?

在此处输入图片说明

This is also the CharacterController2D script:

    public float jumpForce = 600f;

    // player health
    public int playerHealth = 1;

    // LayerMask to determine what is considered ground for the player
    public LayerMask whatIsGround;

    internal void EnemyBounce(CharacterController2D characterController2D)
    {
        throw new NotImplementedException();
    }
    // Transform just below feet for checking if player is grounded
    public Transform groundCheck;

    // player can move?
    // we want this public so other scripts can access it but we don't want to show in editor as it might confuse designer
    [HideInInspector]
    public bool playerCanMove = true;

    // SFXs
    public AudioClip coinSFX;
    public AudioClip deathSFX;
    public AudioClip fallSFX;
    public AudioClip jumpSFX;
    public AudioClip victorySFX;

    // private variables below

    // store references to components on the gameObject
    Transform _transform;
    Rigidbody2D _rigidbody;
    Animator _animator;
    AudioSource _audio;
    // hold player motion in this timestep
    float _vx;
    float _vy;

    // player tracking
    bool _facingRight = true;
    bool _isGrounded = false;
    bool _isRunning = false;
    bool _canDoubleJump = false;

    // store the layer the player is on (setup in Awake)
    int _playerLayer;

    // number of layer that Platforms are on (setup in Awake)
    int _platformLayer;

    void Awake()
    {
        // get a reference to the components we are going to be changing and store a reference for efficiency purposes
        _transform = GetComponent<Transform>();

        _rigidbody = GetComponent<Rigidbody2D>();
        if (_rigidbody == null) // if Rigidbody is missing
            Debug.LogError("Rigidbody2D component missing from this gameobject");

        _animator = GetComponent<Animator>();
        if (_animator == null) // if Animator is missing
            Debug.LogError("Animator component missing from this gameobject");

        _audio = GetComponent<AudioSource>();
        if (_audio == null)
        { // if AudioSource is missing
            Debug.LogWarning("AudioSource component missing from this gameobject. Adding one.");
            // let's just add the AudioSource component dynamically
            _audio = gameObject.AddComponent<AudioSource>();
        }

        // determine the player's specified layer
        _playerLayer = this.gameObject.layer;

        // determine the platform's specified layer
        _platformLayer = LayerMask.NameToLayer("Platform");
    }

    // this is where most of the player controller magic happens each game event loop
    void Update()
    {
        // exit update if player cannot move or game is paused
        if (!playerCanMove || (Time.timeScale == 0f))
            return;

        // determine horizontal velocity change based on the horizontal input
        _vx = CrossPlatformInputManager.GetAxisRaw("Horizontal");

        // Determine if running based on the horizontal movement
        if (_vx != 0)
        {
            _isRunning = true;
        }
        else
        {
            _isRunning = false;
        }

        // set the running animation state
        _animator.SetBool("Running", _isRunning);

        // get the current vertical velocity from the rigidbody component
        _vy = _rigidbody.velocity.y;

        // Check to see if character is grounded by raycasting from the middle of the player
        // down to the groundCheck position and see if collected with gameobjects on the
        // whatIsGround layer
        _isGrounded = Physics2D.Linecast(_transform.position, groundCheck.position, whatIsGround);
        // allow double jump after grounded
        if (_isGrounded)
        {
            _canDoubleJump = true;
        }
        // Set the grounded animation states
        _animator.SetBool("Grounded", _isGrounded);

        if (_isGrounded && CrossPlatformInputManager.GetButtonDown("Jump")) // If grounded AND jump button pressed, then allow the player to jump
        {

            DoJump();
        }
        else if (_canDoubleJump && CrossPlatformInputManager.GetButtonDown("Jump")) // If candoublejump and jump button pressed, then allow player to double jump
        {
            DoJump();
            // disable double hump after double jumping since you can only really do it once
            _canDoubleJump = false;
        }

        // If the player stops jumping mid jump and player is not yet falling
        // then set the vertical velocity to 0 (he will start to fall from gravity)
        if (CrossPlatformInputManager.GetButtonUp("Jump") && _vy > 0f)
        {
            _vy = 0f;
        }

        // Change the actual velocity on the rigidbody
        _rigidbody.velocity = new Vector2(_vx * moveSpeed, _vy);

        // if moving up then don't collide with platform layer
        // this allows the player to jump up through things on the platform layer
        // NOTE: requires the platforms to be on a layer named "Platform"
        Physics2D.IgnoreLayerCollision(_playerLayer, _platformLayer, (_vy > 0.0f));
    }

    // Checking to see if the sprite should be flipped
    // this is done in LateUpdate since the Animator may override the localScale
    // this code will flip the player even if the animator is controlling scale
    void LateUpdate()
    {
        // get the current scale
        Vector3 localScale = _transform.localScale;

        if (_vx > 0) // moving right so face right
        {
            _facingRight = true;
        }
        else if (_vx < 0)
        { // moving left so face left
            _facingRight = false;
        }

        // check to see if scale x is right for the player
        // if not, multiple by -1 which is an easy way to flip a sprite
        if (((_facingRight) && (localScale.x < 0)) || ((!_facingRight) && (localScale.x > 0)))
        {
            localScale.x *= -1;
        }

        // update the scale
        _transform.localScale = localScale;
    }

    // if the player collides with a MovingPlatform, then make it a child of that platform
    // so it will go for a ride on the MovingPlatform
    void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.tag == "MovingPlatform")
        {
            this.transform.parent = other.transform;
        }
    }

    // if the player exits a collision with a moving platform, then unchild it
    void OnCollisionExit2D(Collision2D other)
    {
        if (other.gameObject.tag == "MovingPlatform")
        {
            this.transform.parent = null;
        }
    }

    //make the player jump
    void DoJump()
    {
        // reset current vertical motion to 0 prior to jump
        _vy = 0f;
        // add a force in the up direction
        _rigidbody.AddForce(new Vector2(4, jumpForce));
        // play the jump sound
        PlaySound(jumpSFX);
    }
    // do what needs to be done to freeze the player
    void FreezeMotion()
    {
        playerCanMove = false;
        _rigidbody.velocity = new Vector2(0, 0);
        _rigidbody.isKinematic = true;
    }

    // do what needs to be done to unfreeze the player
    void UnFreezeMotion()
    {
        playerCanMove = true;
        _rigidbody.isKinematic = false;
    }

    // play sound through the audiosource on the gameobject
    void PlaySound(AudioClip clip)
    {
        _audio.PlayOneShot(clip);
    }

    // public function to apply damage to the player
    public void ApplyDamage(int damage)
    {
        if (playerCanMove)
        {
            playerHealth -= damage;

            if (playerHealth <= 0)
            { // player is now dead, so start dying
                PlaySound(deathSFX);
                StartCoroutine(KillPlayer());
            }
        }
    }

    // public function to kill the player when they have a fall death
    public void FallDeath()
    {
        if (playerCanMove)
        {
            playerHealth = 0;
            PlaySound(fallSFX);
            StartCoroutine(KillPlayer());
        }
    }

    // coroutine to kill the player
    IEnumerator KillPlayer()
    {
        if (playerCanMove)
        {
            // freeze the player
            FreezeMotion();

            // play the death animation
            _animator.SetTrigger("Death");

            // After waiting tell the GameManager to reset the game
            yield return new WaitForSeconds(2.0f);

            if (GameManager.gm) // if the gameManager is available, tell it to reset the game
                GameManager.gm.ResetGame();
            else // otherwise, just reload the current level
                SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    public void CollectCoin(int amount)
    {
        PlaySound(coinSFX);

        if (GameManager.gm) // add the points through the game manager, if it is available
            GameManager.gm.AddPoints(amount);
    }

    // public function on victory over the level
    public void Victory()
    {
        PlaySound(victorySFX);
        FreezeMotion();
        _animator.SetTrigger("Victory");

        if (GameManager.gm) // do the game manager level compete stuff, if it is available
            GameManager.gm.LevelCompete();
    }

    // public function to respawn the player at the appropriate location
    public void Respawn(Vector3 spawnloc)
    {
        UnFreezeMotion();
        playerHealth = 1;
        _transform.parent = null;
        _transform.position = spawnloc;
        _animator.SetTrigger("Respawn");
    }
    public void EnemyBounce()
    {
        DoJump();
    }
}

I also tried adding a separate Jump script, it doesn't work.

Just gonna take some notes while reading the code...

This:

// Determine if running based on the horizontal movement
if (_vx != 0)
{
    _isRunning = true;
}
else
{
    _isRunning = false;
}

// set the running animation state
_animator.SetBool("Running", _isRunning);

Can be replaced by

_isRunning = _vx != 0;
_animator.SetBool("Running", _isRunning);

or even just creating a property accessor

bool _isRunning { 
    get {
        return _vx != 0;
    }
}

As for your actual question; I can't see your transitions but I'm assuming there's something wrong with them, keep trying to debug it by removing SetBools, and check the Animator on what is being triggered. The Any State -> Idle looks suspicious.

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