unity随机生成未知符号教程
目录
- 前言
- 方法1
- 方法2
- 脚本
- 后言
- 示例代码
前言
在某些游戏中,有一些让人感到意味不明的未知符号,例如在游戏《巴别塔圣歌》中,就有这样一些能让人在初次就看不懂的未知符号。
或者在其他时候,这些未知符号如果跟粒子系统结合在一起的话,也可以当作是一种特效,可以增加游戏的神秘感。
而现在,如果你想学的话,那么现在就可以开始学了。
方法1
首先讲最简单的方法,最简单的就先随机地显示Wingdings字体的字符,然后在随机显示字符后等待一小会即可,这个对于很多人来说都容易去理解,但是,这个方法主要的难点是如何将TextMeshPro
中的字体设为Wingdings字体,因此,接下来就要详细的讲一下如何更改TextMeshPro
组件的字体。
-
打开文件资源管理器;
-
转到C:\Windows\Fonts,选取里面的Wingdings 常规;
- 将Wingdings 常规拖到unity的项目栏里,并右键选中拖过来的字体,创建
TextMeshPro
的Wingdings字体资产。
- 将
TextMeshPro
组件的字体属性(Font Asset)设为刚才得到的Wingdings字体资产,TextMeshPro
组件的字体也更改好了。
其他只要你学过unity,实现起来就简单,这里就直接上方法了(想用这个方法得需要TextMeshPro
组件)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.VisualScripting;
using System.Runtime.CompilerServices;
using TMPro;public class randomSymbolSummon : MonoBehaviour
{public float waitTime = 0.1f;private bool isEnd = true;private char[] chars;IEnumerator write(){isEnd = false;GetComponent<TextMeshPro>().text = chars[Random.Range(0, chars.Length)].ToString();yield return new WaitForSeconds(waitTime);isEnd = true;}void Start(){chars = new char[127 - 33];char ch = (char)33;for (; ch < 127; ch++){chars[ch - 33] = ch;}write();}void Update(){if (isEnd){StartCoroutine(write());}}
}
下面就是最简单的方法的效果。
方法2
然后来讲难一点的方法,难一点的方法呢,它的核心就是一个可以当作是用于写符号的笔的指针在点上随机移动。
首先,我们要定义一些公有的成员变量。就如点离点的距离,“画板”的长与宽,是否只显示一次符号,线的渲染,线的宽度及等待时间。然后,新建一个summon
方法,这将是我们生成方法2中的符号的核心方法。
public float space = 0.809f;
public uint a = 2;
public uint b = 3;
public Material lineMaterial;
public float lineWidth = 0.1f;
public float waitTime = 0.1f;
private bool isEnd = true;private void summon()
{}
然后,我们在Start
方法里调用一下summon
方法,这将使对象一开始就能生成未知符号,并在Update
函数里面设置执行summon
方法的条件,只有能显示多次符号,并且等会实现的write
协程已经执行完毕,那么就才能执行write
协程。
write
协程,我们要让它能等待,就需要yield return
和新定义的isEnd
变量,因此,刚才就需要什么方法就很明了了。顺带一提醒,就是Start
方法及Update
等方法都不能是协程,这点unity萌新一定要注意!
void Start()
{summon();
}void Update()
{if (!summonOneShot && isEnd){StartCoroutine(write());}
}
接着,就要实现主要的summon
方法了,首先根据“画板”的长与宽和点离点的距离,我们定义一个数组,数组大小为 ( a + 1 ) ( b + 1 ) (a+1)(b+1) (a+1)(b+1)。为了省事,可以在Start
方法内让a
和b
各自增1。并通过指针来一个个的设置点的位置。
private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}
}void Start()
{a++;b++;summon();
}
之后定义一个Vector3
的paths
可变数组,一个有8个bool
的canMove
数组,和一个有8个int
的modeMove
数组,初始化modeMove
数组时,将modeMove
数组第3项和第4项分别设为-1和1。
随后,我们知道,在二维数组中,指针移动二维数组的长度位,就是将指针以垂直方向移动。因此,就可以用变量a
来设置modeMove
数组。
private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>(); bool[] canMove = new bool[8]; int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 }; for (int modei = 0, step = (int)a + 1; modei < 3; ++modei) { modeMove[modei] = -step; modeMove[modeMove.Length - 1 - modei] = step--; }
}
我们需要设定一个绘制符号的结束条件,结束条件呢,就是这个“笔”移到了“画板”每一行及每一列的点,因此,我们就定义一个bool
类型的大小为 a + b a+b a+b的dotMove
数组,如果dotMove
数组全是真,那么等于“笔”移到了第 1 ∼ a 1\sim a 1∼a列的所有点和第 1 ∼ b 1\sim b 1∼b行的所有点了。就需要一个check
方法来检测dotMove
是否全是真。
且结束条件为真时,由于“笔”可能还有一次画的操作,但是“笔”不能回头,所以就也要定义lastDraw
的变量和mode
变量了。
private bool check(bool[] dotMove)
{foreach (bool b in dotMove){if (!b){return false;}}return true;
}private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>(); bool[] canMove = new bool[8]; int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 }; for (int modei = 0, step = (int)a + 1; modei < 3; ++modei) { modeMove[modei] = -step; modeMove[modeMove.Length - 1 - modei] = step--; }bool[] dotMove = new bool[a + b];int mode = 0;bool LastDraw = 1 == Random.Range(0, 2);while (check(dotMove) || LastDraw){if (check(dotMove)){canMove[7 - mode] = false;LastDraw = false;}}
}
而在summon
方法中,我们要对“笔”移动到的点检测一下,假如dots
是一个长为 a + 1 a+1 a+1,宽为 b + 1 b+1 b+1的二维数组,就要让pos
指针分别去通过运算符%
和/
与 a + 1 a+1 a+1进行运算,从而得到pos
在dots
二维数组中的坐标,就可以设置dots
数组项的值。
private bool check(bool[] dotMove)
{foreach (bool b in dotMove){if (!b){return false;}}return true;
}private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>(); bool[] canMove = new bool[8]; int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 }; for (int modei = 0, step = (int)a + 1; modei < 3; ++modei) { modeMove[modei] = -step; modeMove[modeMove.Length - 1 - modei] = step--; }bool[] dotMove = new bool[a + b];bool LastDraw = 1 == Random.Range(0, 2);while (check(dotMove) || LastDraw){if (check(dotMove)){canMove[7 - mode] = false;LastDraw = false;}dotMove[pos % a] = true;dotMove[a + pos / a] = true;}
}
之后,我们定义一个pos
变量,将他的值设为0到 a b − 1 ab-1 ab−1内的随机值,这代表了“笔”的位置,并将这个位置传到paths
数组里,作为方法2中符号的起点。再接着,我们就设置“笔”要移动的方向。
“笔”方向有8种,“↖↑↗←→↙↓↘”这些全都是(分别代表了0~7的数字,这以后会用到)。因此,刚才定义的canMove
和modeMove
数组大小都为8个,并且,假设有一个方向 x x x,因为 x + x 反 = 7 x+x_反=7 x+x反=7,那么它的反方向就是 7 − x 7-x 7−x,因此,刚才就将canMove[7 - mode]
设为假,就不让他回头了。
转到正题,要设置“笔”要移动的方向,就要检测这8个方向中可以移动的方向,就要用到canMove
数组中的每一项作标记。
如果某个方向不能移动,那么就说明到了dots
数组的边界旁,假如让一个指针分别去通过运算符%
和/
与二维数组的长进行运算,那么可以获得二维数组的坐标,我们就可以设置canMove
数组。
private bool check(bool[] dotMove)
{foreach (bool b in dotMove){if (!b){return false;}}return true;
}private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>(); bool[] canMove = new bool[8]; int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 }; for (int modei = 0, step = (int)a + 1; modei < 3; ++modei) { modeMove[modei] = -step; modeMove[modeMove.Length - 1 - modei] = step--; }bool[] dotMove = new bool[a + b];bool LastDraw = 1 == Random.Range(0, 2);while (check(dotMove) || LastDraw){canMove[1] = (0 != pos / a); canMove[3] = (0 != pos % a); canMove[4] = ((a - 1) != pos % a); canMove[6] = ((b - 1) != pos / a); canMove[0] = (canMove[1] && canMove[3]); canMove[2] = (canMove[1] && canMove[4]); canMove[5] = (canMove[6] && canMove[3]); canMove[7] = (canMove[6] && canMove[4]);if (check(dotMove)){canMove[7 - mode] = false;LastDraw = false;}dotMove[pos % a] = true;dotMove[a + pos / a] = true;}
}
那么,我们就因此定义一个mode
变量来从这些可以移动的方向中选取其中的一个让pos
移动了,在pos
移动之后,我们就将pos
移动到的点添加进paths
数组里,一次pos
移动的操作就完成了。以此往复下去,一个完全随机的paths
数组生成了。
private bool check(bool[] dotMove)
{foreach (bool b in dotMove){if (!b){return false;}}return true;
}private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>(); bool[] canMove = new bool[8]; int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 }; for (int modei = 0, step = (int)a + 1; modei < 3; ++modei) { modeMove[modei] = -step; modeMove[modeMove.Length - 1 - modei] = step--; }bool[] dotMove = new bool[a + b];int mode = 0;bool LastDraw = 1 == Random.Range(0, 2);while (check(dotMove) || LastDraw){canMove[1] = (0 != pos / a); canMove[3] = (0 != pos % a); canMove[4] = ((a - 1) != pos % a); canMove[6] = ((b - 1) != pos / a); canMove[0] = (canMove[1] && canMove[3]); canMove[2] = (canMove[1] && canMove[4]); canMove[5] = (canMove[6] && canMove[3]); canMove[7] = (canMove[6] && canMove[4]);if (check(dotMove)){canMove[7 - mode] = false;LastDraw = false;}dotMove[pos % a] = true;dotMove[a + pos / a] = true;mode = Random.Range(0, 8);while (!canMove[mode]){mode = Random.Range(0, 8);}pos += modeMove[mode];paths.Add(dots[pos]);}
}
此时,就可以用这个paths
数组来设置Unity组件LineRenderer
的线条了,不过要设置线条,得先设置线条端点的数量,后设置线条,由于pos
移动的路径就是线条,用paths
数组设置线条就很合适。
private bool check(bool[] dotMove)
{foreach (bool b in dotMove){if (!b){return false;}}return true;
}private void summon()
{Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>(); bool[] canMove = new bool[8]; int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 }; for (int modei = 0, step = (int)a + 1; modei < 3; ++modei) { modeMove[modei] = -step; modeMove[modeMove.Length - 1 - modei] = step--; }bool[] dotMove = new bool[a + b];int mode = 0;bool LastDraw = 1 == Random.Range(0, 2);while (check(dotMove) || LastDraw){canMove[1] = (0 != pos / a); canMove[3] = (0 != pos % a); canMove[4] = ((a - 1) != pos % a); canMove[6] = ((b - 1) != pos / a); canMove[0] = (canMove[1] && canMove[3]); canMove[2] = (canMove[1] && canMove[4]); canMove[5] = (canMove[6] && canMove[3]); canMove[7] = (canMove[6] && canMove[4]);if (check(dotMove)){canMove[7 - mode] = false;LastDraw = false;}dotMove[pos % a] = true;dotMove[a + pos / a] = true;mode = Random.Range(0, 8);while (!canMove[mode]){mode = Random.Range(0, 8);}pos += modeMove[mode];paths.Add(dots[pos]);}GetComponent<LineRenderer>().positionCount = paths.Count;GetComponent<LineRenderer>().SetPositions(paths.ToArray());
}
做到这里,还有几个问题没有解决。
- 变量
a
或b
不能为0,space
不能为0。
解决方法:只需要在Start
方法一开始判断a
,b
或space
为0即可,如果条件达成,就将它们设为默认值。
void Start()
{a = (0 == a ? 2 : a + 1);b = (0 == a ? 3 : b + 1);space = (0 == space ? 0.809f : space);summon();
}
- 有时对象并没有
LineRenderer
组件,却仍要获取对象的LineRenderer
组件,并且必须将LineRenderer
使用世界空间的开关关掉。
解决方法:如果没有LineRenderer
组件,就为它进行初始化,并强制将组件的useWorldSpace
给设为假,让符号一直在物体上。
void Start()
{a = (0 == a ? 2 : a + 1);b = (0 == a ? 3 : b + 1);space = (0 == space ? 0.809f : space);if (null == GetComponent<LineRenderer>()){transform.AddComponent<LineRenderer>();GetComponent<LineRenderer>().material = lineMaterial;GetComponent<LineRenderer>().startWidth = GetComponent<LineRenderer>().endWidth = lineWidth;}GetComponent<LineRenderer>().useWorldSpace = false;summon();
}
这些解决方法弄完之后,也就可以开始看方法2中生成的符号是什么样了。下面就是方法2的效果。
脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.VisualScripting;
using System.Runtime.CompilerServices;public class randomSymbolSummon : MonoBehaviour
{public float space = 0.809f;public uint a = 2;public uint b = 3;public Material lineMaterial;public float lineWidth = 0.1f;public float waitTime = 0.1f;private bool isEnd = true;public bool summonOneShot = false;private bool check(bool[] dotMove){foreach (bool b in dotMove){if (!b){return false;}}return true;}private void summon(){Vector3[] dots = new Vector3[a * b];for (int doti = 0; doti < dots.Length; ++doti){dots[doti] = new Vector3(doti % a * space, doti / a * -space, 0);}List<Vector3> paths = new List<Vector3>();bool[] canMove = new bool[8];int[] modeMove = { 0, 0, 0, -1, 1, 0, 0, 0 };for (int modei = 0, step = (int)a + 1; modei < 3; ++modei){modeMove[modei] = -step;modeMove[modeMove.Length - 1 - modei] = step--;}bool[] dotMove = new bool[a + b];int pos = Random.Range(0, (int)(a * b));int mode = 0;bool LastDraw = 1 == Random.Range(0, 2);paths.Add(dots[pos]);while (!check(dotMove) || LastDraw){canMove[1] = (0 != pos / a);canMove[3] = (0 != pos % a);canMove[4] = ((a - 1) != pos % a);canMove[6] = ((b - 1) != pos / a);canMove[0] = (canMove[1] && canMove[3]);canMove[2] = (canMove[1] && canMove[4]);canMove[5] = (canMove[6] && canMove[3]);canMove[7] = (canMove[6] && canMove[4]);if (check(dotMove)){canMove[7 - mode] = false;LastDraw = false;}dotMove[pos % a] = true;dotMove[a + pos / a] = true;mode = Random.Range(0, 8);while (!canMove[mode]){mode = Random.Range(0, 8);}pos += modeMove[mode];paths.Add(dots[pos]);}GetComponent<LineRenderer>().positionCount = paths.Count;GetComponent<LineRenderer>().SetPositions(paths.ToArray());}IEnumerator write(){isEnd = false;yield return new WaitForSeconds(waitTime);summon();isEnd = true;}// Start is called before the first frame updatevoid Start(){a = (0 == a ? 2 : a + 1);b = (0 == a ? 3 : b + 1);space = (0 == space ? 0.809f : space);if (null == GetComponent<LineRenderer>()){transform.AddComponent<LineRenderer>();GetComponent<LineRenderer>().material = lineMaterial;GetComponent<LineRenderer>().startWidth = GetComponent<LineRenderer>().endWidth = lineWidth;}GetComponent<LineRenderer>().useWorldSpace = false;summon();}void Update(){if (!summonOneShot && isEnd){StartCoroutine(write());}}
}
后言
刚才看到的这些符号,如果用粒子系统搭配的话,使你的游戏就能更好。但是,实际上,你却很难在unity原生的粒子系统上实现这个事情。因此,就得要一个自创的粒子系统,下篇博文教你如何自创粒子系统。
示例代码
-
方法1
-
方法2
相关文章:

unity随机生成未知符号教程
目录 前言方法1方法2脚本后言示例代码 前言 在某些游戏中,有一些让人感到意味不明的未知符号,例如在游戏《巴别塔圣歌》中,就有这样一些能让人在初次就看不懂的未知符号。 或者在其他时候,这些未知符号如果跟粒子系统结合在一起的…...

基于RK3576+FPGA+AI工业控制器的工地防护检测装备解决方案
1.2.1 工地防护检测技术研究现状 在建筑施工的过程中,工人被要求暴露在危险的环境中作业 [2]。因此,防护装备 对于工人的安全与健康具有非常重要的意义[3]。工地工人必须佩戴适当的防护装备, 以降低意外伤害的风险。在过去的几十年里&#x…...

推荐一款PDF压缩的工具
今天一位小伙伴找来,问我有没有办法将PDF变小的办法。 详细了解了一下使用场景: 小伙伴要在某系统上传一个PDF文件,原文件是11.6MB,但是上传时系统做了限制,只能上传小于10MB的文件,如图: 我听…...

混沌映射(Chaotic Map)
一.定义 混沌映射是指一类具有混沌行为的离散时间非线性动力系统,通常由递推公式定义。其数学形式为 ,其中 f 是非线性函数,θ 为参数。它们以简单的数学规则生成复杂的、看似随机的轨迹,是非线性动力学和混沌理论的重要研究对象…...
MySQL对数据库用户的操作
注:‘%’:表示允许远程连接,‘localhost’ :限制本地登陆 – 根据用户名、权限查询用户 SELECT USER FROM mysql.user WHERE USER‘your_name’ AND HOST‘%’; – 彻底删除用户 DROP USER ‘appuser’‘%’; – 刷新使其生效 FL…...

