一、创建受伤动画
找到相关受伤的动画素材,然后在Animation窗口创建动画。此处不再赘述。
此时在Animator
窗口删除刚才创建的两个动画,因为现在要采用另一种方式创建动画:采用Animator的Layer
方式
使用Animator→Layer创建受伤闪烁动画
受伤闪烁动画意为受伤后短暂无敌时间
点击右边+
号,创建新的动画图层,并命名为Hurt Layer
点击创建的新的图层的齿轮,将Weight
设置为1,Blending
设置为Additive
Weight为权重,即权重越高,动画播放优先级越高。
Blending为混合模式,Overrides为覆盖模式,Additive为叠加模式
在Animator窗口,右击选中Create State
创建新的状态
创建新的Animation
动画,更名为blueHurt2。将用此动画创建闪烁动画
在此动画下方点击Add Property
,选中Sprite Renderer.Material._Color
Add Property可以使此动画片段修改其中任意一个被添加的属性
展开被添加的属性,可以看到其中有多个从属性,可以在动画时间轴添加关键帧修改这些从属性
将Samples修改为6,并在0:2、0:4、1:0处打上关键帧,分别将Material._Color.a
设置为0.2、1、0.2
可以将鼠标点击对应的时间轴位置,然后修改需要修改的从属性,即可自动打上关键帧。
Material._Color.a为Alpha通道
在Hurt Layer动画图层中,将blueHurt2动画添加进来
由于此受伤后无敌动画需要触发进行,因此添加一个Trigger,命名为hurt
选中连线,在右下角将此Trigger添加进Condition中。并在上方设置好连线参数。
连接退出动画,选中连线,设置好退出参数
编写受伤闪烁触发器相关代码
打开PlayerAnimation
代码。由于添加的触发器(Trigger)是一次执行,因此不能写在Update()
方法内,另外新写一个方法。
public void PlayerHurt()
{
animator.SetTrigger("hurt");
}
由于是写的关于受伤相关的代码,并且根据正常游戏需求,受伤后需要处理的操作非常庞大,比如UI抖动、人物受击动画、人物受击位移、扣血、削减属性等等。因此,此时需要利用Unity自带的“事件”(Event)
进行处理。
打开Character
代码。在头部添加UnityEvent包。
using UnityEngine.Events;
添加新的全局变量
// 将Transform坐标传入事件中
public UnityEvent<Transform> OnTakeDamage;
由于此处打算编写受击位移,需要坐标值,所以将Transform传入UnityEvent
此时,在Player的组件列表中,Character内多了一个On Take Damage(Transform)
事件处理器。
只要此事件触发,会执行下方添加的所有方法。
将PlayAnimation拖入下面小格中
点击+号,添加PlayHurt()方法
将触发条件设置为Runtime Only
Editor And Runtime为编辑器运行和执行时
Runtime Only为只在执行时
在Character的TakeDamage()方法内,添加新的代码
// 执行受伤
OnTakeDamage?.Invoke(attacker.transform);
OnTakeDamage?用于判断此组件是否绑定了方法,如果绑定了则进一步处理。否则不进行处理
Invoke()方法为开始执行
attacker.transform将攻击者的坐标传入
此时开始Play,可以发现人物受伤后,无论怎么操作,受击闪烁都会执行。这就是Blending中叠加模式(Additive)
的效果
创建受击后撤动画
选择中blueHurt2,然后在右侧Motion中,选择blueHurt
在Animation中,选择blueHurt
,添加Color
的Property
在时间轴中打关键帧,调整颜色数值(可根据自己的需要进行更改)
编写受击后撤的代码
受击后撤需要两个变量,一个受伤时反弹施加的力,一个是否受伤的状态
// 受伤时反弹施加的力
public float hurtForce;
// 是否受伤的状态
public bool isHurt;
新建GetHurt()
方法,在里面写相关逻辑
public void GetHurt(Transform attacker)
{
isHurt = true;
// 受伤时强行使人物停止移动
rb.velocity = Vector2.zero;
// 用人物的x坐标减去攻击者的x坐标,如果得到一个负数,则人物在攻击者左侧。否则,在攻击者的右侧。
// 用差得到方向,乘以受伤的力即可得到加速的效果
Vector2 dir = new Vector2((transform.position.x - attacker.position.x), 0).normalized;
rb.AddForce(dir * hurtForce, ForceMode2D.Impulse);
}
normalized
属性为标准化属性,使数值无论多大,都标准化为1
normalized属性文档:https://docs.unity3d.com/cn/2022.3/ScriptReference/Vector2-normalized.html
修改FixedUpdate()
方法,进行进一步的判断
private void FixedUpdate()
{
if(!isHurt)
{
Move();
}
}
在Player的On Take Damage(Transform)
中,添加GetHurt()
方法
在Player的PlayerController
中,将Hurt Force
设置为自己想要的数值
此时执行,可以发现人物受击后,确实发生了后撤,但是后续无法进行操作
解决受击后撤后无法操作的问题
在Animator窗口中,选中blueHurt2
。接着,在右侧窗口中,选择Add Behavior
添加新的脚本,命名为HurtAnimation,并将新创建的脚本拖入Player文件夹中
打开HurtAnimation
public class HurtAnimation : StateMachineBehaviour
{
// OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
//override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
//
//}
// OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
//override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
//
//}
// OnStateExit is called when a transition ends and the state machine finishes evaluating this state
//override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
//
//}
// OnStateMove is called right after Animator.OnAnimatorMove()
//override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
// // Implement code that processes and affects root motion
//}
// OnStateIK is called right after Animator.OnAnimatorIK()
//override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
//{
// // Implement code that sets up animation IK (inverse kinematics)
//}
}
OnStateEnter():当被绑定此代码的动画进入时执行
OnStateUpdate():当被绑定此代码的动画执行时执行
OnStateExit():当被绑定此代码的动画退出时执行
在OnStateExit()中,获取PlayerController组件,修改当中的isHurt为false
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.GetComponent<PlayerController>().isHurt = false;
}
二、创建死亡动画
找到相关死亡的动画素材,然后在Animation窗口创建动画。此处不再赘述。
在Animator窗口,创建死亡动画
将Hurt Layer的Blending
更改为覆盖模式(Override)
将死亡动画拖入Animator窗口中,与Any State
连线。因为,任何情况都会进入死亡动画
在左侧Parameters窗口中,创建新的参数isDead
选择连线,将isDead
参数添加进条件,并调整相关参数
将BlueDeath与Exit连线,并将isDead
参数添加进条件,调整相关参数
编写死亡相关的代码
在Character文件中,新建onDie
事件属性。由于死亡后也需要处理很多的操作,所以在此创建为UnityEvent
事件对象。
public UnityEvent onDie;
在TakeDamage
中,调用此创建全局变量
onDie?.Invoke();
在PlayerController文件中,创建isDead
全局属性
// 是否死亡状态
public bool isDead;
创建PlayerDead()
方法,禁止玩家的操作输入
public void PlayerDead()
{
isDead = true;
playerInputControl.Gameplay.Disable();
}
在PlayerAnimation文件中,链接Controller中的isDead
状态
animator.SetBool("isDead", playerController.isDead);
将PlayerController组件拖入,并绑定PlayerDead()
方法
此时将玩家血量设置到最低,受伤后就会播放死亡动画。但是,目前会不断反复播放。
解决死亡动画反复播放的问题
选择BlueDeath动画,在右侧将LoopTime取消勾选,即可单次执行
只要连接了Any State的动画,基本就不存在反复执行的问题。连接了Any State的动画,即可根据需求,判断是否需要反复执行。
标签:动画,受伤,创建,2D,Unity,添加,public,Animator From: https://www.cnblogs.com/xinlindeyu/p/17914057.html