您现在的位置是:首页 >技术杂谈 >Unity类·银河恶魔城之P78-P82网站首页技术杂谈

Unity类·银河恶魔城之P78-P82

落叶归—— 2025-03-28 00:01:07
简介Unity类·银河恶魔城之P78-P82

1,黑洞控制器预制件

2,热键控制器预制件

3,Blackhole_Skill_Controller.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 黑洞控制器,负责管理黑洞技能的相关逻辑,如尺寸增长、敌人捕获、克隆体攻击等
public class Blackhole_Skill_Controller : MonoBehaviour
{
    // 热键预制件,用于在敌人上方显示热键提示
    [SerializeField] private GameObject hotkeyPrefab;
    // 热键列表,存储可供选择的热键
    [SerializeField] private List<KeyCode> keyCodeList;

    // 黑洞的最大尺寸
    private float maxSize;
    // 黑洞的增长速度
    private float growSpeed;
    // 黑洞的缩小速度
    private float shrinkSpeed;
    // 黑洞持续时间计时器
    private float blackholeTimer;

    // 增长判断标志,为 true 时黑洞开始增长
    private bool canGrow = true;
    // 缩小判断标志,为 true 时黑洞开始缩小
    private bool canShrink;
    // 是否可以创建热键的标志
    private bool canCreateHotkeys = true;
    // 克隆体攻击释放标志,为 true 时开始克隆体攻击流程
    private bool cloneAttackReleased;
    // 玩家是否可以消失的标志
    private bool playeCanDisapear = true;

    // 克隆体攻击的数量
    private int amountOfAttacks;
    // 克隆体攻击的冷却时间
    private float cloneAttackCooldown;
    // 克隆体攻击的冷却计时器
    private float cloneAttackTimer;

    // 存储被黑洞捕获的敌人的集合
    private List<Transform> targets = new List<Transform>();
    // 存储创建的热键对象的列表
    private List<GameObject> createdHotkey = new List<GameObject>();

    // 玩家退出状态,外部可获取该状态
    public bool playerCanExitState { get; private set; }

    /// <summary>
    /// 设置黑洞的相关参数
    /// </summary>
    /// <param name="_maxSize">黑洞的最大尺寸</param>
    /// <param name="_growSpeed">黑洞的增长速度</param>
    /// <param name="_shrinkSpeed">黑洞的缩小速度</param>
    /// <param name="_amountOfAttacks">克隆体攻击的数量</param>
    /// <param name="_cloneAttackCooldown">克隆体攻击的冷却时间</param>
    /// <param name="_blackholeDuration">黑洞的持续时间</param>
    public void SetupBlackhole(float _maxSize, float _growSpeed, float _shrinkSpeed, int _amountOfAttacks, float _cloneAttackCooldown, float _blackholeDuration)
    {
        maxSize = _maxSize;
        growSpeed = _growSpeed;
        shrinkSpeed = _shrinkSpeed;
        amountOfAttacks = _amountOfAttacks;
        cloneAttackCooldown = _cloneAttackCooldown;
        blackholeTimer = _blackholeDuration;
    }

