Unity的live2dgalgame多语言可配置剧情框架

这段代码用于读取表格

复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OfficeOpenXml;
using System.IO;
using UnityEngine.Networking;
using UnityEngine.UI;
using Random = UnityEngine.Random;
 

public class Plots : MonoBehaviour
{
    public static string ReadingExcel;//正在读取的表格
    [Header("表格文件夹")] public static string URL =  Application.streamingAssetsPath;

    public static string PlotsEXCEL = "Plots";
    private static bool m_loaded;


    
    public  class plot
    {
        public string index, CN,NameCN, NameEN,EN,NameJP, JP,Face;
    }

    public static List<plot> S_Plots= new List<plot>();
    public virtual void OnEnable()
    {
        initialization();
    }

    //初始化
    public void initialization()
    {
        if (!m_loaded)
        {
            LoadExcel();
            m_loaded = true;
        } 

    }

    void LoadExcel()
    {

        //获取Excel文件的信息
        foreach (var VARIABLE in ReadFile())
        {
            Debug.Log("剧情挂载成功");
            FileInfo fileInfo = new FileInfo(VARIABLE);
            //加载背包信息
            if (VARIABLE.Contains(PlotsEXCEL))
            {

                //通过Excel表格的文件信息,打开Excel表格
                //使用using(){}语句命令,在结束时自动关闭文件
                using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
                {
                    //读取Excel中的第一张表, 注意EPPlus的索引值是从1开始的

                    ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];
                    //取得第一行第一列的数据
//                    Debug.Log("行数"+worksheet.Dimension.End.Row + 1);

                    for (int Left = 2; Left < worksheet.Dimension.End.Row + 1; Left++) //根据行数遍历
                    {
                        
                            if (worksheet.Cells[Left, 1].Value.ToString().Length>0)
                            {
                                plot Plot = new plot();
                                Plot.index= worksheet.Cells[Left, 1].Value.ToString();
                                Plot.Face= worksheet.Cells[Left, 2].Value.ToString();
                                Plot.CN= worksheet.Cells[Left, 3].Value.ToString();
                                Plot.NameCN= worksheet.Cells[Left, 4].Value.ToString();
                                Plot.EN= worksheet.Cells[Left, 5].Value.ToString();
                                Plot.NameEN= worksheet.Cells[Left, 6].Value.ToString();
                                Plot.JP= worksheet.Cells[Left, 7].Value.ToString();
                                Plot.NameJP= worksheet.Cells[Left, 8].Value.ToString();
                                S_Plots.Add(Plot);
                            }

                        
               
                  
                    }
                }


            }
        }

    }

    /// <summary>
    /// 字符串转Enum
    /// </summary>
    /// <typeparam name="T">枚举</typeparam>
    /// <param name="str">字符串</param>
    /// <returns>转换的枚举</returns>
    public static T ToEnum<T>(string str)
    {
        try
        {
            return (T)Enum.Parse(typeof(T), str);
        }
        catch (ArgumentException e)
        {
            Debug.LogError("未找到系列"+str);
            throw;
        }

    }

 
    static List<string> ReadFile()
    {
        List<string> files = GetFiles(URL, "*.xlsx");


        List<string> GetFiles(string directory, string pattern)
        {
            List<string> files = new List<string>();
            foreach (var item in Directory.GetFiles(directory, pattern))
            {
                files.Add(item);
            }

            foreach (var item in Directory.GetDirectories(directory))
            {
                files.AddRange(GetFiles(item, pattern));
            }

            return files;
        }

        return files;
    }
}

这个方法里面设置剧情列表,和分支事件

cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using DG.Tweening;
using Live2D.Cubism.Rendering;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using UnityEngine;
using UnityEngine.UI;

public class PlotReader : MonoBehaviour
{
   public Button[] ChoiceButton;
   public Text Text_Plot,Text_Name;
   public static int[] PlotBar;
   public static Action PlotFinEvent;
   public Button BTN_NextStep,BTN_Auto,BTN_Skip;
   public bool AutoMode,SkipMode;

   public Button LanguageCN, LanguageEN, LanguageJP;

   public float DomoveOffeset = 100;
   public float DomoveTime=0.1f;
   public GameObject Live2DFolider;

