unity随机生成未知符号教程

article/2025/7/6 15:05:32

目录

  • 前言
  • 方法1
  • 方法2
  • 脚本
  • 后言
  • 示例代码

前言

在某些游戏中,有一些让人感到意味不明的未知符号,例如在游戏《巴别塔圣歌》中,就有这样一些能让人在初次就看不懂的未知符号。

在这里插入图片描述

或者在其他时候,这些未知符号如果跟粒子系统结合在一起的话,也可以当作是一种特效,可以增加游戏的神秘感。

而现在,如果你想学的话,那么现在就可以开始学了。

方法1

首先讲最简单的方法,最简单的就先随机地显示Wingdings字体的字符,然后在随机显示字符后等待一小会即可,这个对于很多人来说都容易去理解,但是,这个方法主要的难点是如何将TextMeshPro中的字体设为Wingdings字体,因此,接下来就要详细的讲一下如何更改TextMeshPro组件的字体。

  1. 打开文件资源管理器;

  2. 转到C:\Windows\Fonts,选取里面的Wingdings 常规

  1. Wingdings 常规拖到unity的项目栏里,并右键选中拖过来的字体,创建TextMeshPro的Wingdings字体资产。

  1. 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方法内让ab各自增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();
}

之后定义一个Vector3paths可变数组,一个有8个boolcanMove数组,和一个有8个intmodeMove数组,初始化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+bdotMove数组,如果dotMove数组全是真,那么等于“笔”移到了第 1 ∼ a 1\sim a 1a列的所有点和第 1 ∼ b 1\sim b 1b行的所有点了。就需要一个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进行运算,从而得到posdots二维数组中的坐标,就可以设置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 ab1内的随机值,这代表了“笔”的位置,并将这个位置传到paths数组里,作为方法2中符号的起点。再接着,我们就设置“笔”要移动的方向。

“笔”方向有8种,“↖↑↗←→↙↓↘”这些全都是(分别代表了0~7的数字,这以后会用到)。因此,刚才定义的canMovemodeMove数组大小都为8个,并且,假设有一个方向 x x x,因为 x + x 反 = 7 x+x_反=7 x+x=7,那么它的反方向就是 7 − x 7-x 7x,因此,刚才就将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());
}

做到这里,还有几个问题没有解决。

  1. 变量ab不能为0,space不能为0。

解决方法:只需要在Start方法一开始判断abspace为0即可,如果条件达成,就将它们设为默认值。

void Start()
{a = (0 == a ? 2 : a + 1);b = (0 == a ? 3 : b + 1);space = (0 == space ? 0.809f : space);summon();
}
  1. 有时对象并没有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


http://www.hkcw.cn/article/BMAYMlettR.shtml

相关文章

OpenCV——Mac系统搭建OpenCV的Java环境

这里写目录标题 一、源码编译安装1.1、下载源码包1.2、cmake安装1.3、java配置1.4、测试 二、Maven引入2.1、添加Maven依赖2.2、加载本地库 一、源码编译安装 1.1、下载源码包 官网下载opencv包&#xff1a;https://opencv.org/releases/ 以4.6.0为例&#xff0c;下载解压后&…

从Docker拉取镜像一直失败超时解决办法

项目场景&#xff1a; 在ubuntu中&#xff0c;使用docker拉去镜像时&#xff0c;一直超时&#xff0c;拉去失败。 问题描述 原因分析&#xff1a; 国外服务器网络不好导致。 解决方案&#xff1a; 解决方案1 设置国内源 我这边测试&#xff0c;更改以后仍然失败 阿里云提供…

告别printf!嵌入式系统高效日志记录方案

目录 1、分级控制与动态过滤机制 2、异步处理与零拷贝架构 3、跨平台适配层设计 在嵌入式系统开发领域&#xff0c;日志记录系统如同数字世界的黑匣子&#xff0c;承载着系统运行状态的关键信息。传统的printf调试方式虽简单易用&#xff0c;但在处理复杂系统时暴露出效率低…

复变函数 $w = z^2$ 的映射图像演示

复变函数 w z 2 w z^2 wz2 的映射图像演示 复变函数 w z 2 w z^2 wz2 是一个基本的二次函数&#xff0c;在复平面上具有有趣的映射性质。下面我将介绍这个函数的映射特性&#xff0c;并使用MATLAB进行可视化演示。 映射特性 极坐标表示&#xff1a;若 z r e i θ z …

【Redis】Zset 有序集合

文章目录 常用命令zaddzcardzcountzrange && zrevrangezrangebyscorezpopmax && bzpopmaxzpopmin && zpopmaxzrank && zrevrankzscorezremzremrangebyrankzremrangebyscorezincrby 集合间操作交集 zinterstore并集 zunionstore 内部编码应用场…

【AI论文】视觉语言模型中的自我修正推理

摘要&#xff1a;推理视觉语言模型&#xff08;VLMs&#xff09;在复杂的多模态任务上表现出了良好的性能。 然而&#xff0c;它们仍然面临着重大挑战&#xff1a;它们对推理错误高度敏感&#xff0c;需要大量带注释的数据或精确的验证器&#xff0c;并且难以在特定领域之外进行…

正则表达式在Java中的应用(补充)

正则表达式在Java中的应用 Java通过java.util.regex包提供正则表达式支持&#xff0c;核心类包括Pattern和Matcher。Pattern用于编译正则表达式模式&#xff0c;Matcher用于匹配操作。基本语法遵循标准正则规则&#xff0c;如\d匹配数字&#xff0c;\w匹配单词字符。 Pattern…

