• Unity 实现原神中的元素反应


    一、元素反应

    • 原神中共有七种元素,分别是水、火、冰、岩、风、雷、草。这七种元素能互相作用
    • Demo下载:Download

    image-20240424150440824

    • 元素反应表格图示,可能不够精准
    /绽放原激化
    /蒸发超载融化燃烧结晶扩散烈绽放/
    蒸发/感电冻结/碎冰绽放结晶扩散//
    超载感电/超导原激化结晶扩散超绽放超激化
    融化冻结/碎冰超导//结晶扩散//
    燃烧绽放原激化/////蔓激化
    结晶结晶结晶结晶/////
    扩散扩散扩散扩散/////

    二、实现效果

    GIF 2024-4-24 星期三 11-17-38

    • 将每种元素当做卡牌打出,本篇文章只谈元素反应,不谈论元素反应倍率。大概的反应如上图和上表所示。
    • 依次打出两张卡牌,判断两张卡牌是否会发生元素反应,如果发生反应,打印相应的日志(具体的实现自行设置)
    • 如果不发生反应,删除上一张卡牌(场上同时只保存一种元素)
    • 绽放和原激化反应是两种元素结合产生的特殊反应,理解困难可以忽略

    三、代码示例

    • 卡牌类

    既然我们是以卡牌打出的方式实现元素反应,首先我们要定义一个卡牌类

    using System;
    using UnityEngine;
    
    public enum CardElement
    {
        Fire,  // 火
        Water, // 水
        Thunder, // 雷
        Ice,    // 冰
        Grass,  // 草
        Rock,   // 岩
        Wind,   // 风
        //Bloom,   // 绽放
        //Sharpen   // 激化
    }
    
    [Serializable]
    public class Card
    {
        public string EName;
        public CardElement Element; // 卡牌的属性
    
        public Card(CardElement element, int value)
        {
            Element = element;
            EValue = value;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 定义接口

    因为元素反应涉及10多种,如果要考虑先后顺序的话可能会更多。所以我们要创建一个接口,接口里定义一个事件和反应方法。

    using System;
    
    public interface IElementalReaction
    {
        event Action OnReactionOccurred;
    
        void React(Card card1, Card card2);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 实现接口

    假设火元素卡牌和水元素卡牌打出会触发蒸发反应,那么我们需要创建一个蒸发反应的类,并继承元素反应的接口

    using System;
    using UnityEngine;
    
    //蒸发=水+火
    public class EvaporationReaction : IElementalReaction
    {
        public event Action OnReactionOccurred;
    
        public void React(Card card1, Card card2)
        {
            Debug.Log($"{card1.Element} + {card2.Element} = 蒸发");
            OnReactionOccurred?.Invoke();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果你有多个反应类,那么就要创建多个元素反应类,这里就不一一展示。都是同样的代码。

    • 元素反应检测类

    光有元素元素反应类还不够,我们还需要注册那些元素之间会触发对应的反应,所以这里我定义了一个元素反应类,在不考虑卡牌先后顺序的情况下,我们使用switch语句来返回产生反应的类型。

    public static class ElementalReactionFactory
    {
        public static IElementalReaction GetReaction(CardElement element1, CardElement element2)
        {
            // 使用元组排序元素,确保顺序无关性
            var key = element1 < element2 ? (element1, element2) : (element2, element1);
            
            return key switch
            {
                (CardElement.Fire, CardElement.Water) => new EvaporationReaction(),//蒸发
                (CardElement.Fire, CardElement.Thunder) => new OverloadReaction(),//超载
                (CardElement.Fire, CardElement.Ice) => new MeltReaction(),//融化
                (CardElement.Fire, CardElement.Grass) => new BurningReaction(),//燃烧
                (CardElement.Water, CardElement.Thunder) => new ElectrifyReaction(),//感电
                (CardElement.Water, CardElement.Ice) => new FrozenReaction(),//冻结
                (CardElement.Water, CardElement.Grass) => new BloomReaction(),//绽放
                (CardElement.Thunder, CardElement.Ice) => new SuperconDuctivityReaction(),//超导
                (CardElement.Thunder, CardElement.Grass) => new SharpenReaction(),//原激化
                (CardElement.Water, CardElement.Rock) => new RockCrystallizeReaction(),//结晶
                (CardElement.Thunder, CardElement.Rock) => new RockCrystallizeReaction(),
                (CardElement.Ice, CardElement.Rock) => new RockCrystallizeReaction(),
                (CardElement.Fire, CardElement.Rock) => new RockCrystallizeReaction(),
                (CardElement.Water, CardElement.Wind) => new WindDiffuseReaction(),//扩散
                (CardElement.Thunder, CardElement.Wind) => new WindDiffuseReaction(),
                (CardElement.Ice, CardElement.Wind) => new WindDiffuseReaction(),
                (CardElement.Fire, CardElement.Wind) => new WindDiffuseReaction(),
                //(CardElement.Fire, CardElement.Bloom) => new FierceBloomReaction(),//烈绽放
               // (CardElement.Thunder, CardElement.Bloom) => new OverBloomReaction(),//超绽放
               // (CardElement.Thunder, CardElement.Sharpen) => new HyperActivationReaction(),//超激化
                //(CardElement.Grass, CardElement.Sharpen) => new RamificationReaction(),//蔓激化
                _ => null,
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    基础设置已经差不多了,接下来我们创建一个Test脚本用来实现卡牌,这里不要照抄我的,可以根据自己的需求来实现。

    • 测试脚本

    简单介绍下Test脚本的内容。大概是设置了打出的卡牌和卡牌按键的预制体,然后运行时动态创建每一种卡牌按键,单机卡牌按键会向上打出卡牌,同时卡池内的卡牌是否会发生元素反应。按Esc清空卡池,代码写的不规范,只做功能示意。

    using System;
    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class Test : MonoBehaviour
    {
        private List playedCards;
        public Transform beforContent;
        public GameObject beforPrefab;
        public Transform afterContent;
        public GameObject afterPrefab;
        private IElementalReaction reaction;
    
        private void Start()
        {
            InitializedCard();
        }
    
        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                ClearCards();
            }
        }
    
        // 初始化
        private void InitializedCard()
        {
            playedCards = new List();
    
            foreach (Transform item in beforContent)
                Destroy(item.gameObject);
    
            foreach (Transform item in afterContent)
                Destroy(item.gameObject);
    
    
            for (int i = 0; i < Enum.GetValues(typeof(CardElement)).Length; i++)
            {
                Card card = new((CardElement)i, i);
                CreateCardButton(card);
            }
        }
    
        // 创建卡牌按钮
        private void CreateCardButton(Card newCard)
        {
            GameObject cardObj = Instantiate(beforPrefab, beforContent);
            Card card = new(newCard.Element, newCard.EValue);
            cardObj.GetComponentInChildren().text = card.EName;
            cardObj.GetComponentInChildren().color = card.EColor;
            cardObj.GetComponent

    以上代码仅代表个人水平,水平有限,这里仅提供想法思路,如有更好的方法欢迎评论区讨论。

  • 相关阅读:
    Oracle RAC ASM磁盘组删除、添加磁盘
    WEB安全基础 - - -Linux反弹shell
    Spring Security JWT Authentication and Authorisation(一)
    《微信小程序-进阶篇》Lin-ui组件库源码分析-动画组件Transition(一)
    OceanBase CEO杨冰:小就是大,构建企业核心竞争力
    信号与线性系统分析(吴大正,郭宝龙)(信号的分类)
    你听说过推挽电路吗?避免交越失真
    八股文之git
    本地开发好的 SAP UI5 应用部署到 ABAP 服务器时,中文字符变成乱码的原因分析和解决方案
    Vue--解决Scss报错:Syntax Error: TypeError: this.getOptions is not a function
  • 原文地址:https://blog.csdn.net/li1214661543/article/details/138184661