【Unity植物大战僵尸】僵尸生命、子弹伤害和僵尸头掉了(十四)

25、僵尸生命和子弹伤害

僵尸生命,用set访问器实现判断僵尸死亡
更新状态
在僵尸管理器中把该僵尸remove掉
子弹伤害实现,由于子弹的伤害由植物决定,所以在PeaShooter.cs中添加代码
实例化传给Bullet
在Bullet中更新代码:
最后子弹攻击僵尸,僵尸扣血的逻辑如下:
在Bullet.cs中更新代码
在Zombie.cs中更新代码:
测试:

26、实现僵尸头掉了

首先导入僵尸头的动画
 
保存成预制体
在GameConf.cs中配置
僵尸头预制体配置好后,就开始配置僵尸头掉后,身体的动画,显然头掉后,需要重新实例化一个头,但是原来的僵尸行走动画要替换成掉头后僵尸行走的动画。
新建一个动画,并将头掉后僵尸行走的帧放进去
同时僵尸头掉后攻击的动画,也要导入
然后修改它的帧
最后由于头掉了这个动作一次性的,所以将动画循环播放取消
接下来是碰撞的问题,首先阳光、子弹、僵尸都是有碰撞器的, 而只有子弹和僵尸是有碰撞逻辑的,而且僵尸是加了触发器的,来自定义这个碰撞过程,所以需要在2D物理中设置下:
好以上就是所有的场景相关的配置,最后开始写逻辑,首先为掉下的头附加一个脚本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);
    }
}
最后,子弹攻击僵尸,僵尸自身也有一个颜色变化,所以仿照僵尸攻击太阳花时,太阳花的变化,这里直接搬过来就行了
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();
    }
}

测试

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~Lomiss~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值