学习资源:B站 M_Studio《Unity教程2D入门》16
Unity Assets:Sunnyland
Day11
修复自然下落时碰到敌人时不消灭敌人的Bug
问题:
按照之前代码里的逻辑,当player碰到敌人,且状态为fall时,才会将敌人消灭。然而如果是在更高处掉下来时踩到敌人,由于不处于fall状态,所以不会消灭敌人。
思路:
让player只要下落就切换为fall状态。
那么如何判断它在下落呢?
向上冲的速度没有了,同时它不在地面上。
SwitchAnim函数的开头添加:
if(rb.velocity.y < 0.1f && !coll.IsTouchingLayers(ground))
{
anim.SetBool("isFalling", true);
}
当然,动画控制器中也要添加相应的动画过渡效果。
判断条件为isFalling == true
给敌人添加动画事件
预期结果:AI敌人青蛙通过跳跃来移动。
首先,在动画控制器中设置好各个动画间的关系。
编辑脚本,进行动画间的切换 。
- Movement中修改竖直方向的速度为jumpforce
rb.velocity = new Vector2(-speed * Time.deltaTime, jumpforce);
-
如果踩在地面上,它才跳。——添加一个在地面的判断条件
-
达到最高点时,下落。——添加SwitchAnim函数
-
落到地面时,保持idle状态一会儿。继续跳。——添加动画事件
在idle的动画末尾添加动画事件,就可以调用它脚本中的函数。
调用Movement函数。
这里出现了一个bug:我的蛙跳到最左边以后,即使转向了向右跳,但是整体方向还是往左的。而且当速度变为正的以后它就会消失掉。而且跳跃过程中速度不固定。
至于为什么会消失掉,暂时还不是很明白。
可能与Time.deltatime有关系,这里为什么不能这样写呢?
(可能是因为Movement并不是在Update中调用的,因此deltatime并不是每帧的时间,而是叠加的?所以值会越来越大,速度也会越来越大。)
rb.velocity = new Vector2(-speed*Time.deltaTime, jumpforce * Time.deltaTime);
将上面代码中的Time.deltatime删去后,青蛙跳跃正常。不会消失。
只是转向还有点问题。
解决方法:
在修改faceLeft和转向后,立刻修改青蛙的速度。
最后,将speed和jumpforce调整为一个适当的值即可。
当前代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFrog : MonoBehaviour
{
public Transform leftPoint, rightPoint;
public int speed = 2;
public int jumpforce = 6;
public LayerMask ground;
private Rigidbody2D rb;
private bool faceLeft = true;
private float leftx, rightx;
private Animator anim;
private Collider2D coll;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
coll = GetComponent<Collider2D>();
leftx = leftPoint.position.x;
rightx = rightPoint.position.x;
Destroy(leftPoint.gameObject);
Destroy(rightPoint.gameObject);
Movement();
}
// Update is called once per frame
void Update()
{
SwitchAnim();
}
void Movement()
{
//如果碰到地面
if (coll.IsTouchingLayers(ground))
{
Debug.Log("当前速度faceleft" + faceLeft);
//如果面朝左
if (faceLeft)
{
rb.velocity = new Vector2(-speed, jumpforce);
Debug.Log("当前速度x" + rb.velocity.x);
Debug.Log("当前速度y" + rb.velocity.x);
anim.SetBool("isJumping", true);
//如果达到左边界
if (transform.position.x < leftx)
{
transform.localScale = new Vector3(-1, 1, 1);
faceLeft = false;
rb.velocity = new Vector2(speed, jumpforce);
}
}
//面朝右,同理
else
{
rb.velocity = new Vector2(speed, jumpforce);
anim.SetBool("isJumping", true);
if (transform.position.x > rightx)
{
transform.localScale = new Vector3(1, 1, 1);
faceLeft = true;
rb.velocity = new Vector2(-speed, jumpforce);
}
}
}
}
void SwitchAnim()
{
//最高点切换为下落动画
if (anim.GetBool("isJumping"))
{
if (rb.velocity.y < 0)
{
anim.SetBool("isJumping", false);
anim.SetBool("isFalling", true);
}
}
//碰到地面切换为idle
if (coll.IsTouchingLayers(ground) && anim.GetBool("isFalling"))
{
anim.SetBool("isFalling", false);
}
}
void DestroySelf()
{
Destroy(gameObject);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
public float speed = 400;
public float jumpforce = 400;
[Space]
public LayerMask ground;//获取地面信息
public Collider2D coll;
[Space]
public int cherry;
public Text cherryNumber;
[Space]
public Animator frogAnim;
private Rigidbody2D rb;
private Animator anim;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
cherry = 0;//物品数量初始化为0
}
// Update is called once per frame
void FixedUpdate()
{
if(!anim.GetBool("isHurt"))
{
Movement();
}
SwitchAnim();
}
void Movement()
{
float horizontalmove = Input.GetAxis("Horizontal");
float direction = Input.GetAxisRaw("Horizontal");
//角色移动
if(horizontalmove!=0)
{
rb.velocity = new Vector2(speed * horizontalmove * Time.deltaTime, rb.velocity.y);
anim.SetBool("isRunning", true);
}
else
{
anim.SetBool("isRunning", false);
}
//角色朝向
if(direction!=0)
{
transform.localScale = new Vector3(direction, 1, 1);
}
//角色跳跃
if(Input.GetButtonDown("Jump") && coll.IsTouchingLayers(ground))
{
rb.velocity = new Vector2(rb.velocity.x, jumpforce * Time.deltaTime);
anim.SetBool("isJumping", true);
anim.SetBool("isIdle", false);
}
}
void SwitchAnim()
{
if(rb.velocity.y < 0.1f && !coll.IsTouchingLayers(ground))
{
anim.SetBool("isFalling", true);
}
//最高点切换为下落动画
if(anim.GetBool("isJumping"))
{
if(rb.velocity.y < 0)
{
anim.SetBool("isJumping", false);
anim.SetBool("isFalling", true);
}
}
else if(anim.GetBool("isHurt"))
{
anim.SetBool("isRunning", false);
if(Mathf.Abs(rb.velocity.x) <0.1f)
{
anim.SetBool("isHurt", false);
anim.SetBool("isIdle", true);
}
}
//碰到地面切换为idle
else if(coll.IsTouchingLayers(ground))
{
anim.SetBool("isFalling", false);
anim.SetBool("isIdle", true);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
//如果碰撞体的tag是Collection,则销毁
if(collision.tag == "Collection")
{
Destroy(collision.gameObject);
cherry += 1;
cherryNumber.text = cherry.ToString();
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
//碰到敌人的时候
if(collision.gameObject.tag == "Enemy")
{
EnemyFrog Frog = collision.gameObject.GetComponent<EnemyFrog>();
//如果是下落状态
if (anim.GetBool("isFalling"))
{
//frogAnim.SetBool("isDead", true);
//敌人才会消失
//Destroy(collision.gameObject);
//踩完后垫着敌人小跳一下
rb.velocity = new Vector2(rb.velocity.x, jumpforce * Time.deltaTime);
anim.SetBool("isJumping", true);
}
//否则,如果在左侧碰到敌人
else if(transform.position.x < collision.transform.position.x)
{
//向左反弹
rb.velocity = new Vector2(-6, rb.velocity.y);
anim.SetBool("isHurt", true);
}
//右侧同理
else if (transform.position.x > collision.transform.position.x)
{
anim.SetBool("isHurt", true);
//向右反弹
rb.velocity = new Vector2(6, rb.velocity.y);
}
}
}
}