25、僵尸生命和子弹伤害
僵尸生命,用set访问器实现判断僵尸死亡
![](https://img-blog.csdnimg.cn/61b017839b364c0ea80948c1b648da92.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_17,color_FFFFFF,t_70,g_se,x_16)
更新状态
![](https://img-blog.csdnimg.cn/62fbba87c11148409546a343a231ba5c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
在僵尸管理器中把该僵尸remove掉
![](https://img-blog.csdnimg.cn/29430c1f1efb417899fdd875e0e50493.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_18,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/c7c2d6190f3342c1a1d919fadee0e9f3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
子弹伤害实现,由于子弹的伤害由植物决定,所以在PeaShooter.cs中添加代码
![](https://img-blog.csdnimg.cn/481844d153fb4dfe9167952a70450cf2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
实例化传给Bullet
![](https://img-blog.csdnimg.cn/bfdc9e4a4576468bba03b22b1b813a68.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
在Bullet中更新代码:
![](https://img-blog.csdnimg.cn/e33aa3baf3344a4c92e9af448a85c00c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
最后子弹攻击僵尸,僵尸扣血的逻辑如下:
在Bullet.cs中更新代码
![](https://img-blog.csdnimg.cn/816ecb0541c8443899ed789837c6e0dc.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
在Zombie.cs中更新代码:
![](https://img-blog.csdnimg.cn/2417ba11e7fb4ec3aa2936d40f83bf83.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_14,color_FFFFFF,t_70,g_se,x_16)
测试:
![](https://img-blog.csdnimg.cn/a78cf28b844b4a79be7d6922baba6bd2.gif)
26、实现僵尸头掉了
首先导入僵尸头的动画
![](https://img-blog.csdnimg.cn/51398aaee430463ca5d8ca0eb39c1102.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/c0b0fac479814260824595086381d720.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
保存成预制体
![](https://img-blog.csdnimg.cn/b737bf34fc1a458f91caaf0d97b98073.png)
在GameConf.cs中配置
![](https://img-blog.csdnimg.cn/e9bcc4552228496fbeb762941fea9cc2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_16,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/f7a049ac131c40458e56e170b05e1ba4.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
僵尸头预制体配置好后,就开始配置僵尸头掉后,身体的动画,显然头掉后,需要重新实例化一个头,但是原来的僵尸行走动画要替换成掉头后僵尸行走的动画。
新建一个动画,并将头掉后僵尸行走的帧放进去
![](https://img-blog.csdnimg.cn/dfb8cf537fa74469bc1817315670ab8f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_16,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/f93c8f28b8774031a56de6ed740138f3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
同时僵尸头掉后攻击的动画,也要导入
![](https://img-blog.csdnimg.cn/839427674e6948d39e802f3b410ff2a9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
然后修改它的帧
![](https://img-blog.csdnimg.cn/871a4d18de334b898828056991675d98.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
最后由于头掉了这个动作一次性的,所以将动画循环播放取消
![](https://img-blog.csdnimg.cn/bc6a499254564eab9ad6916ee92a33ef.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
接下来是碰撞的问题,首先阳光、子弹、僵尸都是有碰撞器的,
而只有子弹和僵尸是有碰撞逻辑的,而且僵尸是加了触发器的,来自定义这个碰撞过程,所以需要在2D物理中设置下:
![](https://img-blog.csdnimg.cn/9e7f35a8d1614e43ab7a5ad012eb6aa6.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
好以上就是所有的场景相关的配置,最后开始写逻辑,首先为掉下的头附加一个脚本Zombie_Head.cs,并添加代码:
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class Zombie_Head : MonoBehaviour
{
private Animator animator;
private bool isOver = false;
private void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
// 头还没有掉,并且播放已经结束,normalizedTime在[0,1]之间
if (!isOver&&animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1)
{
// 播放完毕
animator.speed = 0;
isOver = true;
// 2s之后销毁自身
Invoke("Destroy",2);
}
}
private void Destroy()
{
Destroy(gameObject);
}
}
![](https://img-blog.csdnimg.cn/1dedd32a912f4d4c8a07a9b174f35274.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/15270eb64e1e457992cb73a5ee4bbd9e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/c16f60b425884e8f800b67aed699d518.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
最后,子弹攻击僵尸,僵尸自身也有一个颜色变化,所以仿照僵尸攻击太阳花时,太阳花的变化,这里直接搬过来就行了
![](https://img-blog.csdnimg.cn/1901435441fe46a281f940ed2fdb839f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAfkxvbWlzc34=,size_20,color_FFFFFF,t_70,g_se,x_16)
Zombie.cs更新代码如下:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using Random = UnityEngine.Random;
……
public class Zombie : MonoBehaviour
{
……
private SpriteRenderer spriteRenderer;
……
// 是否已经失去头
private bool isLostHead = false;
// 生命值
private int hp = 270;
public int Hp
{
get => hp;
set
{
hp = value;
if (hp <= 90 && !isLostHead)
{
// 头已经掉了
isLostHead = true;
walkAnimationStr = "Zombie_LostHead";
attackAnimationStr = "Zombie_LostHeadAttack";
// 创建一个头
GameObject.Instantiate(GameManager.instance.GameConf.Zombie_Head, animator.transform.position,
Quaternion.identity, null);
// 动画文本被改变,此使需要检测状态,才能做到动画马上更新
CheckState();
}
if (hp <= 0)
{
State = ZombieState.Dead;
}
}
}
……
// 攻击动画的名称
private string attackAnimationStr;
……
public ZombieState State
{
get => state;
// 如果状态被写入,则播放相关动画
set
{
state = value;
CheckState();
}
}
/// <summary>
/// 状态检测
/// </summary>
private void CheckState()
{
switch (State)
{
case ZombieState.Idel:
// 播放行走动画,但是要卡在第一帧
animator.Play(walkAnimationStr,0,0);
animator.speed = 0;
break;
case ZombieState.Walk:
// 从上一动画播放的normalizedTime继续播放,而不是从0帧开始
animator.Play(walkAnimationStr,0,animator.GetCurrentAnimatorStateInfo(0).normalizedTime);
animator.speed = 1;
break;
case ZombieState.Attack:
// 从上一动画播放的normalizedTime继续播放,而不是从0帧开始
animator.Play(attackAnimationStr,0,animator.GetCurrentAnimatorStateInfo(0).normalizedTime);
animator.speed = 1;
break;
case ZombieState.Dead:
break;
}
}
private void Awake()
{
// 从[1,4)中随机一个整数
int rangeWalk = Random.Range(1, 4);
// 在初始化时随机播放一个动画
switch (rangeWalk)
{
case 1:
walkAnimationStr = "Zombie_Walk1";
break;
case 2:
walkAnimationStr = "Zombie_Walk2";
break;
case 3:
walkAnimationStr = "Zombie_Walk3";
break;
}
attackAnimationStr = "Zombie_Attack";
}
void Start()
{
// 获得子物体的动画组件
animator = GetComponentInChildren<Animator>();
spriteRenderer = GetComponentInChildren<SpriteRenderer>();
ZombieManager.Instance.AddZombie(this);
GetGridByVerticalNum(Random.Range(0,5));
}
……
public void Hurt(int plantAttackValue)
{
Hp -= plantAttackValue;
StartCoroutine(ColorEF(0.2f, new Color(0.4f, 0.4f, 0.4f), 0.05f, null));
}
……
protected IEnumerator ColorEF(float wantTime, Color targetColor, float delayTime, UnityAction fun)
{
float currTime = 0;
float lerp;
while (currTime < wantTime)
{
yield return new WaitForSeconds(delayTime);
lerp = currTime / wantTime;
currTime += delayTime;
// 实现一个从白到红的插值计算,lerp为0就是白色(原色),如果为1就是Color(1,0.6f,0)
spriteRenderer.color = Color.Lerp(Color.white, targetColor, lerp);
}
// 恢复原来的附加色(白色)
spriteRenderer.color = Color.white;
if (fun != null) fun();
}
}
测试
![](https://img-blog.csdnimg.cn/2192cfaa56cf46318e4d11882e4006d6.gif)