   public int index=0;
   private void Start()
   {
      LanguageCN.onClick.AddListener(()=>
      {
         Center.Language = "CN";
         RefreshLanguage();
      });
      LanguageEN.onClick.AddListener(()=>
      {
         Center.Language = "EN";
         RefreshLanguage();
      });
      LanguageJP.onClick.AddListener(()=>
      {
         Center.Language = "JP";
         RefreshLanguage();
      });
      BTN_Auto.onClick.AddListener(() =>
      {
         AutoMode = !AutoMode;
                  SkipMode = false;
               });
      BTN_Skip.onClick.AddListener(() =>
      {
         SkipMode = !SkipMode;
         AutoMode = false;
      });
      
      BTN_NextStep.onClick.AddListener(PlotNext);
      //注意!!! 剧情要-1,选项要-2
      SetPlotBar(new int[]{0,1,2,3,4,5,6,7},() => MakeChoice(new int[] { 7, 8 ,16}));
      PlotNext();
   }

   private float AutoTimeindex;
   private float AutoTimeMax = 3f;
   private void Update()
   {
      if (AutoMode)
      {
         if (index<=PlotBar.Length)
         {
            AutoTimeindex -= Time.deltaTime;
         }
         if (AutoTimeindex < 0 )
         {
            AutoTimeindex = AutoTimeMax;
            PlotNext();
         }
      }

      if (SkipMode)
      {
         if (index<=PlotBar.Length)
         {
            AutoTimeindex -= Time.deltaTime*20;
         }
         if (AutoTimeindex < 0 )
         {
            AutoTimeindex = AutoTimeMax;
            PlotNext();
         }
      }
   }

   public void PlotNext()
   {
      if (index<PlotBar.Length)
      {
         DoMethodEvent(Plots.S_Plots[PlotBar[index]].Face);
         Text_Plot.text = GetLanguagePlot(PlotBar[index]);
         Text_Name.text = GetLanguageName(PlotBar[index]);
      }else if (index== PlotBar.Length)
      {
         PlotFinEvent();
      }

      index++;
   }

   public void RefreshLanguage()
   {
      try
      {
         Text_Plot.text = GetLanguagePlot(PlotBar[index-1]);
         Text_Name.text = GetLanguageName(PlotBar[index-1]);
      }
      catch (IndexOutOfRangeException e)
      {
         Text_Plot.text = GetLanguagePlot(PlotBar[PlotBar.Length-1]);
         Text_Name.text = GetLanguageName(PlotBar[PlotBar.Length-1]);
      }
   
   }

   /// <summary>
   /// 根据语言获得剧情
   /// </summary>
   /// <param name="index"></param>
   /// <returns></returns>
   public string GetLanguagePlot(int index)
   {
    //  Debug.LogError(index+Plots.S_Plots[index].CN+Plots.S_Plots[index].NameCN);
      switch (Center.Language)
      {
         case "CN":
            return Plots.S_Plots[index].CN;
         case "EN":
            return Plots.S_Plots[index].EN;
         case "JP":
            return Plots.S_Plots[index].JP;
      }
Debug.LogError("语言??");
      return null;
   }
   /// <summary>
   /// 根据语言获得剧情
   /// </summary>
   /// <param name="index"></param>
   /// <returns></returns>
   public string GetLanguageName(int index)
   {
      switch (Center.Language)
      {
         case "CN":
            return Plots.S_Plots[index].NameCN;
         case "EN":
            return Plots.S_Plots[index].NameEN;
         case "JP":
            return Plots.S_Plots[index].NameJP;
      }
      Debug.LogError("语言??");
      return null;
   }
   
   
   /// <summary>
   /// 设置对话列表
   /// </summary>
   /// <param name="t"></param>
   public void SetPlotBar(int[] t,Action FinEvent)
   {
      PlotBar = t;
      PlotFinEvent = FinEvent;
   }

   #region 分支
   public void MakeChoice(int [] choices)
   {
      CloseAllButtons();
      for (int i = 0; i<choices.Length; i++)
      {
         int i1 = i;

         ChoiceButton[i1].gameObject.SetActive(true);
         ChoiceButton[i1].transform.Find("Text").GetComponent<Text>().text = GetLanguagePlot(choices[i1]+1);
         ChoiceButton[i1].onClick.AddListener(() =>
         {
            index = 0;
            Debug.LogError("执行事件BTN"+(choices[i1]+2));
            ExecuteMethodByName("BTN"+(choices[i1]+2));
            CloseAllButtons();
            PlotNext();
         });
      }
   }

   public void CloseAllButtons()
   {
      foreach (var VARIABLE in ChoiceButton)
      {
         VARIABLE.onClick.RemoveAllListeners();
         VARIABLE.gameObject.SetActive(false);
      }
   }

