自由学习记录(18)
动画事件的碰撞器触发
Physics
类的常用方法
RaycastHit hit;
if (Physics.Raycast(origin, direction, out hit, maxDistance)) {Debug.Log("Hit: " + hit.collider.name);
}
Physics.Raycast
:从指定点向某个方向发射射线,检测是否与碰撞体相交。
Physics.RaycastAll
:发射射线并返回所有碰撞到的对象
Physics.IgnoreCollision
:忽略两个碰撞体之间的碰撞。
Physics.IgnoreCollision
方法可以用来忽略两个碰撞体之间的碰撞,但它并没有直接提供查看已忽略碰撞的功能。
如果你需要跟踪哪些碰撞体之间的碰撞被忽略,可以考虑手动维护一个列表或字典,用于记录哪些碰撞体之间的碰撞被忽略。你可以在调用 Physics.IgnoreCollision
时,将被忽略的碰撞体记录到这个列表中。
Dictionary<Collider, List<Collider>> ignoredCollisions = new Dictionary<Collider, List<Collider>>();void IgnoreCollision(Collider a, Collider b) {Physics.IgnoreCollision(a, b);if (!ignoredCollisions.ContainsKey(a)) {ignoredCollisions[a] = new List<Collider>();}ignoredCollisions[a].Add(b);
}
额外的写法,搭配元组 绑定两个碰撞体之间的关系值
Dictionary<(Collider, Collider), bool> ignoreds = new Dictionary<(Collider, Collider), bool>();void IgnoreCollision(Collider a, Collider b) {Physics.IgnoreCollision(a, b);ignoreds[(a, b)] = true; // 记录忽略的碰撞
}void LogIgnoreds() {foreach (var pair in ignoreds.Keys) {Debug.Log($"Ignored Collision: {pair.Item1.name} - {pair.Item2.name}");}
}
Dictionary<(Collider, Collider), bool> ignoredCollisions = new Dictionary<(Collider, Collider), bool>();// 记录忽略的碰撞
ignoredCollisions[(colliderA, colliderB)] = true;
Physics.gravity
:获取或设置全局重力向量,影响所有物体的重力效果。
只对于场景上附加了 Rigidbody
组件的物体,Physics.gravity
会直接影响它们的重力。默认情况下,Rigidbody
会根据这个全局重力向量施加重力。
Physics.DrawRay
:用于在场景视图中可视化射线,便于调试。
帮助你可视化射线,确保其正确指向目标
public static void DrawRay(Vector3 start, Vector3 direction, Color color = Color.white, float duration = 0f);
start (Vector3
):射线起点
direction (Vector3
):射线的方向,通常是一个单位向量
ps:Physics.DrawRay
实际上并没有直接提供长度参数,它只需要起点和方向向量。
要使用射线的长度,你通常需要将方向向量再乘以要的长度,然后计算出终点。
color (Color
):射线的颜色,默认是白色。
Debug.DrawLine
可以绘制从 start
到 end
的线,两者是有些区别的
Debug.DrawRay(start, direction, Color.red);
Physics.OverlapSphere
Collider[] Physics.OverlapSphere(Vector3 position, float radius, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);
返回一个 Collider
数组,包含所有在指定位置和半径内的碰撞体。
position (Vector3
):球体中心的位置,表示检测的起始点。
radius (float
):球体的半径,决定了检测的范围。
layerMask (int
):可选参数,指定哪些层的碰撞体将被检测。默认为所有层。通过位掩码可以更精确地选择层。
queryTriggerInteraction (QueryTriggerInteraction
):可选参数,指定是否检测触发器(Trigger)。可以选择以下值:
QueryTriggerInteraction.UseGlobal
:使用全局设置。QueryTriggerInteraction.Ignore
:忽略触发器。QueryTriggerInteraction.Collide
:包括触发器。
void Update() {// 定义球体中心和半径Vector3 sphereCenter = transform.position;float sphereRadius = 5f;// 获取在范围内的碰撞体Collider[] hitColliders = Physics.OverlapSphere(sphereCenter, sphereRadius);// 遍历所有碰撞体foreach (Collider collider in hitColliders) {// 输出碰撞体的名称Debug.Log("Detected: " + collider.name);}
}
拾取物品、感知范围、区域触发事件
摄像机移动的四元数
只传入一个方向向量给 Quaternion.LookRotation
时,它会默认使用世界坐标系的 Y 轴(即上方向)作为“上”方向。
如果你希望更好地控制对象的朝向和倾斜,可以传入第二个参数,指定一个自定义的上方向
Vector3 direction = new Vector3(1, 0, 0);
Vector3 up = Vector3.up; // 指定上方向为 Y 轴正方向
Quaternion targetRotation = Quaternion.LookRotation(direction, up);
意思是第一个向量确定xz面,上方向再加上y的确认,达成四元数
摄像机的跟随
游戏资源的关系梳理
写代码的时候更带一点编程人员的角度,可拓展性有时也会提高,比如对血条的控制,在这里,maxhp也同样加入了可以控制的范围,看上去多传入了一个参数可能会麻烦一点,不够简化,
但是多传入一个参数的性能消耗其实并不高,如果考虑到游戏制作流程的人力资源分配,则是小巫见大巫
细节之处的地方没有必要那么省性能,影响开发速度
对于做一个流程的游戏,如果过多把写了的东西揉成一团丢一边,然后重写,追求更好的写法,这样也不利于写联通的逻辑。
需要实现功能时,减少性能或优雅追求的妥协点,毕竟需要的功能之后再加上也是可以的,不需要的功能后面要砍也是可以的,而同一个功能的反复修改,可能会有一些得不偿失
gizmo如果没有打开,看不到寻路烘焙
需要注意的是,在unity开发中的“资源自带区”,完全不仅仅是只能看做对资源的提供,还有对变化数据资源的提供再提供,意思是同样的一份数据,可以仅仅是一存一拿,也可以是存入,被其他的拿去计算后,再拿回,
如装备的数据,但这只是很浅一部分,里面记录了很多游戏内容相关的东西,然后这些“游戏内容承载体”可让玩家的可操作数据因此发生二次变化,一种不属于物理操作本身的额外游戏内容数据变化
ps:物理操作本身给出的变化,称为一次变化,这种变化是固定的,与游戏额外添加内容无关的
将资源区的数据分为游戏本身自带的“资源自带区”,和玩家操作产生变化的区域
玩家操作产生变化的区域,
再分成如音乐大小设置,画质帧率设置,操作界面调整等偏后台类数据记录
和玩家操作过程中时常变动的数据,比如血量等级,经验值,装备穿戴情况(装备情况由 “资源自带区”提供,参与计算并给定最终对角色的影响)
资源的使用和游戏物体的预设使用,资源是直接可以套上组件,游戏对象的使用是对资源区的物体,执行实例化的方法
物体的删除和创建没有想象的那么耗性能,并不是说可以完全不要去注意,只是不要放过多权重在上面
SQL视图和索引
MySQL 视图(View)是一个虚拟表,它是基于 SQL 查询的结果集。视图并不存储数据本身,而是存储了一个 SQL 查询的定义。
CREATE VIEW order_summary AS
SELECT order_id,customer_id,order_date,total_amount
FROM orders;
现在,可以简单地查询视图,SELECT * FROM order_summary;
视图可以将复杂的查询逻辑封装在一个简单的结构中。这样,你可以用一个简单的 SELECT 语句来替代复杂的 SQL 查询,降低了使用的复杂性。
视图可以被设计为可更新的,例如,如果你有一个简单的视图只选择了单个表的所有列,那么你可以通过视图进行数据更新,并且更新会直接影响基础表的对应记录。
UPDATE order_summary SET total_amount = 150.00 WHERE order_id = 1;
使用视图可以限制用户的访问权限。例如,如果你希望用户只能访问订单的摘要信息而不允许访问原始表中的其他敏感信息,可以创建一个视图,只包含所需的字段
非聚集索引是一种用于提高数据库查询性能的重要工具。它通过创建独立的索引结构,使得对表中特定列的查询更加高效。
如果没有索引,数据库需要扫描整个表以找到匹配的行;而有了 idx_department
索引后,查询会更快,因为数据库可以直接访问相关的索引数据。
SELECT * FROM employees WHERE department = 'Sales' AND salary > 50000;
如果 id
是主键,它会自动成为聚集索引。
父子预设体的问题
UI的子物体的预设体设置
Image 的 RectTransform 会记录其相对于 Canvas 的位置、锚点、大小等信息。当你在 Canvas 下创建 Image 时,这些属性都是相对于该 Canvas 的。
如果将 Image 预设体拖放到不同大小的 Canvas 上,由于其属性是相对原始 Canvas 的,所以会出现问题
位置偏移:由于不同 Canvas 的尺寸和锚点设置,Image 可能不会在新 Canvas 中显示在预期的位置。
缩放问题:如果原始 Canvas 和目标 Canvas 的缩放比例不同,Image 的大小和显示效果可能也会受到影响。
正常 的3d父子物体,子物体设置成预设体也是记录相对父物体的信息
子物体的 Transform 会记录相对于父物体的位置信息(localPosition)、旋转信息(localRotation)和缩放信息(localScale)。这意味着无论父物体的位置和旋转如何变化,子物体的相对位置和旋转关系保持不变。
如果没有父物体,则默认把这些相对的值赋到世界坐标系上
相对值:没有父物体的情况下,GameObject 的 localPosition
、localRotation
和 localScale
的值会直接对应于它的 position
、rotation
和 scale
。这意味着:
localPosition
等于position
localRotation
等于rotation
localScale
等于scale
当你将一个没有父物体的 GameObject 作为预设体存储并实例化时,它将出现在场景中的确切位置(相对于世界坐标系),并且其 Transform 信息不会受到其他物体的影响。
动画设置总结
串面板的实现,一定会存在初逻辑做的差不多之后发现有小问题没有统一的解决,
对于这种做的快完的时候发生的优化问题,如果想要完全避免的话,
思考成本很高,而且自己的功能实现能力也许会受限
而且一般来讲,这种问题都是边边角角的,如果需要额外加也是可以的
状态机的override版本一定是有用的,给的资源,角色拿着不同武器的移动方式,攻击方式是可归类的,
状态机合理利用override的话,应该说是对角色所有动作的构成和融合的归类,因为有blend tree
移动相关的设置可以更加概括成一个状态,
向前,后,左,右四个动作,构成一个blend tree 进行融合,并且用animator的参数管控blend的2d融合参数,
然后攻击动画只影响上半身,于是利用了遮罩的设置,先建立新的动画层,权重拉高,然后把下半身全部mask,触发开火的时候就可以只变化上半身,但这个新层要注意做一个空状态,不然有点没起点的感觉
对于下蹲,则是又开一层,但这一层开启sync同步,并贴在移动的基层上
之后通过new Layer的权重增大,从而达到让角色下蹲的样子
状态机的设置,可以在内部实现把移动的代码相关调控问题直接解决,给外部仅仅提供一个x和y值和触发的状态,就可以达成预期效果
Animator状态机的要点
层的同步
层的权重设置
层的遮罩不处理
层的参数外提供
状态的连接建立
参数对状态切换的调控
子状态机
右击子状态机或其他状态,选择 "Make Transition" 来创建过渡。
进入子状态机后,会进行独立的状态逻辑判断。子状态机内部可以有自己的状态、过渡和条件,这些都是独立于主状态机的。
可以把子状态机当成状态机的递归,在最上层的状态结构里,子状态机就是一个正常节点,但是如果过渡到该节点之后,就会变成在该子状态机了进行全新的条件判断
摄像机的动画设置
准确来说,有时候代码简化反而可能不如不简化直接使用,比如这里,很直接的把动画播放结束的事件分割成了一个只写了一点点代码的函数,看上去的确是可以简化,反正需要的效果也不多
但如果要简化,很容易把函数结束的一种逻辑潜意识也混入了左转右转的两个动画里,这对于保持逻辑清晰来说,简化后并不一定真的有简化,也许现在看不出什么问题,但有些问题会自然的带到后面对功能的开发
这里更像是动态添加事件函数,每次点击传入这段函数,然后转到动画事件部分,通过将传过来的时间,丢入一个事件变量,然后由PlayOver统一执行这个事件
这样的好处,首先的确是很清爽,如果想自己换法子实现,就要比较复杂的实现延时执行面板的显隐。
动画事件串联全程
添加之后会去脚本里面找
这个函数是写在挂在CameraAnimator这个自定义的脚本上的
动画事件那一块是可以检测到并使用的
动画完成之后要做什么操作,这里是设置了私有变量,以达到外部传入操作到Camera,Camera可以执行该操作
最后就是给外部调用的两个turn的函数,外部尽管传入操作,Camera内部会接收,先执行转向的动画,animator.SetTrigger("具体的对应状态");
然后Animatior就会进入动画的播放,而左转右转这两个自己编辑出来的动画,也对应的在播放结束的位置加上了动画事件,则是PlayOver
而此时,由于触发时间的不同,点击左转时,调用了左转的函数,
先是触发了左转动画的播放,然后立刻给动画播放完成之后 那个存储动画事件的变量添加了要执行的操作,等到旋转动画播放完,就执行那个存储的PlayOver函数,执行完之后再置空保证优雅
Animation Event
public void PlaySound(float volume)
{Debug.Log($"Playing sound at volume: {volume}");
}
挂载到该 GameObject 的 MonoBehaviour 脚本中定义。被调用的函数必须是 public
的。
Animation Event 中,还可以用带参数的函数,难免就会有疑惑,因为方法是写成这样,而调用传参的权利不在自己而在Animation event上。
参数值是由你在 Animation Event 的设置面板中直接定义的,在参数字段中,输入你想要传递给 volume
的具体值,比如 1.0
。这就是你在 Animation Event 中设置的参数值,是你当场定义当场用的感觉,
参数并不是自动从其他地方传递的,而是通过你在 Animation Event 中配置的内容直接给定的。。
背景音乐设置
使用UImanager来管理面板的显隐
GameDataMgr来统一管理数据的存储
音乐脚本设置为单例,强调只需要一个来管理就够了
节约性能,虽然实时在改变拖动的值,但是并没有存在musicdata里面,在点击叉之后再一次性存入Gamedatamgr
每次滑动都直接修改音量上的值,和游戏数据管理类里的直接值,那这里的SaveMusicData
意味着存入json?是的,毕竟内存和硬盘看似很接近,实则天差地别,两个完全不属于一个世界
从硬盘里通过json读过来的数据,到了内存里就和之前毫无联系了,
只有内存呼唤json,建立联系,才能把内存的数据再输入给硬盘
对于背景音乐,设置一个场景上的对象,再挂载对应的脚本,管理上面的各种声音
数据管理类的单例,首次调用时引发构造函数,构造函数中导入json数据
而音乐对象身上的awake里,则调用游戏管理数据类获取音乐设置数据
Life is an absurd art.
相关文章:

自由学习记录(18)
动画事件的碰撞器触发 Physics 类的常用方法 RaycastHit hit; if (Physics.Raycast(origin, direction, out hit, maxDistance)) {Debug.Log("Hit: " hit.collider.name); } Physics.Raycast:从指定点向某个方向发射射线,检测是否与碰撞体…...

vue3-ref 和 reactive
文章目录 vue3 中 ref 和 reactivereactive 与 ref 不同之处ref 处理复杂类型ref在dom中的应用 vue3 中 ref 和 reactive ref原理 基本原理 ref是Vue 3中用于创建响应式数据的一个函数。它的基本原理是通过Object.defineProperty()(在JavaScript的规范中用于定义对…...

Apache Calcite - 查询优化之自定义优化规则
RelOptRule简介 为了自定义优化规则,我们需要继承RelOptRule类。org.apache.calcite.plan.RelOptRule 是 Apache Calcite 中的一个抽象类,用于定义优化规则。优化规则是用于匹配查询计划中的特定模式,并将其转换为更优化的形式的逻辑。通过继…...

大型语言模型(LLM)的小型化研究进展
2024年,大型语言模型(LLM)的小型化研究取得了显著进展,主要采用以下几种方法实现: 模型融合:通过将多个模型或检查点合并为一个单一模型,减少资源消耗并提升整体性能。例如,《WARM: …...

MiniWord
1.nuget 下载配置 2.引用 3. var value = new Dictionary<string, object>() { ["nianfen"] = nianfen, ["yuefen"] = yuefen, ["yuefenjian1"] = (int.Par…...

Netty 常见组件介绍
Netty 常见组件介绍 上篇文章Netty入门程序echo 基本包含了Netty常见的组件,本文分别介绍各个组件 Bootstrap or ServerBootstrapEventLoopEventLoopGroupChannelPipelineChannelFuture or ChannelFutureChannelInitializerChannelHandler Bootstrap vs ServerBo…...

高频电子线路---倍频器与振荡器
目录 倍频电路原理 丙类倍频器原理电路 问题: 提升滤波方法: 导通角 振荡器 振荡器基本工作原理 首先是怎么维持 那么如何振荡呢? 思考题: 组成要素 振荡器的起振条件 平衡条件 要点提示 稳定条件 振幅平衡 硬激励起振时: 稳定条件 相位平衡 倍频电路原理 简单原理 : …...

删除 git submodule
直接运行下面命令即可: git rm <path-to-submodule>然后提交修改即可。 但是,还有一个小问题:上面命令只是将 submodule 的代码目录删除了。 以下痕迹还存在你的仓库中: .gitmodule 中关于该 submodule 的信息.git 目录…...

el-table 多选默认选中(根据返回的id给数据加默认选中状态)
前言 el-table是我们最常用的展示数据的方式,但是有时候需要用到多选来选择数据,新增数据的时候还好,选中状态都是正常的,但是修改就遇到问题,需要对这个已经选择过的数据加上默认的选中状态,本次就是解决…...

境外网站翻译之自由职业
Polls Do you use AI tools (e.g ChatGPT, Midjourney, Github Copilot) as part of your work? 你在工作中会使用人工智能工具(如 ChatGPT、Midjourney、Github Copilot)吗? Yes, as an assistant 是的,作为一种辅助工具。 Y…...

批量图片转PDF文件的多种方法详解
要将批量图片转换为PDF文件,可以使用多种方法,包括使用在线工具、桌面应用程序或编程语言。以下是几种常见的方法: 方法一:使用在线工具 选择工具:搜索“图片转PDF”在线工具,如 Smallpdf、ILovePDF 等。…...

Web服务器(理论)
目录 Web服务器www简介常见Web服务程序介绍:服务器主机主要数据浏览器 网址及HTTP简介URLhttp请求方法:2.3 HTTP协议请求的工作流程: www服务器的类型静态网站动态网站 快速安装Apache安装准备工作httpd所需目录主配置文件 nignx安装1、安装2、准备工作 …...

js:()=>(,);()的作用:明确表达式的边界。
()>{表达式1;表达式2;表达式3;... return 结果} 等同于 ()>(表达式1,表达式2,表达式3,... 结果) 例子: const strarr [a, b, c];const result strarr.reduce((acc, curr) > {(acc[curr] 1);console.lo…...

RSI 5G通信技术中用于标识小区的特定参数
RSI是指在5G通信技术中用于标识小区的特定参数,全称为Radio Subframe Indicator(无线子帧指示符)。在原文的上下文中,RSI被用来确保相邻小区间有足够的间隔,避免由于RSI冲突导致用户设备(UE)随机…...

JavaScript中的闭包、递归问题
一、函数定义和调用 1.函数的定义方式 方式一 函数声明方式 function 关键字(命名函数) function fn(){}方式二 函数表达式(匿名函数) var fn function(){}方式三 new Function() var f new Function(a,b,console.log(a b););//语法 var fn new Fu…...

【青牛科技】GC4938替代A4938/Allegro在水泵、筋膜枪、吸尘器和电动工具中的应用
随着技术的不断进步,电机驱动控制器在各类电动设备中的应用越来越广泛。GC4938作为一种新型的电机驱动控制器,逐渐被视为A4938/Allegro的替代品。在这篇文章中,我们将探讨GC4938在水泵、筋膜枪、吸尘器和电动工具等设备中的应用优势和特点。 …...

基于yolov5的输电线,电缆检测系统,支持图像检测,视频检测和实时摄像检测功能(pytorch框架,python源码)
更多目标检测和图像分类识别项目可看我主页其他文章 功能演示: yolov5,输电线(线缆)检测系统,系统既支持图像检测,也支持视频和摄像实时检测【pytorch框架】_哔哩哔哩_bilibili (一)简介 基于yolov5的输…...

uniapp下载文件的方案,包括H5,App方案解决办法
1. 在uniapp需要下载文件,但是显示情况是不能下载。所以只能使用该办法来进行下载。 2. 这有一个注意点是:如果你做的是H5的方案,那么我已经替你踩好坑了,UC浏览器是不支持blob类型的下载,以及创建a标签的方案来进行下…...

c++ 贪心算法
概念 贪心算法是一种在每一步选择中都选择当前最优解的算法策略。这种方法适用于某些特定问题,可以通过局部最优选择构建全局最优解。 特点 局部最优选择:每一步选择都选择当前看起来最优的解。无后效性:当前选择不会影响未来选择的可能性…...

15分钟学 Go 第 35 天:Go的性能调优 (7000字详细教程)
第35天:Go的性能调优 目标:理解Go语言中基本的性能优化,学习如何分析和提高Go程序的执行效率。 一、性能调优概述 性能调优是软件开发中的一个重要环节,它可以确保程序在资源有限的环境下高效运行。Go语言天生具备高效的性能表现…...

6、显卡品牌分类介绍:技嘉 - 计算机硬件品牌系列文章
技嘉科技是一家以主板、显卡在业界缔造无以撼动的地位的科技公司,其核心理念是「技术创新、质量稳定」的高标准。技嘉专注于关键技术研发,其经营范围涵盖家用、商用、电竞等多元科技领域。通过应用突破性的专利技术,技…...

Redis数据类型——针对实习面试
目录 Redis数据类型Redis常用的数据类型有哪些?String类型可以用于哪些场景?Set类型可以用于哪些场景?Bitmaps类型可以用于哪些场景?HyperLogLog类型可以用于哪些场景?Hash类型与Set类型有什么区别?Hash类型…...

roberta融合模型创新中文新闻文本标题分类
项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…...

《密码系统设计》实验二 4-6学时
文章目录 《密码系统设计》实验实验项目实验二 密码算法实现4-6 学时实践要求(30 分)1. 定义宏2. 使用特定的源文件3. 编译MIRACL库4. 配置KCM和Comba方法5. 编译和运行MEX工具6. 使用config.c工具总结1. 准备环境2. 下载和解压MIRACL库3. 定义宏4. 使用…...

Zypher Network:全栈式 Web3 游戏引擎,服务器抽象叙事的引领者
近期,《黑神话:悟空》的爆火不仅让 AAA 游戏重回焦点,也引发了玩家与开发者的热议。Web2 游戏的持续成功导致部分 Web3 玩家们的倒戈,对比之下 Web3 游戏存在生命周期短且商业模式难以明确的问题,尤其在当前加密市场环…...

2025生物发酵展(济南)为生物制造产业注入新活力共谱行业新篇章
2025第十四届国际生物发酵展将于3月3-5日济南盛大举办!产业链逐步完整,展会面积再创历史新高,展览面积较上届增涨至60000平方米,专业观众40000,品牌展商800,同期活动会议增加至50场,展会同期将举…...

git入门教程14:Git与其他工具的集成
一、Git与代码托管平台的集成 GitHub 集成方式: 在GitHub上创建或克隆仓库。在本地使用Git命令进行代码提交和推送(如git push)。GitHub提供Web界面进行代码浏览、协作和持续集成配置。 特点: 支持Pull Request,便于代…...

在Zetero中调用腾讯云API的输入密钥的问题
也是使用了Translate插件了,但是需要调用腾讯云翻译,一直没成功。 第一步就是,按照这上面方法做:百度、阿里、腾讯、有道各平台翻译API申请教程 之后就是:Zotero PDF translat翻译:申请腾讯翻译接口 主要是…...

【AD】1-8 AD24软件工程创建
1.点击文件,新建项目 2.如图进行设置工程名称和文件路径 3.创建原理图库及原理图,并保存 4.新建PCB库及PCB,并保存 5.单击右键工程保存 注意:先新建工程,在新建文件...

RT-Thread学习
文章目录 前言一、rtt的启动流程二、移植工作总结 前言 RT-Thread学习,这里记录对bsp的移植 一、rtt的启动流程 RT-Thread 支持多种平台和多种编译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一启动入口。一般执行顺序是:系统先从…...