我认为你设置动画的方式使得这比必要的更具挑战性 . 让我们改变一些有希望使你的角色更容易动画的东西 .
首先,我认为使用动画 trigger 在脚本跳跃动画方面是不可靠的 . 更好的方法是在动画师中创建 float ,我称之为 velocityY ,代表玩家的 Rigidbody2D.velocity.y . 我还创建了一个名为 isGrounded 的新 bool ,因为我认为这更清晰,更适用于许多场景 .
创建这些变量后,您可以通过以下方式链接三个动画 - 空闲,跳跃和着陆 -
将默认动画设置为"idle" .
从“空闲”转换为“跳转”,条件是:
velocityY > 0
isGrounded = false
使用以下条件从“跳转”转换为“土地”:
velocityY < 0
isGrounded = false
isGrounded = true 时从"land"过渡到"idle" .
最后,要在角色落下时为其设置动画(不先跳跃),您可以选择从“空闲”转换为“陆地”,其中:
velocityY < 0
isGrounded = false
现在到代码 . 这里's a working example that I tested in a project to achieve your desired results. Note that I did not include everything in your script, just the parts that let the character move and animate its jump correctly. Try using this script and playing around with the movement values, as well as the gravity multiplier on your player' s Rigidbody2D 组件;默认值和重力乘数3.5对我来说很有趣!
using UnityEngine;
public class Player : MonoBehaviour
{
//Components on Player GameObject
private Rigidbody2D myRigidbody;
private Animator myAnimator;
//Movement variables
[SerializeField]
private float movementSpeed = 9; //Set default values so you don't always
[SerializeField] //have to remember to set them in the inspector
private float jumpForce = 15;
//Ground checking
[SerializeField]
private Transform groundPoint;
[SerializeField]
private float groundRadius = 0.1f;
[SerializeField]
private LayerMask whatIsGround;
private float velocityX;
private bool isGrounded;
private bool facingRight;
// Use this for initialization
private void Start()
{
facingRight = true;
myRigidbody = GetComponent();
myAnimator = GetComponent();
}
private void Update()
{
Flip();
HandleInput();
HandleAnimations();
}
private void FixedUpdate()
{
HandleMovement(); //It's generally considered good practice to
//call physics-related methods in FixedUpdate
}
private void HandleAnimations()
{
if (!isGrounded)
{
myAnimator.SetBool("isGrounded", false);
//Set the animator velocity equal to 1 * the vertical direction in which the player is moving
myAnimator.SetFloat("velocityY", 1 * Mathf.Sign(myRigidbody.velocity.y));
}
if (isGrounded)
{
myAnimator.SetBool("isGrounded", true);
myAnimator.SetFloat("velocityY", 0);
}
}
private void HandleMovement()
{
isGrounded = Physics2D.OverlapCircle(groundPoint.position, groundRadius, whatIsGround);
velocityX = Input.GetAxis("Horizontal");
myRigidbody.velocity = new Vector2(velocityX * movementSpeed , myRigidbody.velocity.y);
}
private void HandleInput()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
}
private void Jump()
{
if (isGrounded)
{ //ForceMode2D.Impulse is useful if Jump() is called using GetKeyDown
myRigidbody.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
else
{
return;
}
}
private void Flip()
{
if (velocityX > 0 && !facingRight || velocityX < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
}
我还花了一些时间来重新组织你的代码 . 你现在不一定需要关注太多组织,但我认为你可能会感兴趣,因为你还在学习 .
如您所见,脚本中的每个方法都处理一个具体的任务 . 例如,以这种方式设置代码是个好主意,这样如果你以后必须改变一个方面,比如玩家移动,那么所有相关的代码都在同一个地方 . 我认为这对于创建处理玩家"actions"的方法尤其如此,例如跳跃或攻击;如果你有足够的,你甚至可以创建一个完整的动作 class .
最后要提到的是这行代码:
isGrounded = Physics2D.OverlapCircle(groundPoint.position, groundRadius, whatIsGround);
我发现这是一种更容易确定玩家何时接地的方法 . 我通过向玩家添加一个孩子 GameObject 来实现这个目的,添加一个彩色图标以便于放置(你可以通过点击 GameObject 附近的彩色框来实现这一点),然后将它放在玩家的脚之间 .