《PyTorch Hub:解锁深度学习模型的百宝箱》
走进 PyTorch Hub 在当今的深度学习领域,模型的复用和共享已成为推动技术飞速发展的关键力量。随着深度学习在计算机视觉、自然语言处理、语音识别等众多领域取得突破性进展,研究人员和开发者们不断探索更高效、更强大的模型架构。然而,从头开始训练一个深度学习模型往往需要…...

数据结构 堆与优先级队列
文章目录 📕1. 堆(Heap)✏️1.1 堆的概念✏️1.2 堆的存储方式✏️1.3 堆的创建✏️1.4 堆的插入✏️1.5 堆的删除 📕2. 优先级队列(PriorityQueue)✏️2.1 堆与优先级队列的关系✏️2.2 优先级队列的构造方法✏️2.3 优先级队列的常用方法 3. Java对象的…...
Leetcode 3569. Maximize Count of Distinct Primes After Split
Leetcode 3569. Maximize Count of Distinct Primes After Split 1. 解题思路2. 代码实现 题目链接:3569. Maximize Count of Distinct Primes After Split 1. 解题思路 这一题的话思路倒是还好,显然,要找出所有distinct的质数的切分&…...

用好 ImageFX,解锁游戏素材生成新姿势:从入门到进阶
用好 ImageFX,解锁游戏素材生成新姿势:从入门到进阶 (备注)大陆ip无法访问到imagefx 地址:https://labs.google/fx/zh/tools/image-fx 对于独立游戏开发者和小型团队而言,美术资源往往是项目推进中的一大痛点。预算有限、专业美术人员缺乏…...
unix/linux,sudo,其基本属性、语法、操作、api
现在我们要深入到sudo的“微观结构”了——它的属性、语法、操作以及是否有传统意义上的“API”。这就像我们从宏观的宇宙现象深入到基本粒子的相互作用一样,充满了探索的乐趣! 一、 sudo 的基本属性 (Fundamental Attributes) 这些属性是sudo作为一款软件和系统工具的核心…...
文本内容变化引起布局尺寸变化 导致的 UI 适配问题
在使用 Flutter 开发应用时,配合 easy_localization 实现多语言切换是一个非常常见的做法。但正如你所说,在不同语言下文字长度差异较大(如英文和中文、阿拉伯语等)会导致界面布局错位、UI 不美观的问题。 这个问题本质上是 文本…...

