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

Unity类银河战士恶魔城学习总结(P118 Thunder Strike On Ability 制作一把带有雷电效果的项链)

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

教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/

本节实现了一个能给武器和水晶爆炸技能附魔的项链,取名为风暴之心

都是在造成伤害函数的部分加上了触发特殊效果的代码

Sword_Skill_Controller.cs

修改部分

    private void SwordSkillDamage(Enemy enemy)
    {
        //enemy.DamageEffect();
        player.stats.DoDamage(enemy.GetComponent<CharacterStats>());
        enemy.StartCoroutine("FreezeTimerFor", freezeTimeDUration);

        ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet);//获取护身符

        if (equipedAmulet != null)
            equipedAmulet.Effect(enemy.transform);//如果有护身符,就对敌人造成额外伤害
    }
using System.Collections.Generic;
using Unity.Burst.CompilerServices;
using UnityEngine;

public class Sword_Skill_Controller : MonoBehaviour
{

    private Animator anim;
    private Rigidbody2D rb;
    private CircleCollider2D cd;
    private Player player;

    private bool canRotate = true;
    private bool isReturning;

    private float freezeTimeDUration;
    private float returnSpeed = 12;


    [Header("Pierce info")]
    [SerializeField] private int pierceAmount;



    [Header("Bounce info")]
    private float bounceSpeed;// 想通过函数传递删除SerializeField
    private bool isBouncing; // 是否可以反弹
    private int bounceAmount;// 反弹次数
    private List<Transform> enemyTarget;//敌人目标
    private int targetIndex = 0;//目标索引

    [Header("Spin info")]
    private float maxTravelDistance;//最大旋转距离
    private float spinDuration;//旋转持续时间
    private float spinTimer;//旋转计时器
    private bool wasStopped;//是否停止
    private bool isSpinning;//是否旋转

    private float hitTimer;
    private float hitCooldown;

    private float spinDirection;//旋转方向

    //Awake在脚本实例化时立即调用。它在所有对象的Awake方法都被调用完毕后,才会开始调用Start方法。而Start在第一次更新循环之前调用。
    private void Awake()
    {
        anim = GetComponentInChildren<Animator>();
        rb = GetComponent<Rigidbody2D>();
        cd = GetComponent<CircleCollider2D>();
    }

    private void DestroyMe()
    {
        Destroy(gameObject);
    }

    //以下四个函数都是把局部变量传递给全局变量
    public void SetupSword(Vector2 _dir, float _gravityScale, Player _player, float _freezeTimeDUration, float _returnSpeed) //设置飞行物体
    {
        player = _player;
        freezeTimeDUration = _freezeTimeDUration;
        returnSpeed = _returnSpeed;


        rb.velocity = _dir;
        rb.gravityScale = _gravityScale;


        if (pierceAmount <= 0)
            anim.SetBool("Rotation", true);

        spinDirection = Mathf.Clamp(rb.velocity.x, -1, 1);//限制旋转方向在-1到1之间

        Invoke("DestroyMe", 7);//Invoke 是 Unity 中 MonoBehaviour 类的一部分,用于在指定的延迟时间后调用某个方法
    }


    public void SetupBounce(bool _isBouncing, int _amountOfBounces, float _bounceSpeed)//设置反弹
    {
        isBouncing = _isBouncing;
        bounceAmount = _amountOfBounces;
        bounceSpeed = _bounceSpeed;


        enemyTarget = new List<Transform>();//当把上面的public改成private时,系统就不会创建一个空的列表
    }

    public void SetupPierce(int _pierceAmount)//int _pierceAmoun:方法参数
    {
        pierceAmount = _pierceAmount;
    }

    public void SetupSpin(bool _isSpinning, float _maxTravelDistance, float _spinDuration, float _hitCooldown)//设置旋转
    {
        isSpinning = _isSpinning;
        maxTravelDistance = _maxTravelDistance;
        spinDuration = _spinDuration;//,_spinDuration 是一个形式参数
        hitCooldown = _hitCooldown;
    }


    public void ReturnSword()
    {
        rb.constraints = RigidbodyConstraints2D.FreezeAll;// 冻结刚体的所有约束
        //rb.isKinematic = false;
        transform.parent = null;
        isReturning = true;
    }




    private void Update()
    {
        if (canRotate)//如果可以旋转
            transform.right = rb.velocity;//设置旋转方向

        if (isReturning)
        {
            transform.position = Vector2.MoveTowards(transform.position, player.transform.position, returnSpeed * Time.deltaTime);//返回到玩家手上

            if (Vector2.Distance(transform.position, player.transform.position) < 1)
                player.CatchTheSword();
        }

        BounceLogic();//反弹逻辑
        SpinLogic();//旋转逻辑
    }