C++ 内存泄漏检测器设计

文章目录 1. C中的动态内存分配2. 什么是内存泄漏3. 内存泄漏的代码案例4. 内存泄漏检查器的设计模块1&#xff1a;位置信息捕获&#xff1a;模块2&#xff1a;内存分配跟踪&#xff1a;模块3&#xff1a;内存释放跟踪&#xff1a;模块4&#xff1a;泄漏记录存储&#xff1a;模…

线程安全与线程池

概念&#xff1a;多个线程&#xff0c;同时操作同一个共享资源的时候&#xff0c;可能会出现业务安全问题。 出现线程安全问题的条件&#xff0c;原因&#xff1a;1.存在多个线程在同时执行 2.同时访问一个共享资源 3.存在修改该共享资源 线程同步&#xff1a;是线程安全…

网络安全的学习路线是怎么样的?

我是几乎完全自学的&#xff0c;十年前从双非跨专业考研到中科大软件学院网络安全专业&#xff0c;读研之前&#xff0c;C语言是自学的&#xff0c;数据结构是自学的&#xff0c;计算机网络是自学的&#xff0c;操作系统是自学的&#xff0c;微机原理是自学的。为了让我们能跟上…

每日算法-250602

每日算法学习记录 - 250602 今天学习和复习了两道利用前缀和与哈希表解决的子数组问题&#xff0c;特此记录。 560. 和为 K 的子数组 题目 思路 本题的核心思想是利用 前缀和 与 哈希表 来优化查找过程。 解题过程 题目要求统计和为 k 的子数组个数。 我们首先预处理出一…

Hadoop学习笔记

&#xff08;1&#xff09;Hadoop概述 Hadoop是一个开源的分布式计算和存储框架&#xff0c;用于处理大规模数据集&#xff08;大数据&#xff09;的并行处理。它由Apache基金会开发&#xff0c;核心设计灵感来自Google的MapReduce和Google文件系统&#xff08;GFS&#xff09…

PCIe—TS1/TS2 之Polling.Configuration (二)

前文 在 Polling.Configuration 次状态中&#xff0c;发送⽅停⽌发送 TS1 序列&#xff0c;转⽽发送 TS2 序列&#xff0c;TS2 序列中的链路和通道&#xff08;lane&#xff09;字段仍然使⽤填充字段填充。 该状态中&#xff0c;发送⽅转⽽发送 TS2 的⽬的是通知链路对端的设备…

如何增加 cPanel中的 PHP 最大上传大小?

PHP通过限制文件上传大小来保护服务器性能&#xff0c;但默认限制对于许多现代网页应用来说太低了。当PHP应用程序显示错误信息&#xff0c;要求你增加PHP的最大上传文件大小时&#xff0c;你可能会遇到这个问题。有多种方法可以提高上传限制&#xff0c;包括直接编辑PHP配置文…

linux——文件系统

被打开的文件放到内存中没有被打开的文件放到磁盘 1. 硬件-->磁盘 磁盘的存储基本单位&#xff1a;扇区&#xff08;512字节&#xff09; 512字节写入到磁盘&#xff0c;磁盘如何转动&#xff1a; 磁盘写入的时候是向柱面进行批量写入的 CHS地址&#xff1a;cylind heade…

HBM的那些事2 写操作

搞懂写&#xff0c;把下面这幅图搞定&#xff0c;基本上就掌握了7成了。 术语解释 WL &#xff1a; write latency&#xff0c;说的是命令到发送数据的WDQS的间隔&#xff0c;注意这里不包含twpre1的时间&#xff0c;通过配置MR1实现。 twpre1: 在发送写数据之前&#xff0c;W…

B1039 PAT乙级JAVA题解 到底买不买

小红想买些珠子做一串自己喜欢的珠串。卖珠子的摊主有很多串五颜六色的珠串&#xff0c;但是不肯把任何一串拆散了卖。于是小红要你帮忙判断一下&#xff0c;某串珠子里是否包含了全部自己想要的珠子&#xff1f;如果是&#xff0c;那么告诉她有多少多余的珠子&#xff1b;如果…

力扣HOT100之多维动态规划:62. 不同路径

这道题用二维dp数组来做相当简单&#xff0c;是一道入门题。直接上动规五部曲&#xff1a; 1.确定dp[i][j]的含义&#xff1a;从起点到位置为[i][j]处的路径总数 2.确定递推公式 dp[i][j] dp[i - 1][j] dp[i][j - 1]; 3.dp数组初始化 dp[0][j] 1;dp[i][0] 1; 4.确定遍历顺序…

css呼吸灯

效果图 只是简单的呼吸效果&#xff0c;您按照需求自己拓展即可。 代码 keyframes light{from{opacity: 1;}to{opacity: 0.2;}}使用 .view{animation-name: light;animation-duration: 1s;animation-timing-function: linear;animation-iteration-count: infinite;animation-…

AI入门——AI大模型、深度学习、机器学习总结

以下是对AI深度学习、机器学习相关核心技术的总结与拓展&#xff0c;结合技术演进逻辑与前沿趋势&#xff0c;以全新视角呈现关键知识点 一、深度学习&#xff1a;从感知到认知的技术革命 核心突破&#xff1a;自动化特征工程的范式变革 深度学习通过多层神经网络架构&#x…