01-Redis介绍与安装
01-Redis介绍与安装 SQL与NoSQL SQLNoSQL数据结构结构化非结构化数据关联关联的非关联的查询方式SQL查询非SQL事务特性ACIDBASE存储方式磁盘内存拓展性垂直水平使用场景1、数据结构固定2、相关业务对数据安全性、一致性要求较高1、数据结构不固定2、对安全性、一致性要求不高…...
十六、【前端强化篇】完善 TestCase 编辑器:支持 API 结构化定义与断言配置
【前端强化篇】完善 TestCase 编辑器:支持 API 结构化定义与断言配置 前言准备工作第一步:更新前端 `TestCase` 类型定义第二步:改造 `TestCaseEditView.vue` 表单第三步:修改后端代码中的TestCase模型和序列化器第四步:测试强化后的用例编辑器总结前言 在之前的后端文章…...
Kafka broker 写消息的过程
Producer → Kafka Broker → Replication → Consumer|Partition chosen (by key or round-robin)|Message appended to end of log (commit log)上面的流程是kafka 写操作的大体流程。 kafka 不会特意保留message 在内存中,而是直接写入了disk。 那么消费的时候&…...

VR博物馆推动现代数字化科技博物馆
VR博物馆:推动现代数字化科博馆新篇章 随着科技的飞速发展,虚拟现实(Virtual Reality, VR)技术已经逐渐渗透到我们生活的方方面面,其中,VR博物馆作为现代数字化科博馆的重要形式之一,以独特的优…...