    private void SpinLogic()
    {
        if (isSpinning)
        {
            if (Vector2.Distance(transform.position, player.transform.position) > maxTravelDistance && !wasStopped)//如果距离大于最大旋转距离并且没有停止
            {
                StopWhenSpinning();
            }

            if (wasStopped)//如果停止
            {
                spinTimer -= Time.deltaTime;//计时器减去时间

                //transform.position = Vector2.MoveTowards(transform.position,
                //                                        new Vector2(transform.position.x + spinDirection, transform.position.y), 1.5f * Time.deltaTime);//移动到旋转方向

                if (spinTimer < 0)
                {
                    isReturning = true;
                    isSpinning = false;
                }

                hitTimer -= Time.deltaTime;

                if (hitTimer < 0)
                {
                    hitTimer = hitCooldown;

                    Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 1);

                    foreach (var hit in colliders)
                    {
                        if (hit.GetComponent<Enemy>() != null)
                        {
                            SwordSkillDamage(hit.GetComponent<Enemy>());
                        }
                    }
                }
            }
        }
    }




    private void StopWhenSpinning()//旋转时候停止
    {
        wasStopped = true;
        rb.constraints = RigidbodyConstraints2D.FreezeAll;
        spinTimer = spinDuration;//旋转计时器
    }

    private void BounceLogic()
    {
        if (isBouncing && enemyTarget.Count > 0)//如果可以反弹并且敌人目标数量大于0
        {
            transform.position = Vector2.MoveTowards(transform.position, enemyTarget[targetIndex].position, bounceSpeed * Time.deltaTime);//移动到敌人

            if (Vector2.Distance(transform.position, enemyTarget[targetIndex].position) < 0.1f)//如果距离小于0.1
            {

                SwordSkillDamage(enemyTarget[targetIndex].GetComponent<Enemy>());//敌人受到伤害
                //enemyTarget[targetIndex].GetComponent<Enemy>().Damage();  
                //enemyTarget[targetIndex].GetComponent<Enemy>().StartCoroutine("FreezeTimerFor", freezeTimeDUration);

                targetIndex++; //敌人目标的索引,攻击了这个敌人就攻击下一个敌人
                bounceAmount--;

                if (bounceAmount <= 0)
                {
                    isBouncing = false;
                    isReturning = true;
                }

                if (targetIndex >= enemyTarget.Count) //如果目标索引大于等于敌人目标数量
                {
                    targetIndex = 0;
                }
            }
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)//Sword碰到敌人时候的处理
    {

        if (isReturning)
            return;//后面的就不会再触发,sword可以返回时候攻击到敌人,并且返回到手上


        if (collision.GetComponent<Enemy>() != null)//如果碰到敌人
        {
            Enemy enemy = collision.GetComponent<Enemy>();//获取敌人
            SwordSkillDamage(enemy);
        }


        SetupTargetsForBounce(collision);

        StuckInto(collision);

    }

    private void SwordSkillDamage(Enemy enemy)
    {
        //enemy.DamageEffect();
        player.stats.DoDamage(enemy.GetComponent<CharacterStats>());
        enemy.StartCoroutine("FreezeTimerFor", freezeTimeDUration);

        ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet);//获取护身符

        if (equipedAmulet != null)
            equipedAmulet.Effect(enemy.transform);//如果有护身符,就对敌人造成额外伤害
    }


    private void SetupTargetsForBounce(Collider2D collision)
    {
        if (collision.GetComponent<Enemy>() != null)//碰到敌人
        {
            if (isBouncing && enemyTarget.Count <= 0)//如果可以反弹并且敌人目标数量小于等于0
            {
                Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 10);//获取周围敌人的碰撞体

                foreach (var hit in colliders)//遍历周围敌人的碰撞体
                {
                    if (hit.GetComponent<Enemy>() != null)//如果碰到的是敌人
                    {
                        enemyTarget.Add(hit.transform);//添加到敌人目标
                    }
                }
            }
        }
    }


    private void StuckInto(Collider2D collision)//碰撞时候的处理
    {
        if (pierceAmount > 0 && collision.GetComponent<Enemy>() != null)//如果可以穿透并且碰到敌人
        {
            pierceAmount--;
            return;
        }

        if (isSpinning)
        {
            StopWhenSpinning();//注释掉经过敌人不会停止
            return;
        }

        canRotate = false; // 停止旋转
        cd.enabled = false;// 禁用碰撞体

        rb.isKinematic = true;// 设置刚体为运动学模式
        rb.constraints = RigidbodyConstraints2D.FreezeAll;// 冻结刚体的所有约束

        if (isBouncing && enemyTarget.Count > 0)  // 如果可以反弹并且敌人目标数量大于0
            return;


        anim.SetBool("Rotation", false);
        transform.parent = collision.transform;// 将当前物体设为碰撞对象的子对象,即粘在敌人身上
    }
}

Crystal_Skill_Controller.cs

