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

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

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

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,选项要-2SetPlotBar(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}));}#endregionpublic 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);}}

最终效果

相关文章:

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…...

再畅通工程(最小生成树)

题目描述&#xff1a;还是畅通工程 某省调查乡村交通状况&#xff0c;得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通&#xff08;但不一定有直接的公路相连&#xff0c;只要能间接通过公路可达即可&#xff09;&…...

前后端分离不可忽视的陷阱,深入剖析挑战,分享解决方案,助你顺利实施分离开发。

不管你设计的系统架构是怎么样&#xff0c;最后都是你的组织内的沟通结构胜出。这个观点一直在组织内不断地被证明&#xff0c;但也不断地被忽略。 前后端分离的利与弊 近几年&#xff0c;随着微服务架构风格的引入、前后端生态的快速发展、多端产品化的出现&#xff0c;前后…...

(四)库存超卖案例实战——优化redis分布式锁

前言 在上一节内容中&#xff0c;我们已经实现了使用redis分布式锁解决商品“超卖”的问题&#xff0c;本节内容是对redis分布式锁的优化。在上一节的redis分布式锁中&#xff0c;我们的锁有俩个可以优化的问题。第一&#xff0c;锁需要实现可重入&#xff0c;同一个线程不用重…...

【ROS入门】雷达、摄像头及kinect信息仿真以及显示

文章结构 雷达信息仿真以及显示Gazebo仿真雷达配置雷达传感器信息xacro文件集成启动仿真环境 Rviz显示雷达数据 摄像头信息仿真以及显示Gazebo仿真摄像头新建xacro文件&#xff0c;配置摄像头传感器信息xacro文件集成启动仿真环境 Rviz显示摄像头数据 kinect信息仿真以及显示Ga…...

实用篇-认识微服务

一、服务架构演变 1. 单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部署 单体架构的优点&#xff1a; 架构简单部署成本低 单体架构的缺点&#xff1a; 耦合度高 2. 分布式架构 分布式架构&#xff1a; 根据业务功能对系…...

【产品运营】产品需求应该如何管理

产品项目在进行时经常会有一些需求需要实现&#xff0c;需求是产品更新迭代的动力&#xff0c;需求也是从用户诉求转化而来&#xff1b;在做需求管理时&#xff0c;我们需要判断一个需求的优先级等方面&#xff0c;对产品进行优化&#xff1b; 目录&#xff1a; 一、 为什么要…...

Linux 系统调用IO口,利用光标偏移实现文件复制

用系统调用IO函数实现从一个文件读取最后2KB数据并复制到另一个文件中&#xff0c;源文件以只读方式打开&#xff0c;目标文件以只写的方式打开&#xff0c;若目标文件不存在&#xff0c;可以创建并设置初始值为0664&#xff0c;写出相应代码&#xff0c;要对出错情况有一定的处…...

【原创】指针变量作为函数参数要点注意

指针变量作为函数参数要点注意&#xff08;已写至笔记&#xff09; 1传参指针不加*&#xff08;main中函数&#xff09; 2收参指针要加*&#xff08;被main调用的函数&#xff09; 3传参指针名可与收参指针名不同&#xff0c;不影响 4【问】如何看主函数中指针所指内容是否改变…...

SpringMVC Day 04 : 数据绑定

前言 SpringMVC是一个非常流行的Java Web框架&#xff0c;它提供了很多方便的功能和工具来帮助我们构建高效、灵活的Web应用程序。其中&#xff0c;数据绑定就是SpringMVC中非常重要的一部分&#xff0c;它可以帮助我们方便地将请求参数绑定到Java对象上&#xff0c;从而简化了…...

2.3.1 协程设计原理与汇编实现

1.为什么要有协程&#xff1f; 同步的编程方式&#xff0c;异步的性能。同步编程时&#xff0c;我们需要等待io就绪。但是在协程这里&#xff0c;我们使用一种机制&#xff0c;当io需要等待时&#xff0c;就切到下一个io&#xff0c;之后当之前的io就绪时&#xff0c;再切换回来…...

J2EE项目部署与发布(Windows版本)->会议OA单体项目Windows部署,spa前后端分离项目Windows部署

会议OA单体项目Windows部署spa前后端分离项目Windows部署 1.会议OA单体项目Windows部署&#xff08;以实施的角度&#xff09; 将项目放入webapp&#xff0c;项目能够访问: 首先拿到war包和数据库脚本&#xff0c;并检查是否有什么问题。 如何查看项目报错信息&#xff08;当你…...

Lua脚本语言

1. 概念 Lua&#xff08;发音为"loo-ah"&#xff0c;葡萄牙语中的"lua"意为月亮&#xff09;是一种轻量级的、高效的、可嵌入的脚本编程语言。官网Lua最初由巴西计算机科学家Roberto Ierusalimschy、Waldemar Celes和Luiz Henrique de Figueiredo于1993年开…...

cat()函数和print()函数的区别

目录 区别一&#xff1a; 区别二&#xff1a; cat、print函数都是输出函数。 区别一&#xff1a; cat()函数不能赋值&#xff1b; print()函数可以赋值。 x<-cat("hello world") //赋值 hello world x //cat函数无返回值 NULLy<-print("hello …...

宝塔面板安装Python和Flask(新版Python项目)

&#xff08;一&#xff09;宝塔面板的项目菜单&#xff0c;打开Python项目的“项目版本管理” 安装Python版本3.10.0。 会创建一个Python版本的文件夹www/server/pyproject_evn/versions/ 会创建一个Python虚拟环境的文件夹www/server/pyproject_evn/python_venv/ &#xf…...

火柴排队.

题意&#xff1a;给两列火柴&#xff0c;可以交换任意相邻的火柴&#xff0c;使得&#xff08;ai-bi)^2的和最小&#xff0c;求最小交换次数。 分析&#xff1a;使得&#xff08;ai-bi)^2的和最小&#xff0c;即a^2-2abb^2的和最小&#xff0c;那么使得2ab最大&#xff0c;就可…...

改善游戏体验:数据分析与可视化的威力

当今&#xff0c;电子游戏已经超越了娱乐&#xff0c;成为一种文化现象&#xff0c;汇聚了全球数十亿的玩家。游戏制作公司正采用越来越复杂的技术来提高游戏质量&#xff0c;同时游戏数据分析和可视化工具变得不可或缺。 数据的力量&#xff1a;解析游戏体验 游戏制作涉及到大…...

GEE:本地影像上传到GEE的Assets中,并输入机器学习算法中作为特征变量

作者:CSDN @ _养乐多_ 当我们在 Google Earth Engine(GEE)中应用机器学习算法时,会输入一些影像作为特征变量数据,进一步根据这些特征影像去推理未知区域的数据。但是 GEE 平台上计算特征变量的 API 函数并不是非常全面,我们希望获得更多的特征用于分类。这个时候,我们…...

【Mybatis源码】XMLConfigBuilder构建器 - 读取XML配置初始化Configuration对象

XMLConfigBuilder是Mybatis中定义的进行构建Configuration对象的类,此类用于读取XML配置文件创建并初始化Configuration对象; 上一篇中我们介绍了XMLConfigBuilder构建器加载XML配置文件以及创建Configuration对象https://blog.csdn.net/m1729339749/article/details/133983…...

Python算法练习 10.28

leetcode 700 二叉搜索树中的搜索 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和一个整数值 val。 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 null 。 示例 1: 输入&#xff1a;root [4,2,7,1,…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...