    private void Update()
    {
        // 减少克隆体攻击冷却计时器
        cloneAttackTimer -= Time.deltaTime;
        // 减少黑洞持续时间
        blackholeTimer -= Time.deltaTime;

        // 当黑洞持续时间结束
        if (blackholeTimer < 0)
        {
            // 设置黑洞时间为无穷大,确保只检查一次
            blackholeTimer = Mathf.Infinity;

            // 若有捕获的敌人,释放克隆体攻击
            if (targets.Count > 0)
            {
                ReleaseCloneAttack();
            }
            else
            {
                // 若无捕获的敌人,结束黑洞技能
                FinishBlackHoleAbility();
            }
        }
        //如果按下冲刺键则结束黑洞技能
        if(Input.GetKeyDown(KeyCode.LeftShift))
        {
            // 若无捕获的敌人,结束黑洞技能
            FinishBlackHoleAbility();
        }
        // 检测是否按下 R 键,且有捕获的敌人,按下则释放克隆体攻击
        if (Input.GetKeyDown(KeyCode.R) && targets.Count > 0)
        {
            ReleaseCloneAttack();
        }

        // 处理克隆体攻击逻辑
        CloneAttackLogic();

        // 如果允许黑洞增长且不允许缩小
        if (canGrow && !canShrink)
        {
            // 平滑地改变黑洞的尺寸,使其趋近于最大尺寸
            transform.localScale = Vector2.Lerp(transform.localScale, new Vector2(maxSize, maxSize), growSpeed * Time.deltaTime);
        }

        // 如果允许黑洞缩小
        if (canShrink)
        {
            // 平滑地缩小黑洞尺寸
            transform.localScale = Vector2.Lerp(transform.localScale, new Vector2(-1, -1), shrinkSpeed * Time.deltaTime);

            // 当黑洞尺寸小于 0 时,销毁黑洞对象
            if (transform.localScale.x < 0)
            {
                Destroy(gameObject);
            }
        }
    }

    /// <summary>
    /// 释放克隆体攻击
    /// </summary>
    private void ReleaseCloneAttack()
    {
        // 销毁所有热键
        DestroyHotkeys();
        // 标记克隆体攻击已释放
        cloneAttackReleased = true;
        // 禁止创建热键
        canCreateHotkeys = false;

        // 如果玩家可以消失
        if (playeCanDisapear)
        {
            // 标记玩家不能再消失
            playeCanDisapear = false;
            // 使玩家透明
            PlayerManager.instance.player.MakeTransprent(true);
        }
    }

    /// <summary>
    /// 处理克隆体攻击逻辑
    /// </summary>
    private void CloneAttackLogic()
    {
        // 当冷却时间结束,克隆体攻击已释放,且还有攻击次数
        if (cloneAttackTimer < 0 && cloneAttackReleased && amountOfAttacks > 0)
        {
            // 重置冷却计时器
            cloneAttackTimer = cloneAttackCooldown;

            // 随机选择一个被捕获的敌人
            int randomIndex = Random.Range(0, targets.Count);

            // 随机生成 x 轴偏移量
            float xOffset;
            if (Random.Range(0, 100) > 50)
                xOffset = 2;
            else
                xOffset = -2;

            // 调用技能管理器的克隆技能,在随机敌人位置附近创建克隆体
            SkillManager.instance.clone.CreateClone(targets[randomIndex], new Vector3(xOffset, 0));
            // 减少克隆体攻击数量
            amountOfAttacks--;

            // 当克隆体攻击数量用完
            if (amountOfAttacks <= 0)
            {
                // 延迟 1 秒后结束黑洞技能
                Invoke("FinishBlackHoleAbility", 1f);
            }
        }
    }

    /// <summary>
    /// 结束黑洞技能
    /// </summary>
    private void FinishBlackHoleAbility()
    {
        // 销毁所有热键
        DestroyHotkeys();
        // 允许玩家退出状态
        playerCanExitState = true;
        // 标记克隆体攻击未释放
        cloneAttackReleased = false;
        // 允许黑洞缩小
        canShrink = true;
    }

    /// <summary>
    /// 销毁所有创建的热键对象
    /// </summary>
    private void DestroyHotkeys()
    {
        // 如果没有创建热键,直接返回
        if (createdHotkey.Count <= 0)
        {
            return;
        }

        // 遍历并销毁所有热键对象
        for (int i = 0; i < createdHotkey.Count; i++)
        {
            Destroy(createdHotkey[i]);
        }
    }

    /// <summary>
    /// 当有 2D 碰撞体进入黑洞的触发范围时调用
    /// </summary>
    /// <param name="collision">碰撞的 2D 碰撞体</param>
    private void OnTriggerEnter2D(Collider2D collision)
    {
        // 检查碰撞体是否为敌人
        if (collision.GetComponent<Enemy>() != null)
        {
            // 冻结敌人的时间
            collision.GetComponent<Enemy>().FreezeTime(true);

            // 在敌人上方创建热键提示
            CreateHotkey(collision);
        }
    }