修改部分

    private void AnimationExplodeEvent()//可以放在动画触发器里面
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, cd.radius);//从克隆控制器粘贴上的

        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null)
                player.stats.DoMagicDamage(hit.GetComponent<CharacterStats>());//加上魔法伤害

            ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet) ;//获取护身符

            if (equipedAmulet != null)
                equipedAmulet.Effect(hit.transform);//如果有护身符,就对敌人造成额外伤害
        }
    }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Crystal_Skill_Controller : MonoBehaviour  //放在水晶得预制件里面
{
    private Animator anim => GetComponent<Animator>(); //引用是为了在更新中使用SetTrigger
    private CircleCollider2D cd => GetComponent<CircleCollider2D>();//为了完成爆炸伤害
    private Player player;// 2024年10月30日,给技能加上伤害

    private float crystalExistTimer;//消失计时器

    private bool canExplode ;//是否可以爆炸
    private bool canMove;
    private float moveSpeed;
    
    private bool canGrow;
    private float growSpeed = 5;

    private Transform closetTarget;
    [SerializeField] private LayerMask whatIsEnemy;

    public void SetupCrystal(float _crystalDuration,bool _canExplode,bool _canMove,float _moveSpeed,Transform _closetTarget,Player _player)
    {
        player = _player;
        crystalExistTimer = _crystalDuration;//放置水晶,然后开始计时
        canExplode = _canExplode;
        canMove = _canMove;
        moveSpeed = _moveSpeed;
        closetTarget=_closetTarget;
    }

    public void ChooseRandomEnemy()
    {
        float radius = SkillManager.instance.blackhole.GetBlackholeRadius();//从黑洞控制器中获取黑洞半径

        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, radius, whatIsEnemy);//选取周围所有的碰撞体

        if(colliders.Length > 0)
            closetTarget = colliders[Random.Range(0, colliders.Length)].transform;//随机选取一个敌人
    }



    private void Update()
    {
        crystalExistTimer -= Time.deltaTime;//控制器起码能控制时间吧

        if (crystalExistTimer < 0)
        {
            //Destroy(gameObject);   新增的功能,水晶消失后可以爆炸,所以检查是否可以爆炸
            FinishCrystal();
        }

        if (canMove)//移动到敌人的逻辑函数
        {
            if (closetTarget == null)
                return;//防止拾取物品时候出现bug

            transform.position = Vector2.MoveTowards(transform.position, closetTarget.position, moveSpeed * Time.deltaTime);//水晶移动到敌人位置(这里是最近敌人位置)

            if (Vector2.Distance(transform.position, closetTarget.position) < .5f)//如果水晶到达敌人位置
            {
                FinishCrystal();
                canMove = false;
            }
        }


        if (canGrow)//和上面函数优先级?
            transform.localScale = Vector2.Lerp(transform.localScale, new Vector2(3,3), growSpeed * Time.deltaTime);//水晶变大
    }

    private void AnimationExplodeEvent()//可以放在动画触发器里面
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, cd.radius);//从克隆控制器粘贴上的

        foreach (var hit in colliders)
        {
            if (hit.GetComponent<Enemy>() != null)
                player.stats.DoMagicDamage(hit.GetComponent<CharacterStats>());//加上魔法伤害

            ItemData_Equipment equipedAmulet = Inventory.instance.GetEquipment(EquipmentType.Amulet) ;//获取护身符

            if (equipedAmulet != null)
                equipedAmulet.Effect(hit.transform);//如果有护身符,就对敌人造成额外伤害
        }
    }



    public void FinishCrystal()
    {
        if (canExplode)
        {
            canGrow = true;
            anim.SetTrigger("Explode");
        }
        else
            SelfDestroy();
    }

    public void SelfDestroy() => Destroy(gameObject);
}


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

相关文章:

  • 【ChatGPT】 如何让ChatGPT分析数据并得出结论
  • Springboot 启动端口占用如何解决
  • uniapp+vue2 设置全局变量和全局方法 (兼容h5/微信小程序)
  • MySQL_第13章_视图
  • 第8章利用CSS制作导航菜单
  • 【MATLAB代码】二维平面上的TDOA,使用加权最小二乘法,不限制锚点数量,代码可复制粘贴
  • Ubuntu20.04 安装build-essential问题
  • 丹摩征文活动 | 轻松上手图像生成:FLUX.1遇上ComfyUI,让复杂变简单!
  • 小程序与 H5 的交互
  • mac 中python 安装mysqlclient 出现 ld: library ‘ssl‘ not found错误
  • Vue全栈开发旅游网项目(10)-设计用户模型
  • C++ | Leetcode C++题解之第557题反转字符串中的单词III
  • Rust使用DX11进行截图并保存
  • 逻辑的空无
  • SQL的三值逻辑
  • 基于vue框架的的汽车租赁系统34311(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • HTML查缺补漏
  • playwright学习记录2--定位方式
  • 【Unity/GameFramework】Start Force ——配置和表加载
  • 二分答案-整型二分—愤怒的牛-P1676 [USACO05FEB] Aggressive cows G
  • 微服务架构面试内容整理-监控与追踪-Zipkin
  • AlphaFold3中文安装教程
  • Unity类银河战士恶魔城学习总结(P117 Ice And Fire Item Effec 制作一把冰火属性的剑)
  • 练习题 - Django 4.x WWW 网址使用示例和配置方法
  • Git推送报错Authentication failed
  • 深入探讨钉钉与金蝶云星空的数据集成技术