Unity类银河恶魔城学习记录10-10 p98 UI health bar源代码

news2025/3/16 0:35:47

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

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

HealthBar_UI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using UnityEngine.UIElements;
using UnityEngine.UI;

public class HealthBar_UI : MonoBehaviour
{
    private Entity entity;
    private CharacterStats myStats;
    private RectTransform myTransform;
    private Slider slider;


    private void Start()
    {
        myTransform = GetComponent<RectTransform>();
        entity = GetComponentInParent<Entity>();
        slider = GetComponentInChildren<Slider>();
        myStats = GetComponentInParent<CharacterStats>();

        UpdateHealthUI();

        entity.onFlipped += FlipUI;
        myStats.onHealthChanged += UpdateHealthUI;
    }

    private void Update()
    {
        //UpdateHealthUI();
    }

    private void UpdateHealthUI()//更新血量条函数,此函数由Event触发
    {
        slider.maxValue = myStats.GetMaxHealthValue();
        
        slider.value = myStats.currentHealth;

    }

    private void FlipUI()//让UI不随着角色翻转
    {
        myTransform.Rotate(0, 180, 0);
    }


    private void OnDisable()
    {
        entity.onFlipped -= FlipUI;
        myStats.onHealthChanged -= UpdateHealthUI;
    }
}
CharacterStats.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterStats : MonoBehaviour
{
    [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;  // 降低敌人命中率

    private float ignitedTimer;
    private float chilledTimer;
    private float shockedTimer;


    private float igniteDamageCooldown = .3f;
    private float ignitedDamageTimer;
    private int igniteDamage;

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

    [SerializeField] public int currentHealth;


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

    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));
        }

        _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)//判断异常状态
    {
        if (isIgnited || isChilded || isShocked)
        {
            return;
        }

        if (_ignite)
        {
            isIgnited = _ignite;
            ignitedTimer = 2;
        }
        if (_chill)
        {
            isChilded = _chill;
            chilledTimer = 2;
        }
        if (_shock)
        {
            isShocked = _shock;
            shockedTimer = 2;
        }
    }
    public void SetupIgniteDamage(int _damage) => igniteDamage = _damage;//给点燃伤害赋值

    protected 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;

    }//统计生命值函数
}

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

public class Entity : MonoBehaviour
{
    [Header("Knockback info")]
    [SerializeField] protected Vector2 knockbackDirection;//被击打后的速度信息
    [SerializeField] protected float knockbackDuration;//被击打的时间
    protected bool isKnocked;//此值通过卡住SetVelocity函数的方式用来阻止当一个角色被攻击时,会乱动的情况

    [Header("Collision Info")]
    public Transform attackCheck;//transform类,代表的时物体的位置,用来控制攻击检测的位置
    public float attackCheckRadius;//检测半径
    [SerializeField] protected Transform groundCheck;//transform类,代表的时物体的位置,后面会来定位子组件的位置    
    [SerializeField] protected float groundCheckDistance;
    [SerializeField] protected Transform wallCheck;//transform类,代表的时物体的位置,后面会来定位子组件的位置    
    [SerializeField] protected float wallCheckDistance;
    [SerializeField] protected LayerMask whatIsGround;//LayerMask类,与Raycast配合,https://docs.unity3d.com/cn/current/ScriptReference/Physics.Raycast.html

    #region 定义Unity组件
    public SpriteRenderer sr { get; private set; }
    public Animator anim { get; private set; }//这样才能配合着拿到自己身上的animator的控制权
    public Rigidbody2D rb { get; private set; }//配合拿到身上的Rigidbody2D组件控制权
    public EntityFX fx { get; private set; }//拿到EntityFX
    public CharacterStats stats { get; private set; }
    public CapsuleCollider2D cd { get; private set; }
    #endregion
    public int facingDir { get; private set; } = 1;
    protected bool facingRight = true;//判断是否朝右


    public System.Action onFlipped;//一个自身不用写函数,只是接受其他函数并调用他们的函数
    //https://blog.csdn.net/weixin_44299531/article/details/131343583