Python爬虫之数据提取
本章节主要会去学习在爬虫中的如何去解析数据的方法,要学习的内容有: 响应数据的分类结构化数据如何提取非结构化数据如何提取正则表达式的语法以及使用jsonpath解析嵌套层次比较复杂的json数据XPath语法在Python代码中借助lxml模块使用XPath语法提取非…...

第2讲、Odoo深度介绍:开源ERP的领先者
一、Odoo深度介绍:开源ERP的领先者 Odoo,其前身为OpenERP,是一款在全球范围内广受欢迎的开源企业管理软件套件。它不仅仅是一个ERP系统,更是一个集成了客户关系管理(CRM)、电子商务、网站构建、项目管理、…...

【TCP/IP和OSI模型以及区别——理论汇总】
参考小林code和卡尔哥,感恩! 网络基础篇 面试官您好!OSI和TCP/IP是网络通信中两个关键模型,本质都是分层处理数据传输,但设计理念和应用场景差异很大。 OSI模型是理论上的七层架构,从下到上依次是物理层…...
【HarmonyOS 5】生活与服务开发实践详解以及服务卡片案例
一、金融场景创新实践 智慧银行网点转型 通过统一设备方案整合国产芯片与鸿蒙系统,支持智能柜员机、移动展业终端等设备的弹性硬件组合,降低25%硬件成本。利用元服务框架实现卡片式交互(如客户画像、风险评估一键调取)&a…...
LEAP模型能源需求/供应预测、能源平衡表核算、空气污染物排放预测、碳排放建模预测、成本效益分析、电力系统优化
🌐 LEAP模型(Long-range Energy Alternatives Planning System),即长期能源替代规划系统,是由斯德哥尔摩环境研究所与美国波士顿大学共同开发的基于情景分析的自底向上的能源—环境核算工具。该模型采用自底向上的架构…...

STM32 I2C通信外设
1、外设简介 可变多主机 7位/10位寻址 10位寻址:起始之后的两个字节都作为寻址,第一个字节前5位是11110作为10位寻址的标志位 SMBus:系统管理总线,主要用于电源管理,与I2C类似 2、外设结构框图 比较器、自身地址寄…...

13. springCloud AlibabaSeata处理分布式事务
目录 一、分布式事务面试题 1.多个数据库之间如何处理分布式事务? 2.若拿出如下场景,阁下将如何应对? 3.阿里巴巴的Seata-AT模式如何做到对业务的无侵入? 4.对于分布式事务问题,你知道的解决方案有哪些?请你谈谈? 二、分布式事务问题…...

MySQL 表的内连和外连
一、内连接 内连接实际上就是利用 where 子句对两种表形成的笛卡儿积进行筛选,前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。 select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件; 注意:前面学习的都是内连…...

VR线上展厅特点分析与优势
VR线上展厅:特点、优势与实际应用 VR线上展厅,作为虚拟现实(VR)技术在展示行业的创新应用,正逐步改变着传统的展览方式。通过模拟真实的物理环境,为参观者提供身临其境的展览体验,成为展示行业…...

Python基于SVM技术的手写数字识别问题项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在当今数字化转型加速的时代,手写数字识别作为图像处理与机器学习领域的一个经典问题,具有广…...
Elasticsearch的写入性能优化
优化Elasticsearch的写入性能需要从多维度入手,包括集群配置、索引设计、数据处理流程和硬件资源等。以下是一些关键优化策略和最佳实践: 一、索引配置优化 合理设置分片数与副本数分片数(Shards):过少会导致写入瓶颈(无法并行),过多会增加集群管理开销。公式参考:分…...

2024年数维杯国际大学生数学建模挑战赛A题飞行器激光测速中的频率估计问题解题全过程论文及程序
2024年数维杯国际大学生数学建模挑战赛 A题 复合直升机的建模与优化控制问题 原题再现: (一) 问题的背景 空速,即飞机相对于空气的速度,是飞行期间需要监控的关键参数。空速与飞行状态密切相关,如迎角…...
AWS 成本异常检测IAM策略
问题 审计人员需要看AWS 成本异常检测,则需要开通这个权限。 IAM 自定义策略 {"Version": "2012-10-17","Statement": [{"Action": ["ce:Get*"],"Effect": "Allow","Resource"…...
解决Vue3+uni-app导航栏高亮自动同步方案
路由跳转自动识别导航高亮实现方法 以下代码使用wd-tabbar组件实现路由跳转时自动同步导航栏高亮状态,适用于所有的Vue3uni-app项目。 请根据自身使用框架类型完成,也可根据我使用的UI组件进行完成地址如下: Tabbar 标签栏 | Wot UI &#…...

DeepSeek+SpringAI实现流式对话
大模型的响应速度通常是很慢的,为了避免用户用户能够耐心等待输出的结果,我们通常会使用流式输出一点点将结果输出给用户。 那么问题来了,想要实现流式结果输出,后端和前端要如何配合?后端要使用什么技术实现流式输出呢…...