当前位置: 首页 > article >正文

Unity类银河恶魔城学习记录10-13 p101 Improve aliment - shock源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考
此代码仅为较上一P有所改变的代码

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili

ShockStrike_Controller.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShockStrike_Controller : MonoBehaviour
{
    [SerializeField] private CharacterStats targetsStats;
    [SerializeField] private float speed;
    private int damage;

    private Animator anim;
    private bool triggered;

    public void Setup(int _damage,CharacterStats _targetStats)
    {
        damage = _damage;
        targetsStats = _targetStats;
    }

    void Start()
    {
        anim = GetComponentInChildren<Animator>();
    }

    // Update is called once per frame
    void Update()
    {

        if (!targetsStats)
            return;

        if (triggered)
            return;

        transform.position = Vector2.MoveTowards(transform.position, targetsStats.transform.position, speed * Time.deltaTime);
        transform.right = transform.position - targetsStats.transform.position;
        //https://docs.unity3d.com/cn/current/ScriptReference/Transform-right.html
        //世界空间中变换的红轴

        if (Vector2.Distance(transform.position,targetsStats.transform.position)<.1f)
        {
            anim.transform.localRotation = Quaternion.identity;
            anim.transform.localPosition = new Vector3(0, .5f);

            transform.localRotation = Quaternion.identity;
            transform.localScale = new Vector3(3, 3);


            triggered = true;

            Invoke("DamageAmdSelfDestroy", .2f);
            anim.SetTrigger("Hit");
         
        }
    }

    private void DamageAmdSelfDestroy()
    {
        targetsStats.ApplyShock(true);
        Destroy(gameObject, .4f);
        targetsStats.TakeDamage(damage);
    }
}