   public void BTN9()
   {
      SetPlotBar(new int[]{10,11,12,13},JumpToGameLevel);
   }
   public void BTN10()
   {
      SetPlotBar(new int[]{14,15,16},JumpToGameLevel);
   }
   public void BTN18()
   {
      SetPlotBar(new int[]{0,1,2,3,4,5,6,7},() => MakeChoice(new int[] { 7, 8 ,16}));
   }
   #endregion

   public void JumpToGameLevel()
   {
      Debug.LogError("将跳转场景");
   }
   public void ExecuteMethodByName(string methodName)
   {
      // 使用反射获取类的类型
      Type type = this.GetType();

      // 使用反射获取方法信息
      MethodInfo methodInfo = type.GetMethod(methodName);

      if (methodInfo != null)
      {
         // 调用匹配的方法
         methodInfo.Invoke(this, null);
      }
      else
      {
         Console.WriteLine("Method not found: " + methodName);
      }
   }

   public string[] CutMethod(string input)
   {
      return input.Split('+');
   }

   public void DoMethodEvent(string input)
   {
      Debug.LogError(input);
      foreach (var VARIABLE in CutMethod(input))
      {
         if (!VARIABLE.Contains("("))
         {
            ExecuteMethodByName(VARIABLE);
         }
         else if (VARIABLE.Contains("JOIN_"))
         {
            Match match = Regex.Match(VARIABLE, @"\(([^)]*)\)");
            if (match.Success)
            {
               // 获取括号内的内容,并使用逗号分割
               string[] parts = match.Groups[1].Value.Split(',');

               if (parts.Length == 4)
               {
                  string stringValue = parts[0];
                  int intValue1, intValue2;
                  if (int.TryParse(parts[1], out intValue1) && int.TryParse(parts[2], out intValue2))
                  {
                     string stringValue2 = parts[3];

                     GameObject go = Instantiate(Resources.Load<GameObject>($"Live2D/{stringValue}"), Live2DFolider.transform);
                     go.transform.position = new Vector3(-999, -999, 2);
                     go.name = go.name.Replace("(Clone)", "");
                     Vector3 worldCoordinate= Vector3.down;
                     ;
                     switch (stringValue2)
                     {
                        case "Left":

                           worldCoordinate =Camera.main.ScreenToWorldPoint( new Vector3(intValue1-DomoveOffeset, intValue2, 2));
                           Debug.LogError(worldCoordinate);
                           worldCoordinate.z = 2;
                           go.transform.position = worldCoordinate;
                           worldCoordinate = Camera.main.ScreenToWorldPoint(new Vector3(intValue1, intValue2, 0));
                           worldCoordinate.z = 0;
                           go.transform.DOMove(worldCoordinate,DomoveTime);


                         
                           break;
                        case "Right":
                           worldCoordinate =Camera.main.ScreenToWorldPoint( new Vector3(intValue1+DomoveOffeset, intValue2, 2));
                           Debug.LogError(worldCoordinate);
                           worldCoordinate.z = 2;
                           go.transform.position = worldCoordinate;
                           worldCoordinate = Camera.main.ScreenToWorldPoint(new Vector3(intValue1, intValue2, 0));
                           worldCoordinate.z = 0;
                           go.transform.DOMove(worldCoordinate,DomoveTime);

                           break;
                     }

                  }
                  else
                  {
                     Debug.LogError("Failed to parse integers from the input.");
                  }
               }
               else
               {
                  Debug.LogError("Input does not contain 4 comma-separated values.");
               }
            }
            else
            {
               Debug.LogError("Input does not match the expected format.");
            }
         }
         else if (VARIABLE.Contains("SETA_"))
         {
            Match match = Regex.Match(VARIABLE, @"\(([^)]*)\)");
            if (match.Success)
            {
               // 获取括号内的内容,并使用逗号分割
               string[] parts = match.Groups[1].Value.Split(',');

               if (parts.Length == 3)
               {
                  string stringValue = parts[0];
                  int intValue1, intValue2;
                  if (int.TryParse(parts[1], out intValue1) && int.TryParse(parts[2], out intValue2))
                  {
                     GameObject go = Live2DFolider.transform.Find(parts[0]).gameObject;
                     SetLive2DAlpha(go,intValue1,intValue2);
                  }
                  else
                  {
                     Debug.LogError("Failed to parse integers from the input.");
                  }
               }
               else
               {
                  Debug.LogError("Input does not contain 3 comma-separated values."+VARIABLE+$"length={parts.Length}");
               }
            }
            else
            {
               Debug.LogError("Input does not match the expected format.");
            }
         }
         else if (VARIABLE.Contains("FACE"))
         {
            Match match = Regex.Match(VARIABLE, @"\(([^)]*)\)");
            if (match.Success)
            {
               // 获取括号内的内容,并使用逗号分割
               string[] parts = match.Groups[1].Value.Split(',');

               if (parts.Length == 2)
               {
                  string stringValue = parts[0];
                  string stringValue2 = parts[1];
                  GameObject go = Live2DFolider.transform.Find(parts[0]).gameObject;
                  SetFace(go,stringValue2);
               }
               else
               {
                  Debug.LogError("Input does not contain 4 comma-separated values.");
               }
            }
            else
            {
               Debug.LogError("Input does not match the expected format.");
            }
         }
         else if (VARIABLE.Contains("LEAV_"))
         {
            Match match = Regex.Match(VARIABLE, @"\(([^)]*)\)");
            if (match.Success)
            {
               // 获取括号内的内容,并使用逗号分割
               string[] parts = match.Groups[1].Value.Split(',');

               if (parts.Length == 2)
               {
                  string stringValue = parts[0];
                  GameObject go = Live2DFolider.transform.Find(parts[0]).gameObject;
                  Vector3 worldCoordinate;
                  StartCoroutine(des(go));
                        break;
                        IEnumerator des(GameObject go)
                        {
                           SetLive2DAlpha(go,
                              (int)(go.transform.Find("Drawables").GetComponentsInChildren<CubismRenderer>()[0]
                                 .GetComponent<CubismRenderer>().Color.a)*100, 0);
                           Debug.LogError($"Des{go.name}");
                           yield return new WaitForSeconds(0.3f);
                           Destroy(go);
                        }
                  
               }
               else
               {
                  Debug.LogError("Input does not contain 4 comma-separated values.");
               }
            }
            else
            {
               Debug.LogError("Input does not match the expected format.");
            }
         }
      }
   }