    /// <summary>
    /// 当有 2D 碰撞体离开黑洞的触发范围时调用
    /// </summary>
    /// <param name="collision">碰撞的 2D 碰撞体</param>
    private void OnTriggerExit2D(Collider2D collision)
    {
        // 检查碰撞体是否为敌人
        if (collision.GetComponent<Enemy>() != null)
        {
            // 解除敌人的时间冻结
            collision.GetComponent<Enemy>().FreezeTime(false);
        }
    }

    /// <summary>
    /// 在敌人上方创建热键提示
    /// </summary>
    /// <param name="collision">敌人的碰撞体</param>
    private void CreateHotkey(Collider2D collision)
    {
        // 如果热键列表为空,输出错误信息并返回
        if (keyCodeList.Count <= 0)
        {
            Debug.Log("热键是空的");
            return;
        }

        // 如果克隆体攻击已释放,不创建热键
        if (!canCreateHotkeys)
        {
            return;
        }

        // 实例化热键预制件,并设置其位置在敌人上方
        GameObject newHotkey = Instantiate(hotkeyPrefab, collision.transform.position + new Vector3(0, 2), Quaternion.identity);

        // 将新创建的热键添加到列表中
        createdHotkey.Add(newHotkey);
        // 随机选择一个热键
        KeyCode choosenKey = keyCodeList[Random.Range(0, keyCodeList.Count)];
        // 从热键列表中移除已选择的热键
        keyCodeList.Remove(choosenKey);

        // 获取热键对象的控制器脚本
        Blackhole_Hotkey_Controller newHotkeyScript = newHotkey.GetComponent<Blackhole_Hotkey_Controller>();

        // 设置热键的相关信息,包括选择的热键、对应的敌人和当前控制器
        newHotkeyScript.SetupHotkey(choosenKey, collision.transform, this);
        // 这里注释掉了将敌人添加到目标列表的代码,可能需要根据实际情况调整
        // targets.Add(collision.transform);
    }

    /// <summary>
    /// 将敌人添加到被捕获的敌人列表中
    /// </summary>
    /// <param name="_myEnemy">敌人的 Transform 组件</param>
    public void AddEnemyToList(Transform _myEnemy) => targets.Add(_myEnemy);
}

4,Blackhole_Hotkey_Controller.cs

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

// 黑洞热键控制器类,负责管理显示在敌人上方的热键提示的逻辑
public class Blackhole_Hotkey_Controller : MonoBehaviour
{
    // 热键提示文本的精灵渲染器,用于控制热键提示的显示与隐藏
    private SpriteRenderer sr;
    // 当前热键对应的按键代码,用于检测玩家是否按下该热键
    private KeyCode myHotkey;
    // 显示热键文本的 TextMeshProUGUI 组件,用于显示具体的热键字符
    private TextMeshProUGUI myText;
    // 关联的敌人的 Transform 组件,用于确定热键提示的位置
    private Transform myEnemy;
    // 黑洞技能控制器,用于将敌人添加到被捕获的敌人列表中
    private Blackhole_Skill_Controller blackHole;

    /// <summary>
    /// 设置热键提示的相关信息
    /// </summary>
    /// <param name="_myNewHotkey">新的热键按键代码</param>
    /// <param name="_myEnemy">关联的敌人的 Transform 组件</param>
    /// <param name="_myBlackHole">黑洞技能控制器</param>
    public void SetupHotkey(KeyCode _myNewHotkey, Transform _myEnemy, Blackhole_Skill_Controller _myBlackHole)
    {
        // 获取当前对象的 SpriteRenderer 组件,用于后续控制热键提示的显示
        sr = GetComponent<SpriteRenderer>();

        // 获取当前对象子物体中的 TextMeshProUGUI 组件,用于显示热键文本
        myText = GetComponentInChildren<TextMeshProUGUI>();

        // 记录关联的敌人的 Transform 组件
        myEnemy = _myEnemy;
        // 记录黑洞技能控制器
        blackHole = _myBlackHole;

        // 记录当前热键对应的按键代码
        myHotkey = _myNewHotkey;
        // 将热键对应的按键代码转换为字符串并显示在文本组件上
        myText.text = _myNewHotkey.ToString();
    }

    private void Update()
    {
        // 检测玩家是否按下了当前热键
        if (Input.GetKeyDown(myHotkey))
        {
            // 将关联的敌人添加到黑洞技能控制器的被捕获敌人列表中
            blackHole.AddEnemyToList(myEnemy);

            // 将热键文本的颜色设置为透明,使其不可见
            myText.color = Color.clear;
            // 将热键提示的精灵颜色设置为透明,使其不可见
            sr.color = Color.clear;
        }
    }
}

5,Blackhole_Skill.CS

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 黑洞技能类,继承自 Skill 基类,负责黑洞技能的具体逻辑
public class Blackhole_Skill : Skill
{
    // 克隆体攻击的数量
    [SerializeField] private int amountOfAttacks;
    // 克隆体攻击的冷却时间
    [SerializeField] private float cloneCooldown;
    // 黑洞的持续时间
    [SerializeField] private float blackholeDuration;

    // 用于在 Inspector 面板中添加一个空白间隔,增强可读性
    [Space]

    // 黑洞预制件,用于实例化黑洞对象
    [SerializeField] private GameObject blackHolePrefab;
    // 黑洞的最大尺寸
    [SerializeField] private float maxSize;
    // 黑洞的增长速度
    [SerializeField] private float growSpeed;
    // 黑洞的缩小速度
    [SerializeField] private float shrinkSpeed;

    // 当前激活的黑洞控制器,用于管理黑洞的各种行为
    Blackhole_Skill_Controller currentBlachole;

    /// <summary>
    /// 检查是否可以使用黑洞技能
    /// </summary>
    /// <returns>如果可以使用技能,返回 true;否则返回 false</returns>
    public override bool CanUseSkill()
    {
        // 调用基类的 CanUseSkill 方法进行基本的技能可用性检查
        return base.CanUseSkill();
    }

    /// <summary>
    /// 使用黑洞技能
    /// </summary>
    public override void UseSkill()
    {
        // 调用基类的 UseSkill 方法执行通用的技能使用逻辑
        base.UseSkill();

        // 在玩家当前位置实例化黑洞预制件
        GameObject newBlackHole = Instantiate(blackHolePrefab, player.transform.position, Quaternion.identity);

        // 获取新创建黑洞对象的黑洞技能控制器组件
        currentBlachole = newBlackHole.GetComponent<Blackhole_Skill_Controller>();

        // 设置黑洞的相关参数,如最大尺寸、增长速度、缩小速度、克隆体攻击数量、克隆体攻击冷却时间和黑洞持续时间
        currentBlachole.SetupBlackhole(maxSize, growSpeed, shrinkSpeed, amountOfAttacks, cloneCooldown, blackholeDuration);
    }

    /// <summary>
    /// 在脚本实例被加载时调用,用于初始化操作
    /// </summary>
    protected override void Start()
    {
        // 调用基类的 Start 方法执行通用的初始化逻辑
        base.Start();
    }

    /// <summary>
    /// 每帧调用一次,用于更新逻辑
    /// </summary>
    protected override void Update()
    {
        // 调用基类的 Update 方法执行通用的更新逻辑
        base.Update();
    }

    /// <summary>
    /// 检查黑洞技能是否完成
    /// </summary>
    /// <returns>如果技能完成,返回 true;否则返回 false</returns>
    public bool SkillCompleted()
    {
        // 如果当前没有激活的黑洞控制器,返回 false
        if (!currentBlachole)
            return false;

        // 如果当前黑洞控制器允许玩家退出状态,说明技能完成
        if (currentBlachole.playerCanExitState)
        {
            // 将当前黑洞控制器置为 null,表示技能已结束
            currentBlachole = null;
            return true;
        }

        // 否则,技能未完成,返回 false
        return false;
    }
}

6,PlayerBlackholeState .cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 玩家黑洞状态类,继承自 PlayerState 类,用于处理玩家处于黑洞技能状态时的逻辑
public class PlayerBlackholeState : PlayerState
{
    // 玩家飞行的持续时间,单位为秒
    private float flyTime = .4f;
    // 标记黑洞技能是否已经使用
    private bool skillUsed;
    // 玩家刚体的初始重力缩放值,用于在状态结束后恢复重力
    private float defaultGravity;

    /// <summary>
    /// 构造函数,初始化玩家、状态机和动画布尔参数名
    /// </summary>
    /// <param name="_player">玩家对象</param>
    /// <param name="_stateMachine">玩家状态机</param>
    /// <param name="_animBooIName">动画布尔参数名</param>
    public PlayerBlackholeState(Player _player, PlayerStateMachine _stateMachine, string _animBooIName) : base(_player, _stateMachine, _animBooIName)
    {
    }

    /// <summary>
    /// 动画结束触发事件,调用基类的同名方法
    /// </summary>
    public override void AnimationFinshTrigger()
    {
        base.AnimationFinshTrigger();
    }

    /// <summary>
    /// 进入玩家黑洞状态时调用,进行状态初始化操作
    /// </summary>
    public override void Enter()
    {
        // 调用基类的 Enter 方法执行通用的进入状态逻辑
        base.Enter();

        // 记录玩家刚体的初始重力缩放值
        defaultGravity = player.rb.gravityScale;

        // 标记黑洞技能尚未使用
        skillUsed = false;

        // 设置状态计时器为飞行时间,控制飞行持续时长
        stateTimer = flyTime;

        // 将玩家刚体的重力缩放值设置为 0,使玩家在飞行阶段不受重力影响
        player.rb.gravityScale = 0;
    }

    /// <summary>
    /// 退出玩家黑洞状态时调用,进行状态清理操作
    /// </summary>
    public override void Exit()
    {
        // 调用基类的 Exit 方法执行通用的退出状态逻辑
        base.Exit();

        // 恢复玩家刚体的初始重力缩放值
        player.rb.gravityScale = defaultGravity;

        // 使玩家恢复不透明状态
        player.MakeTransprent(false);
    }

    /// <summary>
    /// 每帧更新玩家黑洞状态的逻辑
    /// </summary>
    public override void Update()
    {
        // 调用基类的 Update 方法执行通用的更新逻辑
        base.Update();

        // 如果状态计时器大于 0,说明玩家处于飞行阶段
        if (stateTimer > 0)
        {
            // 设置玩家刚体的速度,使其向上飞行
            player.rb.velocity = new Vector2(0, 15);
        }
        // 如果状态计时器小于 0,说明飞行阶段结束
        if (stateTimer < 0)
        {
            // 设置玩家刚体的速度,使其有一个轻微的向下速度
            player.rb.velocity = new Vector2(0, -.1f);

            // 如果黑洞技能尚未使用
            if (!skillUsed)
            {
                // 检查黑洞技能是否可以使用
                if (player.skill.blackhole.CanUseSkill())
                {
                    // 使用黑洞技能,并标记技能已使用
                    player.skill.blackhole.CanUseSkill();
                    skillUsed = true;
                }
            }
        }

        // 检查黑洞技能是否已经完成
        if (player.skill.blackhole.SkillCompleted())
        {
            // 如果技能完成,切换玩家状态到空气状态
            stateMachine.ChangeState(player.airState);
        }
    }
}

注:记得在player1中实例化

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。