CharacterStats.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterStats : MonoBehaviour
{
    private EntityFX fx;


    [Header("Major stats")]
    public Stat strength; // 力量 增伤1点 爆伤增加 1% 物抗
    public Stat agility;// 敏捷 闪避 1% 闪避几率增加 1%
    public Stat intelligence;// 1 点 魔法伤害 1点魔抗 
    public Stat vitality;//加血的

    [Header("Offensive stats")]
    public Stat damage;
    public Stat critChance;      // 暴击率
    public Stat critPower;       //150% 爆伤

    [Header("Defensive stats")]
    public Stat maxHealth;
    public Stat armor;
    public Stat evasion;//闪避值
    public Stat magicResistance;

    [Header("Magic stats")]
    public Stat fireDamage;
    public Stat iceDamage;
    public Stat lightingDamage;


    public bool isIgnited;  // 持续烧伤
    public bool isChilded;  // 削弱护甲 20%
    public bool isShocked;  // 降低敌人命中率

    [SerializeField] private float ailmentsDuration = 4;
    private float ignitedTimer;
    private float chilledTimer;
    private float shockedTimer;


    private float igniteDamageCooldown = .3f;
    private float ignitedDamageTimer;
    private int igniteDamage;
    [SerializeField] private GameObject shockStrikePrefab;
    private int shockDamage;


    public System.Action onHealthChanged;//使角色在Stat里调用UI层的函数

    [SerializeField] public int currentHealth;


    protected virtual void Start()
    {
        critPower.SetDefaultValue(150);//设置默认爆伤
        currentHealth = GetMaxHealthValue();

        fx = GetComponent<EntityFX>();
    }

    protected virtual void Update()
    {
        //所有的状态都设置上默认持续时间,持续过了就结束状态
        ignitedTimer -= Time.deltaTime;
        chilledTimer -= Time.deltaTime;
        shockedTimer -= Time.deltaTime;
        ignitedDamageTimer -= Time.deltaTime;

        if (ignitedTimer < 0)
            isIgnited = false;
        if (chilledTimer < 0)
            isChilded = false;
        if (shockedTimer < 0)
            isShocked = false;

        //被点燃后,出现多段伤害后点燃停止
        if (ignitedDamageTimer < 0 && isIgnited)
        {
            Debug.Log("Take Burning Damage" + igniteDamage);
            DecreaseHealthBy(igniteDamage);
            if (currentHealth < 0)
                Die();
            ignitedDamageTimer = igniteDamageCooldown;
        }
    }

    public virtual void DoDamage(CharacterStats _targetStats)//计算后造成伤害函数
    {
        if (TargetCanAvoidAttack(_targetStats))设置闪避
        {
            return;
        }



        int totleDamage = damage.GetValue() + strength.GetValue();

        //爆伤设置
        if (CanCrit())
        {
            totleDamage = CalculateCriticalDamage(totleDamage);
        }

        totleDamage = CheckTargetArmor(_targetStats, totleDamage);//设置防御

        //_targetStats.TakeDamage(totleDamage);
        DoMagicaDamage(_targetStats);
    }

    public virtual void DoMagicaDamage(CharacterStats _targetStats)//法伤计算
    {
        int _fireDamage = fireDamage.GetValue();
        int _iceDamage = iceDamage.GetValue();
        int _lightingDamage = lightingDamage.GetValue();

        int totleMagicalDamage = _fireDamage + _iceDamage + _lightingDamage + intelligence.GetValue();
        totleMagicalDamage = CheckTargetResistance(_targetStats, totleMagicalDamage);

        _targetStats.TakeDamage(totleMagicalDamage);

        //让元素效果取决与伤害
        bool canApplyIgnite = _fireDamage > _iceDamage && _fireDamage > _lightingDamage;
        bool canApplyChill = _iceDamage > _lightingDamage && _iceDamage > _fireDamage;
        bool canApplyShock = _lightingDamage > _fireDamage && _lightingDamage > _iceDamage;

        //防止循环在所有元素伤害为0时出现死循环
        if (Mathf.Max(_fireDamage, _iceDamage, _lightingDamage) <= 0)
            return;

        //为了防止出现元素伤害一致而导致无法触发元素效果
        //循环判断触发某个元素效果
        while (!canApplyIgnite && !canApplyChill && !canApplyShock)
        {
            if (Random.value < .25f)
            {
                canApplyIgnite = true;
                Debug.Log("Ignited");
                _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
                return;
            }
            if (Random.value < .35f)
            {
                canApplyChill = true;
                Debug.Log("Chilled");
                _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
                return;
            }
            if (Random.value < .55f)
            {
                canApplyShock = true;
                Debug.Log("Shocked");
                _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
                return;
            }

        }

        //给点燃伤害赋值
        if (canApplyIgnite)
        {
            _targetStats.SetupIgniteDamage(Mathf.RoundToInt(_fireDamage * .2f));
        }

        if (canApplyShock)
            _targetStats.SetupShockStrikeDamage(Mathf.RoundToInt(_lightingDamage * .1f));

        _targetStats.ApplyAilments(canApplyIgnite, canApplyChill, canApplyShock);
    }

    private static int CheckTargetResistance(CharacterStats _targetStats, int totleMagicalDamage)//法抗计算
    {
        totleMagicalDamage -= _targetStats.magicResistance.GetValue() + (_targetStats.intelligence.GetValue() * 3);
        totleMagicalDamage = Mathf.Clamp(totleMagicalDamage, 0, int.MaxValue);
        return totleMagicalDamage;
    }

    public void ApplyAilments(bool _ignite, bool _chill, bool _shock)//判断异常状态
    {
        bool canApplyIgnite = !isIgnited && !isChilded && !isShocked;
        bool canApplyChill = !isIgnited && !isChilded && !isShocked;
        bool canApplyShock = !isIgnited && !isChilded;
        //使当isShock为真时Shock里的函数仍然可以调用

        if (_ignite && canApplyIgnite)
        {
            isIgnited = _ignite;
            ignitedTimer = ailmentsDuration;

            fx.IgniteFxFor(ailmentsDuration);
        }
        if (_chill && canApplyChill)
        {
            isChilded = _chill;
            chilledTimer = ailmentsDuration;

            float slowPercentage = .2f;

            GetComponent<Entity>().SlowEntityBy(slowPercentage, ailmentsDuration);

            fx.ChillFxFor(ailmentsDuration);
        }
        if (_shock && canApplyShock)
        {
            if(!isShocked)
            {
                ApplyShock(_shock);
            }
            else
            {
                if (GetComponent<Player>() != null)//防止出现敌人使玩家进入shock状态后也出现闪电
                    return;
                HitNearestTargetWithShockStrike();
            }//isShock为真时反复执行的函数为寻找最近的敌人,创建闪电实例并传入数据

        }
    }

    public void ApplyShock(bool _shock)
    {
        if (isShocked)
            return;

        isShocked = _shock;
        shockedTimer = ailmentsDuration;

        fx.ShockFxFor(ailmentsDuration);
    }

    private void HitNearestTargetWithShockStrike()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 25);//找到环绕自己的所有碰撞器

        float closestDistance = Mathf.Infinity;//正无穷大的表示形式(只读)
        Transform closestEnemy = null;


        //https://docs.unity3d.com/cn/current/ScriptReference/Mathf.Infinity.html
        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null && Vector2.Distance(transform.position, hit.transform.position) > 1)// 防止最近的敌人就是Shock状态敌人自己
            {
                float distanceToEnemy = Vector2.Distance(transform.position, hit.transform.position);//拿到与敌人之间的距离
                if (distanceToEnemy < closestDistance)//比较距离,如果离得更近,保存这个敌人的位置,更改最近距离
                {
                    closestDistance = distanceToEnemy;
                    closestEnemy = hit.transform;
                }
            }

            if (closestEnemy == null)
                closestEnemy = transform;
        }

        if (closestEnemy != null)
        {
            GameObject newShockStrike = Instantiate(shockStrikePrefab, transform.position, Quaternion.identity);
            newShockStrike.GetComponent<ShockStrike_Controller>().Setup(shockDamage, closestEnemy.GetComponent<CharacterStats>());
        }
    }

    public void SetupIgniteDamage(int _damage) => igniteDamage = _damage;//给点燃伤害赋值
    public void SetupShockStrikeDamage(int _damage) => shockDamage = _damage;

    public virtual void TakeDamage(int _damage)//造成伤害是出特效
    {
        DecreaseHealthBy(_damage);


        if (currentHealth < 0)
            Die();

    }
    protected virtual void DecreaseHealthBy(int _damage)//此函数用来改变当前声明值,不调用特效
    {
        currentHealth -= _damage;

        if(onHealthChanged != null)
        {
            onHealthChanged();
        }
    }
    protected virtual void Die()
    {

    }
    private static int CheckTargetArmor(CharacterStats _targetStats, int totleDamage)//设置防御
    {

        //被冰冻后,角色护甲减少
        if (_targetStats.isChilded)
            totleDamage -= Mathf.RoundToInt(_targetStats.armor.GetValue() * .8f);
        else
            totleDamage -= _targetStats.armor.GetValue();
        totleDamage = Mathf.Clamp(totleDamage, 0, int.MaxValue);
        return totleDamage;
    }

    private bool TargetCanAvoidAttack(CharacterStats _targetStats)//设置闪避
    {
        int totleEvation = _targetStats.evasion.GetValue() + _targetStats.agility.GetValue();

        //我被麻痹后
        //敌人的闪避率提升
        if (isShocked)
            totleEvation += 20;

        if (Random.Range(0, 100) < totleEvation)
        {
            return true;
        }
        return false;
    }

    private bool CanCrit()//判断是否暴击
    {
        int totleCriticalChance = critChance.GetValue() + agility.GetValue();

        if (Random.Range(0, 100) <= totleCriticalChance)
        {
            return true;
        }

        return false;
    }

    private int CalculateCriticalDamage(int _damage)//计算暴击后伤害
    {
        float totleCirticalPower = (critPower.GetValue() + strength.GetValue()) * .01f;

        float critDamage = _damage * totleCirticalPower;

        return Mathf.RoundToInt(critDamage);//返回舍入为最近整数的
    }
    public int GetMaxHealthValue()
    {

        return maxHealth.GetValue() + vitality.GetValue() * 10;

    }//统计生命值函数
}