   public void SetLive2DAlpha(GameObject target, int begin,int end)
   {
      StartCoroutine(AlphaChangerCoroutine(target, begin / 100.0f, end / 100.0f));
   }

   private IEnumerator AlphaChangerCoroutine(GameObject target, float begin, float end)
   {
      foreach (var renderer in target.transform.Find("Drawables").GetComponentsInChildren<CubismRenderer>())
      {
         Color currentColor = renderer.Color;
         currentColor.a = begin;
         Debug.LogError(currentColor.a);
         renderer.Color = currentColor;
      }
      float duration = 0.1f;
      int numSteps = 10;
      float stepTime = duration / numSteps;

      for (int step = 0; step <= numSteps; step++)
      {
         float a = begin;
         if (end>begin)
         {
            a += (end - begin) / numSteps * step;
         }
         else
         {
            a -= (begin - end) / numSteps * step;
         }
         foreach (var renderer in target.transform.Find("Drawables").GetComponentsInChildren<CubismRenderer>())
         {
//            Debug.LogError(renderer.name);
            Color currentColor = renderer.Color;
            currentColor.a = a;
            Debug.LogError(currentColor.a);
            renderer.Color = currentColor;
         }
         yield return new WaitForSeconds(stepTime);
      }
   }
   public void SetFace(GameObject go, string Animatorname)
   {
      go.GetComponent<Animator>().Play(Animatorname);
   }
   
   
}

最终效果

相关推荐
天人合一peng4 小时前
unity 生成标记根据背景色标记变色
unity·游戏引擎
天人合一peng8 小时前
unity 生成标记根据背景色变色为明显的颜色
unity·游戏引擎
魔士于安8 小时前
Unity 超市总动员 超市收银台 超市货架 超市购物手推车 超市常见商品
游戏·unity·游戏引擎·贴图·模型
CandyU28 小时前
Unity —— 数据持久化
unity·游戏引擎
zh路西法8 小时前
【Unity实现Oneshot胶卷显形】游戏窗口化与Win32API的使用
游戏·unity·游戏引擎
迪捷软件9 小时前
显控系统虚拟仿真的工程化路径
游戏引擎·cocos2d
凡情13 小时前
android隐私合规检测
android·unity
小贺儿开发13 小时前
Unity3D 本地 Stable Diffusion 文生图效果演示
人工智能·unity·stable diffusion·文生图·ai绘画·本地化
Swift社区14 小时前
传统游戏引擎 vs 鸿蒙 System 架构
架构·游戏引擎·harmonyos
mxwin1 天前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader