• Unity
  • Help with Player Controller Script Unity

  • Изменено

Hello, I have Player Controller Script that allows me to have the Player to have idle, walk and jump with animation. When I tried to add run, the Player runs but the animation is not working. I was following ThinkCitric's guides and I could not figure out what went wrong.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Spine.Unity;

public class PlayerController : MonoBehaviour
{
    public SkeletonAnimation skeletonAnimation;
    public AnimationReferenceAsset idle, walking, jumping, running;
    public string currentState;
    public float speed;
    public float movement;
    private Rigidbody2D rigidbody;
    public string currentAnimation;
    public float jumpSpeed;
    private Vector2 characterScale;
    public string previousState;
    public float runSpeed;

// Start is called before the first frame update
void Start()
{
    rigidbody = GetComponent<Rigidbody2D>();
    currentState = "Idle";
    SetCharacterState(currentState);
    characterScale = transform.localScale;

}

// Update is called once per frame
void Update()

{
    Move();
}

//sets character animation
public void SetAnimation(AnimationReferenceAsset animation, bool loop, float timeScale)
{
    if (animation.name.Equals(currentAnimation))
    {
        return;
    }
    Spine.TrackEntry animationEntry = skeletonAnimation.state.SetAnimation(0, animation, loop);
    animationEntry.TimeScale = timeScale;
    animationEntry.Complete += AnimationEntry_Complete;
    currentAnimation = animation.name;
}

//Do something after animation completes
private void AnimationEntry_Complete(Spine.TrackEntry trackEntry)
{
    if (currentState.Equals("Jumping"))
    {
        SetCharacterState(previousState);
    }
}

//Checks character state and sets the animation accordingly
public void SetCharacterState(string state)
{

    if (state.Equals("Walking"))
    {
        SetAnimation(walking, true, 1.5f);
    }
    else if (state.Equals("Jumping"))
    {
        SetAnimation(jumping, false, 1f);
    }
    else if (state.Equals("Running"))
    {
        SetAnimation(running, true, 1f);
    }
    else
    {
        SetAnimation(idle, true, 1f);
    }

    currentState = state;
}

public void Move()
{
    movement = Input.GetAxis("Horizontal");
    rigidbody.velocity = new Vector2(movement * speed, rigidbody.velocity.y);
    if (movement != 0)
    {
        if (!currentState.Equals("Jumping"))
        {
            SetCharacterState("Walking");
        }

        

        if (movement > 0)
        {
            transform.localScale = new Vector2(characterScale.x, characterScale.y);
        }
        else
        {
            transform.localScale = new Vector2(-characterScale.x, characterScale.y);
        }
    }
    else
    {
        if (!currentState.Equals("Jumping"))
        {
            SetCharacterState("Idle");
        }
        

    }

    if (Input.GetButtonDown("Jump"))
    {
        Jump();
    }

    if (Input.GetKey(KeyCode.LeftShift))
    {
        Run();
    }
}

public void Jump()
{
    rigidbody.velocity = new Vector2(rigidbody.velocity.x, jumpSpeed);
    if (!currentState.Equals("Jumping"))
    {
        previousState = currentState;
    }
    SetCharacterState("Jumping");
}

public void Run()
{
    rigidbody.velocity = new Vector2(movement * runSpeed, rigidbody.velocity.y);
    if (!currentState.Equals("Running"))
    {
        previousState = currentState;
    }
    SetCharacterState("Running");
}
}


Is the running AnimationReferenceAsset set correctly?

I think so. When I press Lshift it shows the state is Running. And I have also tested the animation without the Player Controller Script and the animation works.

KelvinWakaka написал

And I have also tested the animation without the Player Controller Script and the animation works.

How did you test them? Are you sure that you have assigned the correct AnimationReferenceAssets from the skeleton asset you are controlling, and not from another skeleton that also has a Walking animation?

Please also describe in more detail what you mean by "the animation is not working". What are you expecting to see and what do you see instead. Does the animation play but show an undesired result, or is the skeleton not moving at all when playing the animation?

Harald написал
KelvinWakaka написал

And I have also tested the animation without the Player Controller Script and the animation works.

How did you test them? Are you sure that you have assigned the correct AnimationReferenceAssets from the skeleton asset you are controlling, and not from another skeleton that also has a Walking animation?

Please also describe in more detail what you mean by "the animation is not working". What are you expecting to see and what do you see instead. Does the animation play but show an undesired result, or is the skeleton not moving at all when playing the animation?