    protected virtual void Awake()
    {
        
    }
    protected virtual void Start()
    {
        anim = GetComponentInChildren<Animator>();//拿到自己子组件身上的animator的控制权
        sr = GetComponentInChildren<SpriteRenderer>();
        fx = GetComponent<EntityFX>();拿到的组件上的EntityFX控制权
        rb = GetComponent<Rigidbody2D>();
        stats = GetComponent<CharacterStats>();
        cd = GetComponent<CapsuleCollider2D>();
    }
    protected virtual void Update()
    {

    }

    protected virtual void Exit()
    {

    }
    public virtual void DamageEffect()
    {

        fx.StartCoroutine("FlashFX");//IEnumertor本质就是将一个函数分块执行,只有满足某些条件才能执行下一段代码,此函数有StartCoroutine调用
                                     //https://www.zhihu.com/tardis/bd/art/504607545?source_id=1001
        StartCoroutine("HitKnockback");//调用被击打后产生后退效果的函数
        Debug.Log(gameObject.name+"was damaged");
    }
    
    protected virtual IEnumerator HitKnockback()
    {
        isKnocked = true;//此值通过卡住SetVelocity函数的方式用来阻止当一个角色被攻击时,会乱动的情况
        rb.velocity = new Vector2(knockbackDirection.x * -facingDir, knockbackDirection.y);
        yield return new WaitForSeconds(knockbackDuration);
        isKnocked = false;
    }
    //被击打后产生后退效果的函数
    #region 速度函数Velocity
    public virtual void SetZeroVelocity()
    {
        if(isKnocked)
        {
            return;
        }
        rb.velocity = new Vector2(0, 0);
    }//设置速度为0函数

    public virtual void SetVelocity(float _xVelocity, float _yVelocity)
    {
        if(isKnocked)
            return;此值通过卡住SetVelocity函数的方式用来阻止当一个角色被攻击时,会乱动的情况

        rb.velocity = new Vector2(_xVelocity, _yVelocity);//将rb的velocity属性设置为对应的想要的二维向量。因为2D游戏的速度就是二维向量
        FlipController(_xVelocity);//在其他设置速度的时候调用翻转控制器
    }//控制速度的函数,此函数在其他State中可能会使用,但仅能通过player.SeVelocity调用
    #endregion
    #region 翻转函数Flip
    public virtual void Flip()
    {
        facingDir = facingDir * -1;
        facingRight = !facingRight;
        transform.Rotate(0, 180, 0);//旋转函数,transform不需要额外定义,因为他是自带的

        if(onFlipped != null)
          onFlipped();

    }//翻转函数

    public virtual void FlipController(float _x)//目前设置x,目的时能在空中时也能转身
    {
        if (_x > 0 && !facingRight)//当速度大于0且没有朝右时,翻转
        {
            Flip();
        }
        else if (_x < 0 && facingRight)
        {
            Flip();
        }
    }
    #endregion
    #region 碰撞函数Collision
    public virtual bool IsGroundDetected()
    {
        return Physics2D.Raycast(groundCheck.position, Vector2.down, groundCheckDistance, whatIsGround);
    }//通过RayCast检测是否挨着地面,https://docs.unity3d.com/cn/current/ScriptReference/Physics2D.Raycast.html
    //xxxxxxxx()   => xxxxxxxx  == xxxxxxxxxx() return xxxxxxxxx;
    public virtual bool IsWallDetected()
    {
        return Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, wallCheckDistance, whatIsGround);
    }//通过RayCast检测是否挨着地面,https://docs.unity3d.com/cn/current/ScriptReference/Physics2D.Raycast.html
    //xxxxxxxx()   => xxxxxxxx  == xxxxxxxxxx() return xxxxxxxxx;
    protected virtual void OnDrawGizmos()
    {
        Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));//绘制一条从 from(前面的) 开始到 to(后面的) 的线。
        Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x + wallCheckDistance, wallCheck.position.y));//绘制一条从 from(前面的) 开始到 to(后面的) 的线。
        Gizmos.DrawWireSphere(attackCheck.position, attackCheckRadius);//https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Gizmos.DrawWireSphere.html
        //绘制具有中心和半径的线框球体。
    }//画图函数
    #endregion
    public void MakeTransprent(bool isClear)
    {
        if (isClear)
            sr.color = Color.clear;
        else
            sr.color = Color.white;
    }

    public virtual void Die()
    {

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1520121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AJAX学习(四)

版权声明 本文章来源于B站上的某马课程&#xff0c;由本人整理&#xff0c;仅供学习交流使用。如涉及侵权问题&#xff0c;请立即与本人联系&#xff0c;本人将积极配合删除相关内容。感谢理解和支持&#xff0c;本人致力于维护原创作品的权益&#xff0c;共同营造一个尊重知识…

NodeJs利用腾讯云实现手机发送验证码

本文介绍如何在nodejs实现短信发送&#xff0c;以腾讯云的短信验证为例。 腾讯云中准备工作 首先需要腾讯云的个人或者企业认证的账号&#xff0c;个人会赠送一百条&#xff0c;企业赠送一千条&#xff0c;可以用于测试&#xff0c;地址&#xff1a;腾讯云短信服务。然后需要…

k8s helm 删除 tiller

kuberneter 上面装了 helm 想卸载还并不是那么简单, 参考 stackoverflow 回复 kubectl get -n kube-system secrets,sa,clusterrolebinding -o name|grep tiller|xargs kubectl -n kube-system delete kubectl get all -n kube-system -l apphelm -o name|xargs kubectl dele…

前端实例:页面布局1(后端数据实现)

效果图 注&#xff1a;这里用到后端语言php&#xff08;页面是.php文件&#xff09;,提取纯html也可以用 inemployee_index.php <?php include(includes/session.inc); $Title _(内部员工首页); $ViewTopic 内部员工首页; $BookMark 内部员工首页; include(includes/…

FFmepg--音频编码流程--pcm编码为aac

文章目录 基本概念流程apicode(核心部分) 基本概念 从本地⽂件读取PCM数据进⾏AAC格式编码&#xff0c;然后将编码后的AAC数据存储到本地⽂件。 PCM样本格式&#xff1a;未经压缩的⾳频采样数据裸流 参数&#xff1a; Sample Rate : 采样频率Sample Size : 量化位数Number o…

14 stack和queue的使用

stack的介绍 stack文档 1.stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入和提取操作 2.stack是作为容器适配器被实现的&#xff0c;容器适配器是对特定类封装作为其底层的容器&#xff0c;并提供…

C/C++ Socket 获取或设置 TCP MSS 大小

通过 Socket 系统接口&#xff0c;链接到一个TCP服务器&#xff0c;那么在链接成功之后会被配置一个从本地端到目的端最佳的TCP_MSS大小。 我们通过这个特点&#xff0c;即可轻松的实现&#xff0c;链路MTU大小发现功能&#xff0c;在不依赖ROOT管理员权限的情况下&#xff0c;…

Unity AI Navigation插件快速使用方法

AI Navigation插件使您能够创建能够在游戏世界中智能移动的角色。这些角色利用的是根据场景几何结构自动生成的导航网格。障碍物可以让您在运行时改变角色的导航路径。 演示使用的Unity版本为Tuanjie 1.0.0,团结引擎是Unity中国的引擎研发团队基于Unity 2022 LTS版本为中国开发…

第五十九回 公孙胜芒砀山降魔 晁天王曾头市中箭-飞桨自然语言处理套件PaddleNLP初探

公孙胜献出八卦阵&#xff0c;宋江用八员大将守阵。项充李衮进入阵里&#xff0c;被抓住了。宋江说久闻大名&#xff0c;来梁山吧。两人说誓当效力到死&#xff0c;希望能先放我们两个回去把樊瑞带来一起。见到樊瑞后把宋江讲义气一说&#xff0c;樊瑞说不可逆天&#xff0c;于…

人工智能程序使用的编程语言

用C语言可以写人工智能程序吗&#xff1f; 可以用C语言编写具有人工智能功能的程序&#xff0c;但是较为复杂。C语言是一种通用的编程语言&#xff0c;它在执行速度和资源控制方面表现出色&#xff0c;这使得它适合于需要高性能处理的人工智能应用&#xff0c;如游戏AI&#xf…

ES解析word内容为空的问题和直接使用Tika解析文档的方案

导言 在上一篇文章最后&#xff0c;我们虽然跑通了ES文件搜索的全部流程&#xff0c;但是仍然出现了1个大的问题&#xff1a;ES7.3实测无法索引docx和doc文档&#xff0c;content有值但是无法解析到附件成为可读的可搜索的内容&#xff0c;附件内容为空&#xff08;附件中根本…

【pycharm】如何将pacharm设置成中文

【pycharm】汉化教程——如何将pacharm设置成中文 1、打开pycharm 2、点击file 3、点击setting——Plugins——搜索Chinese——点击如下图图标进行下载 汉化后界面情况&#xff1a;

JVM高频面试点(一):Java类加载过程

1.概述 在 Java 中&#xff0c;类加载过程是指将 Java 类的字节码加载到内存中&#xff0c;并转换为 Java 虚拟机能够识别和执行的数据结构的过程。类加载是 Java 虚拟机执行 Java 程序的必要步骤之一&#xff0c;它负责加载程序中用到的类和接口。下图所示是 ClassLoader 加载…

【滤波专题-第9篇】类EMD分解算法联合小波阈值降噪及MATLAB代码实现(以ICEEMDAN-样本熵-小波阈值降噪方法为例)

今天这篇介绍的算法&#xff0c;由于其高度的灵活性、使用方法的丰富性以及不错的效果&#xff0c;堪称水论文神器。对于需要使用滤波算法的同学们&#xff0c;这篇文章不可错过~ 本篇会提及很多前置概念&#xff0c;比如ICEEMDAN等模态分解算法、熵特征提取、小波阈值滤波等等…

idea项目mapper.xml中的SQL语句黄色下划线去除

问题描述 当我们使用idea开发java项目时&#xff0c;经常会与数据库打交道&#xff0c;一般在使用mybatis的时候需要写一大堆的mapper.xml以及SQL语句&#xff0c;每当写完SQL语句的时候总是有黄色下划线&#xff0c;看着很不舒服。 解决方案&#xff1a; 修改idea的配置 Edi…

SQLiteC/C++接口详细介绍之sqlite3类(八)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;七&#xff09; 下一篇&#xff1a; SQLiteC/C接口详细介绍之sqlite3类&#xff08;八&#xff09;&#xff08;暂未发表&#xff09; 24.sqlite3_cr…

SpringMVC重点记录

目录 1.学习重点2.回顾MVC3.回顾servlet4.初始SpringMVC4.1.为什么要学SpringMVC?4.2.SpringMVC的中重点DispatcherServlet4.3.SpringMVC项目的搭建4.4.MVC框架要做哪些事情?4.5.可能会遇到的问题 5.SpringMVC的执行原理6.使用注解开发SpringMVC7.Controller控制总结8.RestF…

腾讯地图的(地图选点|输入模糊匹配)

1.支持用户输入框输入进行模糊匹配获取详细地址以及经纬度2.支持用户模糊匹配后点击选点获取详细地址以及经纬度 1.支持用户输入框输入进行模糊匹配获取详细地址以及经纬度2.支持用户模糊匹配后点击选点获取详细地址以及经纬度 <template><div class"tencentMap-…

Web 服务器-Tomcat

文章目录 Web服务器一、Tomcat简介二、基本使用三、在IDEA中创建Maven Web项目四、在IDEA中使用Tomcat Web服务器 一、Tomcat简介 二、基本使用 三、在IDEA中创建Maven Web项目 四、在IDEA中使用Tomcat

首个ChatGPT机器人- Figure 01;李开复旗下零一万物推出Yi系列AI大模型API

&#x1f989; AI新闻 &#x1f680; 首个ChatGPT机器人- Figure 01 摘要&#xff1a;Figure 01是一个由初创公司Figure联合OpenAI开发的人形机器人。它展示了与人类和环境互动的能力&#xff0c;可以说话、看东西&#xff0c;并且可以执行各种任务&#xff0c;如递食物、捡垃…