一切都要从Update()和FixedUpdate()这两个折磨怪讲起:
- Update()在游戏运行时,每一帧都会调用一次该方法。但在不同的机器上,游戏运行效率,帧率是不同的;就算在一台机器上跑,帧率也是有浮动的。这就导致对Update()的调用并不是严格周期性的,如果将游戏中对刚体的运算放在Update()里——比如角色的移动、跳跃,可能会导致角色的移动速度、跳跃高度有变化,这不是我们想要的。
- FixedUpdate()则是以固定周期调用(每0.02S调用一次),即使帧率不同,它的调用频率也是不变的,因此我们一般将刚体的运算放在FixedUpdate()中。
但这也会导致新的问题:
如果我们将角色的跳跃功能放在FixedUpdate()中,包括玩家输入检测和实现代码一并放在FixedUpdate()里,可能会遇到“按下跳跃键但是角色没反应”的情况。
这应该是FixedUpdate()方法的弊端,导致我们有时按下跳跃键后,输入并没有被FixedUpdate()接收。
因此我们可以将输入检测放在Update()里,将跳跃代码放在FixedUpdate()里。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FinalMovement : MonoBehaviour
{
private Rigidbody2D rb;
private Animator anim;
private Collider2D Ccoll;
public LayerMask ground;
public Transform groundCheck;
private float speed, jumpForce;
private bool isJump, isGround;
private int jumpCount;
private bool jumpPressed;//当跳跃键按下的时候
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
Ccoll = GetComponent<CircleCollider2D>();
speed = 7f;
jumpForce = 7f;
jumpCount = 2;
}
void Update()
{
if(Input.GetButtonDown("Jump") && jumpCount>0)
{
jumpPressed = true;
}
}
private void FixedUpdate()
{
Movement();
//检测是否在地面
isGround=Ccoll.IsTouchingLayers(ground);
Jump();
switchAnim();
}
private void Movement()
{
float horizontalMove = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(horizontalMove * speed, rb.velocity.y);//设置速度
if(horizontalMove!=0)
{
transform.localScale = new Vector3(horizontalMove, 1, 1);//更改朝向
}
}
private void Jump()
{
if(isGround)
{
jumpCount = 2;
isJump = false;
}
if (jumpPressed && isGround)
{
isJump = true;
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
jumpCount--;
jumpPressed = false;//别忘了设置
}
else if (jumpPressed && !isGround && jumpCount > 0)//在空中按下跳跃键
{
rb.velocity = new Vector2(rb.velocity.y, jumpForce);
jumpCount--;
jumpPressed = false;
}
}
private void switchAnim()
{
anim.SetFloat("Running", Mathf.Abs(rb.velocity.x));
if(Ccoll.IsTouchingLayers(ground))
{
anim.SetBool("Falling", false);
}
else if(rb.velocity.y>0)//跳跃
{
anim.SetBool("Jumping", true);
anim.SetBool("Falling", false);
}
else if(rb.velocity.y<0)//下落
{
anim.SetBool("Jumping", false);
anim.SetBool("Falling", true);
}
}
}