我对Unity和C#还是陌生的,所以将对您有所帮助。
我进行了精灵跳跃,效果很好,但是,唯一会播放的动画是着陆动画。起飞动画将不会播放,并且精灵会一直停留在空闲位置,同时跳跃直到速度低于0,然后播放着陆动画。
我在做什么错?我希望当玩家跳起来时能够实现起飞动画播放,然后在跌落时直接进入降落动画。
这是我的代码:
using UnityEngine;
public class Player : MonoBehaviour
{
private Rigidbody2D myRigidbody;
private Animator myAnimator;
[SerializeField]
private float movementSpeed;
private bool facingRight;
private bool attack;
private bool slide;
[SerializeField]
private Transform[] groundPoints;
[SerializeField]
private float groundRadius;
[SerializeField]
private LayerMask whatIsGround;
private bool isGrounded;
private bool jump;
private bool airControl;
[SerializeField]
private float jumpForce;
// Use this for initialization
void Start()
{
facingRight = true;
myRigidbody = GetComponent<Rigidbody2D>();
myAnimator = GetComponent<Animator>();
}
void Update()
{
HandleInput();
}
// Update is called once per frame
void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
HandleMovement(horizontal);
isGrounded = IsGrounded();
Flip(horizontal);
HandleAttacks();
HandleLayers();
ResetValues();
}
private void HandleMovement(float horizontal)
{
if (myRigidbody.velocity.y < 0)
{
myAnimator.SetBool("land", true);
}
if (!myAnimator.GetBool("slide") && !this.myAnimator.GetCurrentAnimatorStateInfo(0).IsTag("Attack")&&(isGrounded || airControl))
{
myRigidbody.velocity = new Vector2(horizontal * movementSpeed, myRigidbody.velocity.y);
}
if (isGrounded && jump)
{
isGrounded = false;
myRigidbody.AddForce(new Vector2(0, jumpForce));
myAnimator.SetTrigger("jump");
}
if (slide && !this.myAnimator.GetCurrentAnimatorStateInfo(0).IsName("Slide"))
{
myAnimator.SetBool("slide", true);
}
else if (!this.myAnimator.GetCurrentAnimatorStateInfo(0).IsName("Slide"))
{
myAnimator.SetBool("slide", false);
}
myAnimator.SetFloat("speed", Mathf.Abs(horizontal));
}
private void HandleAttacks()
{
if (attack && !this.myAnimator.GetCurrentAnimatorStateInfo(0).IsTag("Attack"))
{
myAnimator.SetTrigger("attack");
myRigidbody.velocity = Vector2.zero;
}
}
private void HandleInput()
{
if(Input.GetKeyDown(KeyCode.Space))
{
jump = true;
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
attack = true;
}
if (Input.GetKeyDown(KeyCode.LeftControl))
{
slide = true;
}
}
private void Flip(float horizontal)
{
if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
private void ResetValues()
{
attack = false;
slide = false;
jump = false;
}
private bool IsGrounded()
{
if (myRigidbody.velocity.y <= 0)
{
foreach (Transform point in groundPoints)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, whatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
myAnimator.ResetTrigger("jump");
myAnimator.SetBool("land", false);
return true;
}
}
}
}
return false;
}
private void HandleLayers()
{
if (!isGrounded)
{
myAnimator.SetLayerWeight(1, 1);
}
else
{
myAnimator.SetLayerWeight(1, 0);
}
}
}
答案 0 :(得分:0)
我认为您设置动画的方式使这项工作变得更具挑战性。让我们进行一些更改,希望可以使角色动画变得更加轻松。
首先,我认为在编写跳跃动画脚本时,使用动画n
是不可靠的。更好的方法是在动画师中创建一个trigger
,我将其称为 velocityY ,它代表玩家的float
。我还创建了一个名为 isGrounded 的新Rigidbody2D.velocity.y
,因为我认为这更清楚,更适用于许多“跳跃”场景。
创建完这些变量后,您可以通过以下方式链接三个动画-空闲,跳转和着陆:
从“空闲”过渡到“跳跃”,条件是:
bool
velocityY > 0
在以下条件下从“跳跃”过渡到“土地”:
isGrounded = false
velocityY < 0
在isGrounded = false
时从“土地”过渡到“空闲”。
最后,要为角色掉落时的动画(不先跳动),您可以选择从“空闲”过渡到“降落”,其中:
isGrounded = true
velocityY < 0
现在输入代码。这是我在一个项目中测试过的有效示例,可以达到您想要的结果。请注意,我并未在脚本中包含所有内容,仅包含了使角色移动并使其跳跃动画正确的部分。尝试使用此脚本并使用玩家的isGrounded = false
组件上的运动值以及重力倍数;默认值和3.5的重力倍数对我来说很有趣!
Rigidbody2D
我还花了一些时间来重组您的代码。您不一定现在就不必担心太多的组织,但是我认为这可能会使您感兴趣,因为您仍在学习。
如您所见,脚本中的每个方法都处理一个具体任务。例如,有一种方法专门用于处理动画,另一种方法可以让播放器跳转。以此方式设置代码是一个好主意,这样,如果以后必须更改一个方面(例如玩家移动),那么所有相关代码都放在同一位置。我认为这对于创建处理球员“动作”(例如跳跃或进攻)的方法尤为正确。如果您有足够的它们,您甚至可以创建整个动作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<Rigidbody2D>();
myAnimator = GetComponent<Animator>();
}
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;
}
}
}
。
最后要提到的是这一行代码:
class
我发现这是确定播放器何时接地的更简便方法。为此,我向播放器添加了一个孩子isGrounded = Physics2D.OverlapCircle(groundPoint.position, groundRadius, whatIsGround);
,并添加了一个彩色图标以方便放置(您可以通过点击GameObject
名称旁边的彩色框来完成此操作),然后将其放置在在球员的脚之间。