So I tried playing the scene while only looping the animation (i disabled the player controller script). Thats what I meant by tested the animation. I am sure I have assigned the correct AnimationReferenceAssets from the skeleton asset.

I was hoping to see the Player would run the "Running" animation and instead it only runs the first frame of the animation at the moment when I press LShift.

I apologise for not describing the issue in more detail previously.

If you see only the first frame of an animation being played, you are most likely starting the same animation every frame instead of only once.

Harald написал

If you see only the first frame of an animation being played, you are most likely starting the same animation every frame instead of only once.

I see. What am I missing? I followed the same principle the tutorial used for "Jump" in "Run".

I believe whats happening is that when your character is running, you are first setting it to "Walking" and then setting it to "Running" every frame. So the animation gets switched to Walking and then immediately switched to Running, which causes the run animation to start over.

public void Move()
    {
        movement = Input.GetAxis("Horizontal");
        rigidbody.velocity = new Vector2(movement * speed, rigidbody.velocity.y);
        if (movement != 0)
        {
            if (!currentState.Equals("Jumping"))
            {
                SetCharacterState("Walking"); <

---

This is triggering each frame when you're running
            }

....

You'll want to set up your code so that when you're supposed to be running, it doesn't set you to Walking

Jamez0r написал

I believe whats happening is that when your character is running, you are first setting it to "Walking" and then setting it to "Running" every frame. So the animation gets switched to Walking and then immediately switched to Running, which causes the run animation to start over.

public void Move()
    {
        movement = Input.GetAxis("Horizontal");
        rigidbody.velocity = new Vector2(movement * speed, rigidbody.velocity.y);
        if (movement != 0)
        {
            if (!currentState.Equals("Jumping"))
            {
                SetCharacterState("Walking"); <

---

This is triggering each frame when you're running
            }

....

You'll want to set up your code so that when you're supposed to be running, it doesn't set you to Walking

So I tried hiding this part

if (!currentState.Equals("Jumping"))
           {
               SetCharacterState("Walking"); <

---

This is triggering each frame when you're running
           } 

and you are right. Now when I press LShift the Player actually runs the "Running" animation. However when I press w or d to move, instead of "Walking" animation, it runs the "Idle" animation. I don't really know how to set up my code to achieve that.

Remove this part from below:

if (Input.GetKey(KeyCode.LeftShift))
{
    Run();
 }

And instead have it check if its running here, by replacing this:

if (!currentState.Equals("Jumping"))
{
   SetCharacterState("Walking");
}

with this:

if (!currentState.Equals("Jumping")){
    if (Input.GetKey(KeyCode.LeftShift)) {
        Run();
    } else {
        SetCharacterState("Walking");
    }
}

That way it can only either set it to Run or to Walking but not both on the same frame.

I highly recommend spending some time focusing just on the basics of programming. I know its fun to jump right into making a game, but at some point you'll need to take a step back and get a good programming foundation or else you will struggle when you evolve from following along in a tutorial to actually creating your own stuff from scratch. It's tough but its worth it!

Thanks again Jamez0r for answering!

Jamez0r написал

I highly recommend spending some time focusing just on the basics of programming.

We definitely second that. Learning the foundational knowledge first is very important and will save a lot of trouble down the road. One thing for example would be to not use strings like "Walking" for saving and querying state, where you could use an enum instead. Also you should never repeat a string all over the place, instead declare a constant, this saves you from any typos and makes editing much easier. Additionally, learning design patterns helps carrying out what you intend to do in a way that's cleaner and easier to extend.

6 дней спустя
Jamez0r написал

Remove this part from below:

if (Input.GetKey(KeyCode.LeftShift))
{
    Run();
 }

And instead have it check if its running here, by replacing this:

if (!currentState.Equals("Jumping"))
{
   SetCharacterState("Walking");
}

with this:

if (!currentState.Equals("Jumping")){
    if (Input.GetKey(KeyCode.LeftShift)) {
        Run();
    } else {
        SetCharacterState("Walking");
    }
}

That way it can only either set it to Run or to Walking but not both on the same frame.

I highly recommend spending some time focusing just on the basics of programming. I know its fun to jump right into making a game, but at some point you'll need to take a step back and get a good programming foundation or else you will struggle when you evolve from following along in a tutorial to actually creating your own stuff from scratch. It's tough but its worth it!

Yep, I don't usually work on the programming side of things and it shows. Thank you for the solution!