http://www.kler.cn/a/271594.html

相关文章:

  • RK3568中使用QT opencv(显示基础图像)
  • 如何解决Unit sshd.service could not be found
  • 【MySQL】MySQL客户端连接用 localhost和127.0.0.1的区别
  • 网站如何正式上线(运维详解)
  • Linux 4.19内核中的内存管理:x86_64架构下的实现与源码解析
  • 树状数组讲解
  • 豆瓣电影信息爬取与可视化分析
  • 【MySQL】的相关面试题(四)
  • 【Python】实现一个鼠标连点器
  • 力扣第 126 场双周赛(A~B)
  • 每日一题:LeetCode2.两数相加
  • mysql读写分离及高可用集群常见问题
  • 观测云在 .NET 业务中分析性能问题的最佳实践
  • OpenCV(七)——灰度图像的阙值处理以及图像的边界填充
  • 网络面试题
  • 模型的参数量、计算量、延时等的关系
  • 数据结构的概念大合集04(队列)
  • 学习vue3第五节(reactive 及其相关)
  • 裁员潮下,打工人的自我修养
  • 微信小程序一次性订阅requestSubscribeMessage授权和操作详解
  • MyBatis中 #{} 和 ${} 区别
  • Python实战:NumPy数组与矩阵操作入门
  • 提高安全投资回报:威胁建模和OPEN FAIR™风险分析
  • 数据类型【mysql数据库】
  • 数据可视化-ECharts Html项目实战(2)
  • 【Python循环3/5】条件循环语句