在之前的笔记里已经实现了敌人以及击杀敌人,本节丰富敌人细节;
1. 敌人移动
1.1 青蛙
青蛙的移动逻辑是左右移动,到达左端点后转向,再向右端点移动。为了确定左右端点,可以创建两个object实体作为锚点:
通过获取这两个实体的位置来确定青蛙的左右移动端点,而要获取位置,直接在代码里声明两个transform对象,并在unity中拖拽实现绑定(因此要对青蛙sprite创建一个脚本元素):
public Transform leftpoint, rightpoint;
public float speedx, speedy; // 这个速度值不能给太高 不然容易出问题
private float leftx, rightx; // 左右端点赋值
在start函数中给左右断点位置赋值:
leftx = leftpoint.position.x;
rightx = rightpoint.position.x;
移动函数:
void movement()
{
if (faceleft)
{
if (leftx > transform.position.x) // 到达了左点
{
// 掉头
transform.localScale = new Vector3(-1, 1, 1);
faceleft = false;
}
else if (coll.IsTouchingLayers(ground)) // 一定要用else if 不然转向之后顺序再次执行这句 导致背身跳BUG
{
anim.SetBool("jumping",true);
rb.velocity = new Vector2(-speedx, speedy);
}
}
else
{
if (rightx < transform.position.x) // 到达了右点
{
// 掉头
transform.localScale = new Vector3(1, 1, 1);
faceleft = true;
}
else if (coll.IsTouchingLayers(ground))
{
anim.SetBool("jumping", true);
rb.velocity = new Vector2(speedx, speedy);
}
}
}
注意这里必须是先进行是否到达端点的判断再进行移动,否则容易过分出界,同时,移动的代码12-15行,必须也是else if;牢记掉头方法
1.2 青蛙的动画
青蛙有三个状态,跳,落,idle,死亡因此为这四个状态添加动画:
其中,death的条件设置为一个triger型参数;
动画切换函数:
void switchAnimation()
{
if (anim.GetBool("jumping"))
{
if(rb.velocity.y < 0.1f)
{
anim.SetBool("falling", true);
anim.SetBool("jumping", false);
}
}
if (coll.IsTouchingLayers(ground) && anim.GetBool("falling"))
{
anim.SetBool("falling", false);
}
}
死亡动画效果后续说明
1.3 鹰以及鹰的移动
从青蛙的左右移动切换成上下移动即可;
2. 敌人死亡动画
由于敌人的死亡特效是一致的,重复在每一个脚本中编写对应切换代码当然可以,但不是简洁的;因此,这里引入了一种类似c++中类继承的机制;
我们创建一个Enemy脚本,统一管理敌人的部分动画:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
protected Animator anim; // 用protected关键字是为了能在子父级调用中使用
// Start is called before the first frame update
protected virtual void Start() // virtual关键字是为了子级能重写该函数
{
anim = GetComponent<Animator>();
}
public void death()
{
Destroy(gameObject); // 谁调用这个函数就消灭谁?
}
public void jumpedOn()
{
anim.SetTrigger("death");
}
}
Enemy脚本中,在start函数里首先声明了动画接口anim,并且利用death()和jumpedOn()来定义死亡动画的触发以及消灭对象,其他敌人的脚本中直接调用该函数即可;
因此,在Frog脚本中,我们不再直接继承MonoBehaviour,而是继承Enemy,同时,因为Enemy默认初始化了anim对象,由于Frog继承了它,因此,anim对象不用在Frog中再次声明;
因此,在player脚本中,当我们判断出踩踏到Enemy时,我们只需要声明一个Enemy的临时变量,利用这个变量调用Enemy中的函数即可:
player脚本中判断是否踩到敌人:
if (collision.gameObject.tag == "enemy" && anim.GetBool("falling"))
{
Enemy enemy = collision.gameObject.GetComponent<Enemy>();
enemy.jumpedOn();
// 踩到的同时再次起跳
rb.velocity = new Vector2(rb.velocity.x, jumpforce * Time.deltaTime);
anim.SetBool("jumping", true);
}
但是如果此时顺势直接调用Enemy.death()的话,敌人会直接消失,不会切换到爆炸死亡的动画。我们希望当爆炸动画播放完成后才调用death()函数,因此,引入一个很重要的东西——Event;
打开青蛙的爆炸动画,添加event,并将其移动到动画末尾:
并将event设置为death():
此时,当爆炸动画播放完成后自动调用这个death()函数,青蛙消失;
3. 添加音频
首先找到音频素材(在Asset Store里找)
3.1 BGM
为player添加Audio Source,将找好的BGM拖进去:
勾选Play On Awake和Loop实现进入游戏自动播放和循环播放;
3.2 跳跃声
找到音频素材,创建Audio Source,在player脚本代码中声明变量:
public AudioSource jumpAudio, CollectionAudio, hurtAudio;
在Unity中利用拖拽的方式完成绑定;
然后在跳跃处的代码添加:
jumpAudio.Play();
实现音频的播放(其他例如hurt音效同理);