同步日记

This commit is contained in:
zzz
2025-03-18 17:44:46 +08:00
parent 8e9e13563d
commit d6ef4c901d
24 changed files with 892 additions and 119 deletions

View File

@@ -1,20 +1,31 @@
[
"file-explorer",
"global-search",
"switcher",
"graph",
"backlink",
"canvas",
"outgoing-link",
"tag-pane",
"page-preview",
"daily-notes",
"templates",
"note-composer",
"command-palette",
"editor-status",
"bookmarks",
"outline",
"word-count",
"file-recovery"
]
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"starred": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": false,
"properties": false,
"bookmarks": true
}

View File

@@ -13,6 +13,13 @@
"a": 1,
"rgb": 14701138
}
},
{
"query": "path:资源 ",
"color": {
"a": 1,
"rgb": 14725458
}
}
],
"collapse-display": false,
@@ -25,6 +32,6 @@
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 0.7132754626224436,
"scale": 0.5087618855792605,
"close": false
}

View File

@@ -8,29 +8,20 @@
"type": "tabs",
"children": [
{
"id": "e26bcf9583f0e0fa",
"type": "leaf",
"pinned": true,
"state": {
"type": "graph",
"state": {},
"pinned": true
}
},
{
"id": "45882341e179f5f2",
"id": "4e6788fa2bacf67e",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "2024-04-10.md",
"file": "编辑器/SerializedObject.md",
"mode": "source",
"source": false
}
},
"icon": "lucide-file",
"title": "SerializedObject"
}
}
],
"currentTab": 1
]
}
],
"direction": "vertical"
@@ -50,7 +41,9 @@
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical"
}
},
"icon": "lucide-folder-closed",
"title": "文件列表"
}
},
{
@@ -65,7 +58,9 @@
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
}
},
"icon": "lucide-search",
"title": "搜索"
}
},
{
@@ -73,7 +68,9 @@
"type": "leaf",
"state": {
"type": "starred",
"state": {}
"state": {},
"icon": "lucide-file",
"title": "插件不再活动"
}
},
{
@@ -81,7 +78,9 @@
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {}
"state": {},
"icon": "lucide-bookmark",
"title": "书签"
}
}
]
@@ -104,7 +103,7 @@
"state": {
"type": "backlink",
"state": {
"file": "2024-04-10.md",
"file": "地图编辑器/RoadMap.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
@@ -112,7 +111,9 @@
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
}
},
"icon": "links-coming-in",
"title": "RoadMap 的反向链接列表"
}
},
{
@@ -120,7 +121,9 @@
"type": "leaf",
"state": {
"type": "calendar",
"state": {}
"state": {},
"icon": "calendar-with-checkmark",
"title": "Calendar"
}
},
{
@@ -129,10 +132,12 @@
"state": {
"type": "outgoing-link",
"state": {
"file": "2024-04-10.md",
"file": "地图编辑器/RoadMap.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
}
},
"icon": "links-going-out",
"title": "RoadMap 的出链列表"
}
},
{
@@ -143,7 +148,9 @@
"state": {
"sortOrder": "frequency",
"useHierarchy": true
}
},
"icon": "lucide-tags",
"title": "标签"
}
},
{
@@ -152,8 +159,10 @@
"state": {
"type": "outline",
"state": {
"file": "2024-04-10.md"
}
"file": "地图编辑器/RoadMap.md"
},
"icon": "lucide-list",
"title": "RoadMap 的大纲"
}
},
{
@@ -161,7 +170,9 @@
"type": "leaf",
"state": {
"type": "git-view",
"state": {}
"state": {},
"icon": "git-pull-request",
"title": "Source Control"
}
},
{
@@ -169,7 +180,9 @@
"type": "leaf",
"state": {
"type": "git-history-view",
"state": {}
"state": {},
"icon": "history",
"title": "History"
}
}
],
@@ -190,52 +203,51 @@
"command-palette:打开命令面板": false
}
},
"active": "45882341e179f5f2",
"active": "4e6788fa2bacf67e",
"lastOpenFiles": [
"编辑器/SearchFilter UnityEditor筛选器.md",
"并行计算/GPU/SIMT.md",
"并行计算/GPU/Compute Shader.md",
"性能优化/批量渲染 数字UI.md",
"性能优化/关于Unity加载优化你可能遇到这些问题 - 知乎.md",
"程序集.md",
"2024-04-10.md",
"2024-03-19.md",
"链接.md",
"TODO.md",
"未命名.md",
"渲染/GPU/Pasted image 20230413163234.png",
"渲染/GPU/GPU渲染流程.md",
"性能优化/Batch & DrawCall.md",
"网络同步.md",
"Batch & DrawCall.md",
"conflict-files-obsidian-git.md",
"渲染/软渲染/冯 高光.md",
"渲染/软渲染",
"渲染/软渲染/还未实现.md",
"待办事项/TODO.md",
"渲染/一些渲染效果/Unity可交互雪地渲染Part5-雪地闪光及SSS.md",
"渲染/一些渲染效果",
"算法/TopK 问题.md",
"并行计算/CPU/SIMD(单指令多数据).md",
"编辑器/SerializedObject.md",
"Mesh/Mesh Renderer 与 Skinned Mesh Renderer.md",
"Mesh/Mesh Baker.md",
"Mesh/图片/Pasted image 20221021171104.png",
"log_learn/SkillConfig.md",
"战斗/还需要做的事.md",
"log_learn/shader入门精要.md",
"渲染/GPU/Pasted image 20230413163234.png",
"渲染/GPU/GPU渲染流程.md",
"战斗/技能/SkillBase.md",
"战斗/战斗系统 - 3C相关.md",
"战斗/游戏知识学习——【战斗系统】.md",
"战斗/动作.md",
"性能优化",
"地图编辑器/RoadMap.md",
"地图编辑器/复盘.md",
"地图编辑器",
"资源/打包",
"资源",
"UniTask与State对比",
"Unity 技术美术Trick",
"算法",
"渲染/软渲染",
"渲染/软渲染/图片/Pasted image 20230613102109.png",
"渲染/软渲染/图片",
"2023-07-26.md",
"2023-06-26.md",
"渲染/软渲染/课程.md",
"软渲染器/OpenGL.md",
"渲染/软渲染/视口剔除.md",
"渲染/软渲染/视锥剔除.md",
"渲染/软渲染/透视矫正.md",
"并行计算/CPU/Brust.md",
"并行计算/CPU/SIMD(单指令多数据).md",
"Issue/超出ScrollView的特效渲染层级不对.md",
"FairyGui/工作流.md",
"FairyGui",
"未命名.canvas",
"未命名 1.canvas",
"log_learn",
"渲染",
"渲染/GPU",
"并行计算/GPU",
"并行计算/GPU.canvas",
"并行计算/CPU",
"并行计算/CPU.canvas",
"未命名 2.canvas",
"并行计算",
"Issue",
"编辑器/图片/Pasted image 20221025121100.png"
]
}

View File

@@ -1 +0,0 @@
[原神渲染解析:分割视锥体以优化体积雾 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/687122372)

1
TODO.md Normal file
View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,12 @@
# 状态类
通过各种标志位来控制位移,旋转,状态,是否攻击。
攻击需要通过tick时间点来记录也需要通过标志位决定是否位移位移状态计算时间播放动画
# UniTask
不需要计算时间位移旋转可以自己写Wait来插值过去时间可控方法相当于状态可以Await。但是有可能没有Cancel导致一直处于这个状态内且不好Debug。
当外部Cancel状态时候内部状态处理较为复杂且不好写如何退出。
# 现在的问题
状态不该绑定动画,因为一个状态可能还包含开始进行中结束三个不同的动画。
所以状态是状态,动画是动画,不能混为一谈。
在一些for循环动画中造成切动画的时候会把其他的状态给Cancel导致逻辑出错。

View File

@@ -0,0 +1,5 @@
# 是否该与动作分开?
## 与动作分开后,有速度变化 或者 Blend融合如何处理
## 与动作分开后CTS的处理

View File

@@ -0,0 +1,17 @@
[[Update]]
选择Unitask
[[移动问题]]
# 死亡后表演
所有Handle都暂停开启死亡handle即可
2、玩家死亡后的Handle
代码手写战斗表演问题:
所有玩家都死亡后,如果暂停,
复活后,如果继续
fallback

View File

@@ -1,17 +0,0 @@
1、模型空间到切线空间的推导
精要如果一个变换中仅存在平移和旋转那么这个变换的逆矩阵就等于它的转置矩阵M = (M^-1)^T
https://www.jianshu.com/p/4d742fec15ca
2、切线空间的优势
--todo
3、渲染队列
在Background通道渲染背景 、 Geometry里渲染不透明 、 AlphaTest中渲染需要透明测试的
这三个通道都开启了深度测试和深度写入
建议Transparent中写关闭深度写入开启了透明混合的shader该通道还会按从后往前顺序渲染
Overlay渲染后处理
4、pass

View File

@@ -0,0 +1 @@
[关于Unity加载优化你可能遇到这些问题 - 知乎](https://zhuanlan.zhihu.com/p/23733044)

View File

@@ -0,0 +1,6 @@
[基于DOTS+DrawMeshInstancedIndirect的伤害数字渲染方案1实现思路 - 知乎](https://zhuanlan.zhihu.com/p/718118444)
[Unity3d HUD UI高性能方案 - 知乎](https://zhuanlan.zhihu.com/p/624580377)
[《重返帝国》HUD方案分析和实现 - 知乎](https://zhuanlan.zhihu.com/p/636610023)

5
战斗/动作.md Normal file
View File

@@ -0,0 +1,5 @@
用Tag标记的方法 标记出不能取消动作片段
状态机用在了用户施放技能的指示UI
不用状态机是因为并没有太多的因为切换了动作而导致输入输出的不同[[FAQ]]

View File

@@ -0,0 +1,378 @@
更新1:
*有一个很重要的点我忘记说了,就是游戏策略 -实际上在制作动作系统的时候要考虑兼容各种策略,**但是在调手感前, 要先想清楚自己的战斗策略**,所为战斗策略是指博弈方式,以及对玩家的操作进行约束,约束具体是指你需要的是一个黏糊糊的手感,还是一个干净利索的手感,而整个战斗博弈是什么样的, 如何保持有效博弈的同时,让玩家特别明确,例如剪刀石头布的方式?,或者是打地鼠? 亦或者是节奏游戏?或者搓招?
*关于战斗反馈 - 这一点是关于给玩家的信息的, 所有给玩家的信息绝对不能是单一的,例如被击,被击相关联的信息我之前看过一篇文章他们做了11种不同的反馈方向,保证玩家至少能接收到3-4种, 例如声音, 攻击特效,手柄震动, 屏幕效果, 动作反馈,环境反馈等等,这种信息量越多,玩家就越明确,这里还涉及到上一条战略策略,玩家游戏失败的原因归错到游戏的可能性也会更低
*关于业务感知能力 - 我想说其实大部分问题都是看做这个的game play有没有业务感知能力, 感知到一些细节还有问题, 这一块基本上靠策划是不行的,策划毕竟不能实现细节,而且很多时候还会提出错误的方向,这全靠gameplay去探索和补完, 所以gameplay是一个极其吃经验和爱的职位.如果你不是一个深爱你做的这个类型的game play 仅靠工程能力和一个靠谱的策划, 这个手感和细节一定达不到顶级.
---
首先3C(camera,control,character)是一个巨大的话题.
我对战斗系统本身非常有爱.
但是架不住不赚钱啊, 这年头手游当道,基本上仅仅是3C做的出色很难找到很好的工作.
运气好的是在我们那个独立游戏项目结束后有一段时间
而且加上我之前开发独立游戏很多时候被渲染相关的业务卡住,
于是就转型做技术向的TA, houdini大地形生成这个方向, 并且一边学习图形学,一边学习美术资产相关的东西.
图形学相关的东西也相当的迷人,我天生就喜欢复杂而且结构化的东西,感觉可以沉浸在图形学里好多年,如此说来人生也许一晃就过去了.
3C作为任何游戏的基础, 为了以后还有机会做动作类的游戏,也对之前经验的总结
我把所有的信息整合在这篇文章里,方便以后查阅,也分享给大家,希望得到更多的指点.
## 关于3C
关于3C我认为最重要的一件事是有爱
那么根据重要程度排序是这样的:
1.
2. 细节
3. 架构
爱决定了细节的数量和高度, 细节决定了质量, 架构决定你能不能开发一个能用的东西出来.
我想说其实大部分问题都是看你有没有业务感知能力, 感知到一些细节还有问题, 这一块基本上靠策划是不靠谱的,策划毕竟不能实现,所以gameplay是一个极其吃经验和爱的职位.如果你不是一个深爱你做的这个类型的game play 仅靠工程能力, 这个手感一定达不到顶级.
并且, 3C的camera是另外一个大坑,我用的Cinemachine,但是负责任的说,如果要追求好的3C相机必须自己做, 但是control和 character应该在一起做,我只做了后者也是对工程量的妥协,整个系统我从18年8月开始做, 期间得到很多大佬的指点和帮助例如 @我乱写的[1] 还有号称从不玩知乎的小白, 最后做到11月底,后来转向去研究渲染和houdini.
动作系统实际上就是一个ACT的核心,当然你拿他做RPG也没问题
大致分为美式和日式,
日式更多的是走的打击感,操作性
美式走的一般是真实感,而真实感需要大量的资源和黑科技加成,例如 motion matching
所以我的整个基础是基于日式的风格做的.
我认为整个日式动作游戏的3C水平 大致可以这么划分: 塞尔达 - 黑魂 - 只狼 - 鬼泣 or 猎天使魔女
当然这么分很不严谨, 这是我的认知
整体的导图如下:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpTZscsKy6SUvL92eMW5zWz5gQdRbkEjWmElLg8ZFU3au246apSoWWSQ/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)
我在最后会把思维导图的下载链接发出来,方便大家浏览.如果你对战斗系统很熟悉,可以直接跳过文章直接看思维导图会更方便和直观.更多的描述用于新接触战斗的萌新方便上手
我们分为几个大类描述:
- 可配置性 - 可配置性决定了这东西做出来是否能用, 如何配置一个怪物,配置一个角色, 配置一个boss
- 动力学和动画模块分开 - 这样处理能避免大部分的奇怪问题.并且在结构上更为方便维护
- 状态管理 - 状态管理对玩家的输入如何处理, 前摇中段后摇 如何处理, 这里我开始漏掉了,我朋友告诉我应该谢谢状态管理, 所以文章完成后扭头来写这个的时候其实我已经没劲了,最后写的实在是写的很崩溃,因为内容太多,每个地方都要想半天当时怎么做的,什么思路,还要对照代码, 如果这里有不明确的地方希望有兴趣的童靴给我留言, 这里我补充一点,unity的状态机不是很好用,如果有工程能力的同学,建议自己手动管理,仅仅用animation controller的混合树就好了,我就是这么做的
- 动作的细节处理 - 这是一些经验之谈
- IK的简单描述- 其实IK的应用就那么几个点,具体的功能点就自己摸索摸索吧
- 物理和动画的互相作用 - 这里是进一步提升的方式, 但是我并没有做物理相关的东西
- 黑科技 - 如果你想把3C往更深了做 这些方向可以考虑
## 可配置性1 - 角色模板
可配置性是一个框架是否可用的标准
所以我们放在第一个讨论, 这里关系到你的工程能力, 一般第一次做重构个3-4次太正常了
所以大家放心大胆的开发,后面多重构就好了,不用考虑一次性开发一个完美的系统.
如何考虑可配置性呢? 我们需要从业务出发,抽象出我们需要的类型
1 角色 - 怪物和玩家都属于角色的一种
2 角色需要动作 - 动作让角色动起来, 每个不同类型的角色可能需要不同的动画, 但是角色之间有没有共性?
3 如何播放? 事件和角色的关系, 这里还要考虑AI , 其他玩家操作输入,网络等
让我们进一步抽象
有没有可能有几种角色,长相差距很大,但是动作是类似的? 例如拿刀的骷髅兵 和 拿剑的人类士兵, 同时需要攻击动作,和 idle , 和 走跑
可能骷髅兵的攻击只有两下, 人类士兵会多一个跳劈
并且我们支持非空判断,如果特殊攻击时空,就无法触发
那么从动作组上我们这样分类这三个单位(骷髅兵 - 弓箭兵 - 人类士兵)
- 角色A - 关联动作(攻击, idle - 移动 - 特殊攻击)
- 角色B - 关联动作(远程攻击 , 移动)
再此之外,还要考虑什么事件可以触发,例如攻击就是攻击事件触发
可能特殊攻击需要一个 扳机状态 + 攻击触发,
那么基本上大思路就出来了,
我们需要一个模板A 角色模板,支持配置模型 动作组, 以及一些参数
还有每个动作相关联的事件, 这样的东西有较高的配置性.
我做了如下模板:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpWbmOvJX3o3D015nUEW9zAWrXzh4wgF5hSlyEX0jT2SfMkSjDYMGV7Q/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)
当然,你可以根据你的业务需求调整,
下面的bing action setting 是用来绑定对应事件的
红色的代表该bing action 有问题
左边是状态, 右边是对应事件, none代表没有状态
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEp3yPbonRVyCc1wvttRjZfaVel4KwEMXmt08pcGZenFW6vEh26a3ymrA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)这样,我们的角色模板就创建好了
**可配置性2 - 动画组**
然而关联对应的动画组, 我们也需要考虑角色的动画有那些类型
例如最简单的 idle - 走 - 跑 - 攻击 - 特殊攻击 这些动画背后有关联着那些内容呢?
idle - 走 - 跑 这三个被称为**locomotion** 是一个角色的基础动作组
我这里采用的是一个动画组支持多个locomotion, 放置一个角色有多重基础动作
例如一个角色有锤子, 和 举起锤子两个状态 , 举起锤子的时候可以移动, 那么locomotion里的移动动作必须全部换新的, 并且这个角色还可以切换武器 - 太刀, 那么所有的动画片又被替换了
所以最后动画组是这样的:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEphAkwRYGcfTZEGREJNcAn2bdbcicqsdic8E7JCmYqvOgdwM9mGRxwT9vA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)上面是一个基础的locomotion, 下面是对应的 其他locomotion
再往下是具体的动画业务, 这里最好的状态是下面的动画根据上面locomotion的切换也有一定的可编辑性,但是我当时并没有做.
动画片的意思是例如攻击, [idle - 走 - 跑] , 翻滚 , 这些动画的类型如何处理
我们当然可以直接播放动画片,但是一个动画片包含了很多可能性, 这些可能性我们应该做成可配置性的
locomotion 的做法我采用了是否的选择, 例如考虑到巨型怪物可能只有走,
或者某些小型怪物只有跑, 走和跑还有idle都是用于的可选项
locomotion动画片的选项如下:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpEH9p2eWOFEbxOnicjfP5gperEibtibOr0YycJsLQyrvOTxE3dpwxhxGQw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)你可以考虑是否有疾跑, 跑, 和走
很关键一点在于生成locomotion以及对应的混合树,我把最复杂的混合树截图出来,其他的大家自己研究吧,有问题可以留言.
这里的关键点在于 走和跑的分离, 这样在左右横移的时候 不会出现这样的状态切换 [左横跑 - 左横走- idle - 右横走 - 右横跑], 双层混合树的好处在于直接变成:[左横跑 - 右横跑]
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEp2ubib1PB30d0pYANhickWtVyb5iaDpMkJlMyE0m4CbQxiaOSGpVI5qFUOA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)当然, 直接八向混合也可以,但是**如果追求细节不要这么做.**
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpbPkYTbLa6OberQqBT3CSWicE7uIDHlficYBkEMLIM5dx9oXB8pYhSupA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)
最基础形态就是全部取消,只有idle:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpOLz53icjH0O8GjOC8gvpeKp9JRdYfwEludKZ8rXcCj0jwsXI2Mq0nWw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)因为动画状态特别多,如下:
```
public enum AnimationType
```
我在用一个典型的举例,就不多讲了
如果讨论动画组,不讨论combo也太不厚道了
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpYSsoaC4HgdCibcpzAwI4qt03xJ7taGe1BicAvAjMRSkusr56qQEzmtJw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)combo我大致是这么做的, 可以支持多个动画片, 在播放时根据长度连续播放这样就支持连击了, 而且可以选择遮罩,例如只有上半身, 只有下半身,每个动画片绑定自己的前摇和后摇.
还有是否支持root motion等
再举个例子就是被击:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpdl2ibnb5MOpXAANI3fv2ENqG3cnB7VoR5GdHoBvC7f3AQibkhjNYypzQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)被击可以选择有效图层和具体播放动画片的朝向, 这个根据你的业务具体安排
其他例如loop动画, 普通animation, 就是可以配置前摇后摇时间即可, loop要支持三个动画的循环, 在动画播放结构中也需要支持.
**动力学和动画模块分离**
这里的核心思想是:
PlayController需要将输入交给动力学组件,同时将动力学组件的内容,交给Animation组件.
需要根据真实移动速度来决定动画状态,而不是输入向量,基于这个大的思想,可以保证一些奇怪的问题不要出现.
而动力学的核心在于处理特殊情况.
这里的类结构大概是这样:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEpmm6Ft2b9UBIHricdBguYibvJXX4q0x984Myb9oPMayxibFNGF2TR7u7zA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)Kinematic大概有几个大的业务要考虑清楚:
- **撞墙** - 撞墙的处理关键在于不要穿的太厉害,当动力学组件遇见墙体时候,Rootmotion依旧会执行,这时需要同步角色位置到当前动力学组件的位置,这个是基础
- **边缘检测** - 边缘检测在于下滑,一般人物会用一个胶囊体,这个胶囊体会卡在边缘,这里要处理的平滑,下落既是下落,而不下落时人物要站扎实不要抖
- **跳跃1** - 原地起跳 - 原地起跳最好用一个独立动画,问题的关键是当前跳的落点是高低不平还是平面,因为资源和时间的问题,我直接用跳跃处理的这里,当动画播完还没落地,我就认为地面是不平的直接过渡到跳跃循环
- **跳跃2** - 冲刺起跳 - 当玩家加速跑时,这个起跳必须和普通跳跃不同,否则没有那种速度感,同时向前跃起,这里最大的坑在于可能你刚起跳就撞到物体了,好一点的或者美式动作游戏会处理一下,给个撞击动画,但是有些游戏也不处理,尤其是日式游戏,硬播完对玩家来说并不是不可接受的事情,冲刺起跳后落地最好也接一个落地动画,例如翻个跟头,而撞墙就不适合播放,这里具体如何处理就要看GamePlay的爱了...
- **跳跃3** - 向前跳跌入悬崖或者落地 - 跳跃其实分为是哪个部分,起跳,loop, 跳跃落地,落地又分为下落时间过长的大硬直和下落距离不大的小硬直
- **爬梯子1** - 分为三个状态,上梯子,下梯子,和爬,这里最好给一个固定动画,由程序控制正播或者倒播,比较麻烦是对上点,并且要动力学组件配合,这里还有个做法就是用ik让手和脚找梯子的挂点具体就看GP的爱吧...
- **爬梯子2** - 还有一个坑就是爬梯子的时候,被击怎么处理,黑魂里是给人物一个抖动,死了就直接跌落
- **爬峭壁** - 这算是比较恶心的一个点了,爬峭壁的核心在于配合IK以及关卡设计,以及庞大的动画状态,这个状态属于一个全新的locomotion,我当时只是试了一下挂在峭壁上,然后按跳跃就播放跳跃,然后扒到下一个挂点
允许我偷个懒,多余的就不写了,有问题请评论追加...
## 状态管理
首先unity的animation controller提供的混合树非常好,但是状态却又一些不疼不痒的bug,例如A状态到B状态的过程中, 切换C状态这时会出现闪一下切过去, 上下半身的动作会又互相影响, 修正起来既蛋疼,又麻烦, 所以我干脆就自己管理状态, 让unity直接执行就好了, 手动管理状态,把ac内部的混合树当一个状态调用
而和状态在一起的,还有一个关联项目就是对输入的处理
输入可能有三个来源
1. 玩家手柄或者键盘
2. AI行为树
3. 网络
不管哪个来源,我们可以用同样的抽象层让输入统一,
输入分为几个类型
- 普通事件 - 不要让玩家的输入直接操作动作,一定要做一个转换,尤其是移动,移动的朝向交给动力学,动力学作用于动画系统,而按键输入一定要转化为一个类似行为的抽象.
- 状态转换型输入 - 某些按键实际上是一个状态, 例如,玩家按下收刀实际上角色要进入到一个收刀的状态,此时攻击键变成了一个特殊攻击,相对应这个状态下的输入都出现了变化,所以一个行为应该是基于状态的, 关于这个状态和事件的区别大致是这样的:
![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/l2Uzl9GfAIcGrR8WkWics8ia8cmyJbqFEptytMVY5lM1uUEOR2qSeMhSEcdDEibuHicxTQIFiaNTpNbTRe3Uic87ZIHw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)
这个状态手柄上一般会用扳机键
- 输入的时效 - 一般一个动作分为三个阶段 - 前摇, 执行中, 后摇,你可以指定三个阶段那个是有效输入阶段,例如我一般会屏蔽前摇的输入, 执行中是有效输入阶段,后摇就处理玩家输入
- 输入指令的重排序 - 这里很重要的是当一个动作执行中,玩家的输入要如何处理,后摇就开始执行之前输入的动作进入预混合阶段,而且后摇这个时间点我推荐对动作进行排序,例如当前是攻击,那么要做一个输入的优先级排序, 优先级最高的可能是下一个攻击, 而翻滚之后 优先级最高的可能是喝血, 不要根据玩家的最后一次按键去执行,这里对感受的提升是巨大的
## 动作的细节处理
**攻击和翻滚相关:**
> *攻击,翻滚的前摇最好不要锁方向,这样玩家容易攻击之后怪物因为移动躲开了, 最好的量我感觉最好根据不同动作,每个单独设置
> * 攻击 - 攻击的核心在于Root Motion, 但是细节又有好多讲究,例如如何定帧, 是真的停顿还是减速, 攻击的碰撞又有几种方式, 有直接绑定碰撞盒的, 有攻击最后一个伤害帧算扇形面积的,攻击中还可能有被击, 被击怎么处理
> *攻击还有一个特性就是3D场景下的攻击,容易让玩家产生错误空间感受, 所以要增强玩家在3D场景下的攻击范围,或者敌人伤害的触发范围,这个要结合是否有PVP单独调整.
> *翻滚 翻滚我因为动作资源的限制用一个翻滚,然后角色转向的方式处理, 其实最好的方式应该是8个方向分别用独立的动作, 翻滚很重要一点是启动的时候,需要给一个旋转的时间,也就是前摇不要锁方向这一点是通用的
**locomotion相关:**
> *locomotion其实决定了一个手感的基础,大部分的动作都是由locomotion过渡的,这里双层混合树是指第一个混合树用来做当前速度,朝向的判断,第二层有三个对应的混合树
> idle,当没有速度的时候,就默认idle
> 走,当速度不够跑的时候,就默认用走
> 跑,速度够的时候就切换到跑,之所以要把跑单独出来,是因为有一个特殊情况,就是玩家在向左平移时,突然向右,有一个瞬间会速度到0,例如从左到右 速度会这样变化: [1, 0,-1], 此时如果走和跑用一个混合树,动作会过渡到走,然后过渡到跑,这里会有一个微小的卡顿,很不舒服
> 直接根据速度和方向切换到走跑,这样在一个平移中,例如向左横移,突然向右,会有一个微小的过渡卡顿, 跑-走-跑, 而实际上这是不符合人的移动习惯的,但是在一个情况下例如怪物没有走路的动画只有idle和跑,或者没有跑步,只有idle和走,那么可以用单层混合树搞定全部
**特殊动作处理:**
> 在某个武器的状态中,要支持一个或者多个特殊状态,例如太刀的收刀,大锤子的蓄力,有些特殊动作会禁止移动,有些特殊动作释放中可以移动,那这里我感觉最好是切换locomotion
> 切换武器实际上相对应的很多动画都要切换,我这里用的是直接切换全套动画组来处理,例如双刀切换到单手中剑,这连idle都切换了
**被击**
> 被击实际上是打击感的核心,一个动作的受力做的极其好,但是没有攻击物体时,你是感受不到力量的, 但是一个动作做的一般,但是被击做的非常到位,此时你可以感受到攻击后的力量,这个力量感就是被击表现,被击的核心有几块: 停顿配合, 击退距离和攻击移动距离要配合, 连续攻击后击飞, ,音效,特效等等
> 被击方式1 : 攻击原地不动,被击者微小后退,几下后击飞或者退出攻击距离(塞尔达),这是一种对怪物的保护,连击几下后怪物就被击飞
> 被击方式2 : 攻击者前移,被击者后退(黑魂)
> 被击方式3 4向被击 - 四向被击对被击的体验提示是很大的,而且被击本身最好支持Rootmotion,攻击对象被击后后退对被击对象也是一种保护,拉开与攻击者的距离,还要配合击倒,并且可以支持4向-同时支持每个方向根据攻击角度不同采用2种不同被击
> 击倒 - 这其实是一个保护性动作,击倒后角色不可以被二次攻击,当然也有可以被攻击的鬼泣里的就有这里就看具体策略了
**硬直中的被击处理**
> 硬直被打断 - 直接转入被击,这里的处理没有特别好的办法,被击的关键在于快速反馈,直接决定手感是否刀刀入肉,所以如果连续被攻击,就会出现抖动,如果例如被4个人前后间隔不到一秒攻击4下,这里可能要特殊处理是否要从第一个被击直接过渡到第四个 中间2个干掉一个 甚至直接干掉2个
> 硬直没有被打断 - 硬直动画例如蓄力攻击中被攻击有可能不会破坏硬直效果,那此时最好混合一部分被击,让人物有一定抖动,否则也会很假
**处决**
> 处决的核心在于把两个角色的相对位置弄的差不多, 比较糙你就直接滑过去, 然后两个动画的同步播放, 例如黑魂的背刺,你到达指定位置可以触发了,咱们就直接滑动调整位置,一般处决玩家就无敌了,只狼也是这么做的
> 另外一种就是类似QTE的,这一种又分好几种,例如莎木的就比较弱鸡, 但是战神的就比较猛,这个我没做过
**Gameplay 到过场动画的无缝衔接**
> 摄像机平滑过渡的切换和角色动作的切换,这个没做过,难点在于摄像机和角色如何抵达预定位置,中间还是平滑的,看看战神...即便不做成战神那样,这个细节量也很大
## 关于IK
我是用的final IK 解决我的ik问题,所以这里我不展开讲了, 主要处理这几个问题:
- 楼梯上脚悬空的处理
- 开门是用ik还是固定动画
- 拿桌上,抽屉内物体
- 死亡后的纸娃娃效果
- 头部朝向锁定目标或者场景内重要物品
## 物理和动画的相互作用
> 物理这里完全没做过,不过听某些大佬讲,这里处理好可以增加真实感,例如攻击的时候被击,被击没有打断攻击状态可以加一个10-30%的物理状态的抖动到攻击身上
> 例如你被前面的敌人攻击然后背后也有人攻击你,此时如果不处理就是抖动到背后的被击了,因为被击必须快速切换,响应慢了就假了,被击直接影响手感,听某些大佬说可以考虑混一点物理,这样抖动的效果会更好,但是我并没有试过
## 这些黑科技
> motion matching是育碧搞的一个动作匹配技术,基于目标的位置和方向速度通过算法从数据库中取用匹配动画,需要大量的动画片支持,同时还要预判断未来地形变化,总之很黑科技,没有足够的动画资源基本没办法做,美式动作游戏或者冒险游戏里大量的使用该技术
> 例如当一个角色的动画是变速的时候,如何保持动作的受力感受同时又可以变速,例如某个技能可以根据玩家输入加快速度,或者减慢速度,某些游戏会考虑尝试多套动作,但是高级动作游戏例如鬼泣,贝姐,显然不是这么做的,至少我感觉不是这么做也可能是我感觉错了
> 动作中断后如何和下一个动作保持良好的衔接-好吧,讲的直接点,我实在不知道鬼泣和猎天使魔女怎么那么灵活还那么流畅的,不管我怎么处理混合总感觉混合时间不够,或者动作幅度特别大就变的很奇怪,这里我感觉暴力一点就是做大量的中间动作片加强过渡, 不过只能是猜测了
---
嗯 能看到这里的都是真爱
希望有一天我也能开发出像黑魂, 只狼这样游戏设计和技术完美结合的游戏
而且有很多细节介于主题太大了,我也没劲写了
欢迎大家跟我讨论
我有一个网盘,里面放着我做的一些东西
思维导图我也放里面了.
也欢迎下载
链接: https://pan.baidu.com/s/1lLxvffJuN7NEds4mbNYPLg[2]
提取码: 9vb1
### 参考资料
[1]
@我乱写的: _https://www.zhihu.com/people/c6adcb1f69bff45a74f57f4e2150dc3c_
[2]
https://pan.baidu.com/s/1lLxvffJuN7NEds4mbNYPLg: _https://pan.baidu.com/s/1lLxvffJuN7NEds4mbNYPLg_

View File

@@ -1,18 +0,0 @@
## 技能环节(SkillProcUnit):
负责每个环节要做的事情:
例如:0.2s治疗 0.4s根据治疗量上攻击buff 0.6s造成AOE伤害
前摇后摇
## 技能流程管理纳入到Base管理
对于环节类,应该有一个管理类来管理时间戳到哪个环节,流传上个环节的数值到下个环节,然后调用场景管理类的实际功能
## 场景管理:
实际触发
## 技能信息类:
受到技能的级数技能buff加成等影响技能元数据的装饰类
## 技能表现:
由SKillBase通信动画组件与特效组件干活

View File

@@ -0,0 +1,3 @@
[游戏知识学习——【战斗系统】-CSDN博客](https://blog.csdn.net/qq_53045580/article/details/130804401)

View File

@@ -0,0 +1,5 @@
正常流程
1、攻击 - 扣血 - 死亡
2、攻击附加buff
3、技能

View File

@@ -0,0 +1 @@
[Unity 技术美术Trick —— dither妙用 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/697133450)

View File

@@ -0,0 +1 @@
[Unity可交互雪地渲染Part5-雪地闪光及SSS - 知乎](https://zhuanlan.zhihu.com/p/30651821847)

View File

@@ -0,0 +1,142 @@
# The quicktype FAQ
- [What is this?](#what-is-this)
- [How does this work?](#how-does-this-work)
- [How do I use this with my code?](#how-do-i-use-this-with-my-code)
- [No code appears when I paste my JSON](#why-does-quicktype-complain-about-my-json)
- [I think I found a bug!](#i-think-i-found-a-bug)
- [When will you support my favorite language?](#when-will-you-support-my-favorite-language)
- [Why do my types have weird names?](#why-do-my-types-have-weird-names)
- [I'd like the output to be a little different.](#id-like-the-output-to-be-a-little-different)
- [Am I allowed to use the generated code in my software?](#am-i-allowed-to-use-the-generated-code-in-my-software)
- [This map/dictionary should be a class!](#this-mapdictionary-should-be-a-class)
- [This class should be a map/dictionary!](#this-class-should-be-a-mapdictionary)
- [Where can I learn more about JSON Schema?](#where-can-i-learn-more-about-json-schema)
- [I'd like to customize the output for my particular application.](#id-like-to-customize-the-output-for-my-particular-application)
- [How can I control the property order in JSON Schema?](#how-can-i-control-the-property-order-in-json-schema)
- [quicktype is awesome, I'd like to support it!](#quicktype-is-awesome-id-like-to-support-it)
- [How is this different from other JSON converters?](#how-is-quicktype-different-from-other-json-converters)
## What is this?
[quicktype](https://app.quicktype.io) produces nice types and JSON (de)serializers for many programming languages. It can infer types from JSON but also takes types from JSON Schema, TypeScript, and GraphQL.
## How does this work?
You paste JSON on the left, and code appears on the right. [This video](https://www.youtube.com/watch?v=19bMU7jZ27w) gives a quick demonstration.
## How is this different from other JSON converters?
`quicktype` is superior to other JSON converters in many important ways:
- **Type inference**: quicktype infers optionals, dates, UUIDs, enums, integers, and unions. It also infers maps (versus objects) using a Markov chain.
- **Careful naming**: quicktypes naming system creates nice, legal, unique names for types and properties, handling reserved words and tricky corner cases (e.g. `{ “”: “this is legal”, “null”: “so is this”, "1;DROP TABLE users”: “and this" }`).
- **Heterogeneous data**: JSON data is often heterogenous. quicktype infers this, and creates union types in languages that support them, or synthetic union types in languages that dont (e.g. try quicktyping `[0, “zero”]` as Swift and Go).
- **Type unification**. This works across multiple samples, so you can quicktype a directory of API data, for example, and unify types across all responses (e.g. youll get just one `Customer` type, even if customer data occurs in many samples). You can also provide multiple samples for the same type for better coverage.
- **Marshalling code**: In addition to types, quicktype generates functions for marshalling your types to and from JSON.
- Supports dynamic languages: quicktype can add dynamic typechecks for JavaScript, TypeScript, Flow, Python, and Ruby.
- **Convenient CLI**: Run `quicktype https://blockchain.info/latestblock -o LatestBlock.ts` to quicktype a Bitcoin API in TypeScript.
- **Client-side**: [The web version of quicktype](https://app.quicktype.io/) runs on the client, so servers never see your data (most JSON converters send your JSON to their server)
- **Typed input**: Feed quicktype TypeScript or JSON Schema instead of JSON for better control over generated types.
- **Code quality**: quicktype emits clean code
## How do I use this with my code?
The generated code has comments at the start with a short code sample that shows how to convert a JSON string to instances of the generated types. You can also go the other way, which is very easy, too, but you'll have to look at the generated code to see how it works.
## No code appears when I paste my JSON
This is probably because your JSON is invalid. The most common issues we're seeing are
- Trailing commas in arrays and objects: `[1, 2, 3]` is valid JSON, while `[1, 2, 3,]` is not.
- Unquoted property keys in objects: `{ "name": "Mark" }` is valid JSON, while `{ name: "Mark" }` is not.
- Comments: JSON does not support comments.
If you're unsure whether your JSON is valid, please use [JSONLint](https://jsonlint.com).
## I think I found a bug!
Please [file an issue on GitHub](https://github.com/quicktype/quicktype/issues). Give as much context as you can so that we can reproduce it. Assume we know nothing about what you're trying to do (because we don't).
## When will you support my favorite language?
Please check whether there is [a pull request](https://github.com/quicktype/quicktype/pulls) that adds support for your language. If there is, please consider helping it along. If there isn't, please consider contributing one.
## Why do my types have weird names?
Sometimes quicktype has trouble giving names to your types. There are a couple of causes for this:
- The name quicktype would like to give to your type conflicts with a name that's already used in the target language, such as `String` in C#.
- Two or more types in your data have the same name.
- A type has so many potential names that quicktype can't find a commonality between them.
If you're using JSON Schema, you can use the `title` property to give a type a name that quicktype tries hard to use.
## I'd like the output to be a little different.
Check out the "Language" and "Other" tabs in the options panel. What you're looking for might just be there:
<img width="33%" height="33%" alt="Screenshot showing the options panel" src="https://raw.githubusercontent.com/quicktype/quicktype/master/media/faq/options-panel.png" />
If it isn't, then depending on your coding skills, you might be able to [customize the output](https://blog.quicktype.io/customizing-quicktype/).
## Am I allowed to use the generated code in my software?
Yes, there are no intellectual property restrictions on the code that quicktype generates.
## This map/dictionary should be a class!
quicktype has [advanced heuristics](https://blog.quicktype.io/markov/) to decide whether a JSON object should be represented by a class or a map, but sometimes it gets it wrong. If it generates a map, but you'd rather have a class, you can disable map detection in the options panel:
<img width="66%" height="66%" alt="Screenshot showing the 'Detect maps' switch in the options panel" src="https://raw.githubusercontent.com/quicktype/quicktype/master/media/faq/disable-detect-maps.png" />
## This class should be a map/dictionary!
quicktype has [advanced heuristics](https://blog.quicktype.io/markov/) to decide whether a JSON object should be represented by a class or a map, but sometimes it gets it wrong. If it generates a class, but you need a map, first make sure that you have the "Detect maps" option set in the options panel. Also, check that all properties in the object have the same exact type because quicktype only makes a map if that's the case. If that still doesn't do it, you have two options:
- Duplicate some of the properties and/or change the property names to look more random.
- Output JSON Schema, modify it to produce a map, and then use the schema as the input to quicktype.
## Where can I learn more about JSON Schema?
The [JSON Schema homepage](http://json-schema.org) contains many links and resources.
## I'd like to customize the output for my particular application.
We have [a blog post](https://blog.quicktype.io/customizing-quicktype/) on that very topic.
## How can I control the property order in JSON Schema?
There is a custom schema field `quicktypePropertyOrder` which can be used to specify the order of properties for quicktype.
For example:
```json
...
"Location": {
"quicktypePropertyOrder": [ "latitude", "longitude" ],
"type": "object",
"properties": {
"latitude": {
"type": "number",
"description": "The latitude component of the location",
"example": -32.204754
},
...
},
"required": [ "latitude", "longitude" ]
},
...
```
## quicktype is awesome, I'd like to support it!
There are many ways you can support quicktype:
- Tell all your friends about it! Show it around, tweet about it, write a blog post, present it at a lightning talk.
- quicktype is open source - please contribute! We need documentation at least as much as code, so you don't need strong coding skills to make an impact. If you do, we have [lots of open issues](https://github.com/quicktype/quicktype/issues) that need resolving, almost all of our target languages can be improved, and there are many, many programming languages that quicktype doesn't support yet. Talk to us [on Slack](http://slack.quicktype.io) if you're interested - we're always happy to help.

View File

@@ -1 +0,0 @@
todo

7
算法/TopK 问题.md Normal file
View File

@@ -0,0 +1,7 @@
地址:[前端进阶算法10别再说你不懂topk问题了 · Issue #73 · sisterAn/JavaScript-Algorithms (github.com)](https://github.com/sisterAn/JavaScript-Algorithms/issues/73)
解法:
1、最小最大堆
2、快速选择(快速排序+快速选择时基准恰好等于K时)
3、中位数的中位数BFPRT算法

29
资源/打包/导航.md Normal file
View File

@@ -0,0 +1,29 @@
- [【Unity】打包(五)](https://www.jianshu.com/p/4884cae1195d)
AssetBundle使用方式 上一篇文章涵盖了AssetBundle基础包括各种底层的加载API。这篇文章主要讨论AssetBundles实...
- [【Unity】打包(四)](https://www.jianshu.com/p/11bcb4c4fb55)
AssetBundle基础 这篇文章讨论了AssetBundles。介绍了AssetBundles打包系统以及AssetBundles核心API...
- [【Unity】打包(三)](https://www.jianshu.com/p/451b7640bc07)
Resources目录 这篇文章主要讨论Resources系统。这是一个允许开发者存储一个或多个文件或文件夹在Resources文件夹下在运行...
- [【Unity】打包(二)](https://www.jianshu.com/p/0b9ed3bcffef)
Assets,Objects序列化 这是涵盖Assets,Resources和资源管理的一列文章中的第二篇。 这篇文章涵盖了Unity序列化系统...
- [【Unity】打包(一)](https://www.jianshu.com/p/13afc42e9fde)
AssetBundles和Resources的指南 这一系列文章对Unity引擎中Assets和resource管理进行深度探讨。试图为专家开发...

167
资源/资源导入.md Normal file
View File

@@ -0,0 +1,167 @@
# [【三思Unity】深入浅出资源管理之Asset Import Pipeline v2](https://www.cnblogs.com/hearthstone/p/13358025.html "发布于 2020-07-21 23:12")
每个游戏都是由种类繁多的资源构成,例如:网格、材质、纹理、着色器、动画、音频等。导入并管理这些资源文件,是游戏引擎必备的能力。资源管理包含两部分:离线管理和运行时管理。
在 Unity 2019 LTS 中,对应的解决方案分别是 Asset Import Pipeline v2下文简称 AIP v2 和 Addressable Asset System。本文主要讲解 AIP v2 部分, 包含 v2 相对于 v1 的改进之处,和完整的资源导入流程。
关键词Asset Import Pipeline v2Unity AcceleratorAsset RevisionsAsset Database
# 1. Asset Import Pipeline v2
资源导入是 Unity 中最耗时的工作流程之一,是 AIP v1 的遗留问题。针对其中最耗时的两个阶段——新资源的导入和平台切换AIP v2 分别提供了对应的解决方案。
## 1.1 新资源的导入
第一次拉取项目时,项目中没有 Library 文件夹,这意味着 Assets 文件夹和 Packages 文件夹中的所有资源都需要经过 AIP 的导入处理,这步非常耗时。相较而言,直接拉取导入结果,耗时就要少几个数量级。
### Unity Accelerator
AIP v2 给出的方案是 Unity Accelerator一种基于 Unity Collaborate 的局域网代理和缓存服务。原理是:团队中有一人导入完资源,导入结果被自动缓存到 Accelerator团队里的其他成员在导入相同版本的资源时Unity 首先检测 Accelerator 上是否已经有对应的导入结果,如果有就下载。因为是本地网络,带宽不是问题,所以在资源较多的项目中,下载时间要远少于导入时间。
在 Unity 给出的测试中一个大小100MB、数量12000个的项目资源Untiy 的导入时间为6分钟Accelerator 的导入时间为30秒节省了90%以上的资源导入时间。然而实际项目中12000个资源的空间占用一般要大于100MB因此该测试仅供参考。
Unity Accelerator 基于 Unity Teams Advaned按团队人数收费。目前提供30天免费试用25GB云存储3人团队的价格是60元/月每增加一名团队成员的价格是48元/月。
## 1.2 平台切换
在 AIP v1 中Library 文件夹中缓存的导入结果以资源的GUID作为文件名。这天然的导致了一个资源只存在一个导入结果因此每次切换平台都需要重新导入所有资源。这步非常耗时在大型项目中甚至需要数个小时。
在 AIP v2 出现前,临时的解决方案是每个平台分别对应一个项目。缺点是要占用多份项目的硬盘空间,以及每个项目需要单独拉取更新。
### Asset Revisions
AIP v2 给出的解决方案是不使用资源的GUID作为导入结果的文件名而是使用资源所有依赖的哈希值作为文件名而平台正是资源的依赖之一资源依赖的说明见下文4.3。于是每个资源因为依赖的不同而拥有多个版本的导入结果它们被称为资源的修订版Asset Revisions。因此 Asset Database 中可以同时缓存多个平台的导入结果,当切换至已经有导入结果的平台时,就不需要再经历耗时的导入处理。
AIP v2 同样存在占用硬盘空间大的缺点,但是相较于每个平台分别对应一个项目,占用空间要小很多。对此 AIP v2 也做了优化处理:只保存每个资源仅平台依赖不同的修订版,其他依赖导致的不同修订版,在 Unity 每次重启时会被删除。
# 2. 源文件 Source File
Source File 是指由 Unity 之外的软件创建并导出的资源文件。常见的有图片png、jpg、psd、音频wav、ogg、mp3、视频avi、wmv、mp4、模型fbx、obj、c4d、blend、字体ttf、otf、ttc、着色器cg、hlsl、文本文件txt、xml、json、csv、代码文件dll、jar、cpp、c、mm、dylib等。
仅仅将 Source File 放入项目文件夹中,并不代表它成为了项目的一部分。只有经过 AIP 的导入处理Soure File 转变成 Asset 才能为项目所用。
导入处理将 Source File 转换成 Unity 能够处理的格式。这些格式往往硬件友好能够让CPU、图形、音频等硬件立即处理。例如Unity 在运行时不会直接使用 .png 格式的图片,而是使用经过导入处理后的某种具体格式的 texture 文件。
Pipeline 确保了导入结果的确定性,即:相同依赖的 Sourece File 经过导入处理,在任意时刻、任意设备得到的 Asset 是相同的。
# 3. 资源数据库 Asset Database
Asset Database 包含了两层含义。一层指 Source Files 经过 AIP 导入处理后的数据文件集合,即项目 Library 文件夹中的内容,又称为 Asset Cache。Unity 在项目运行和打包时,使用的正是这里面的数据文件。
另一层指 Unity 封装的 AssetDatabase 类。该类提供了对于 AIP 最重要的一个方法 Refresh以及一系列方便安全的项目文件操作方法例如Contains、CreateAsset、CreateFolder、RenameAsset、CopyAsset、MoveAsset、DeleteAsset、LoadAssetAtPath等。
# 4. 刷新 Asset Database
将 Source File 放入项目 Assets 文件夹中时,或通过 Package Manager 导入 Package 时AIP 检测到新资源,并执行导入处理。这一步的本质是触发了 AssetDatabase 的 Refresh 方法。
以下三种情况会触发 AssetDatabase 的 Refresh 方法:
1. Unity Editor 重新获得焦点(如果开启了 Auto-Refresh
2. 点击 Assets > Refresh 菜单。
3. 在 C# 代码中直接调用 Refresh 方法;或通过调用 CreateAsset、ImportAsset 等方法,间接触发 Refresh 方法。
AssetDatabase 的 Refresh 方法将按顺序执行以下步骤:
1. 寻找变更的 Assets并更新 source Asset DatabaseLibrary 文件夹中)
2. 导入并编译代码相关文件
3. 重载脚本域
4. 导入非代码文件
5. 热重载
6. 更新 Artifact DatabaseLibrary 文件夹中)
接下来将对上述步骤做较详细介绍,其中某些步骤会被拆分为几个小步骤。
## 4.1 寻找变更的 Assets
当触发了 AssetDatabase.Refresh() 方法后Unity 开始扫描项目中 Assets 文件夹和 Packages 文件夹中的每个资源。与上次扫描相比,如果资源出现了新增、变更或删除,则将它添加到一个资源变更列表中。
## 4.2 更新 source Asset Database
计算资源变更列表中的每个资源的哈希值并且根据它们的GUID更新 source Asset Database并从列表中删除对应资源。
## 4.3 依赖追踪Dependency tracking
资源的依赖Dependencies是指所有能够影响导入结果的数据。资源的 Source File 是最原始的依赖,资源的导入设置、目标平台等也都是依赖。
**资源变更的本质,是资源依赖的变更**。AIP 追踪了每个资源的所有依赖。资源的任意依赖发生变更,都将引起资源的重新导入,生成新的导入结果。
**资源变更的结果,是不同版本的资源缓存**。AIP 维护了项目所有资源的导入结果,这些导入结果缓存在 Library 文件夹中又叫做资源缓存Asset Cache。同一个资源的不同导入结果是不同版本的资源缓存又称为资源的修订版Asset Revisions
## 4.4 导入并编译代码相关文件
Unity 从资源变更列表中收集与代码相关的文件递送给脚本编译管线script compilation pipeline。然后编译器根据脚本文件和 assembly definition 文件生成程序集Assemblies
## 4.5 重载脚本域Reload the domain
域重载Domain Reloading处理会完全重置脚本的状态包括重置所有静态字段和静态事件句柄。任意脚本的变更都会重载脚本域。为了确保自定义导入器Scripted Importer起作用这步将重启 AssetDatabase.Refresh() 方法。
## 4.6 导入非代码资源
AIP 基于资源文件名的扩展名识别文件类型再基于文件类型使用对应的导入器Asset Importer处理资源。例如TextureImporter 负责导入 jpg、png 和 psd 等图片资源。导入器分为两种原生导入器Native Importers和自定义导入器Scripted Importers
### 4.6.1 原生导入器Native Importers
Unity 内置了很多原生导入器,支持大多数资源类型,例如:图片、音频、视频、模型、材质、着色器、字体、文本文件、代码文件等。
### 4.6.2 自定义导入器Scripted Importers
对于新的资源类型,我们可以编写自己的导入器。对于 Unity 已经提供了导入器的资源类型,也可以使用自定义导入器覆盖原生的导入处理。
部分 Unity 内置的导入器也属于自定义导入器因此这些导入器的处理发生在自定义导入器的处理阶段。例如StyleSheetImporteruss 文件、UIElementsViewImporteruxml 文件)。
## 4.7 预处理Preprocess和后处理Postprocess
在导入阶段,有许多回调方法,可用于资源导入的预处理和后处理。
预处理方法有:
- OnpreprocessAsset
- OnpreprocessAnimation
- OnpreprocessAudio
- OnpreprocessModel
- OnpreprocessSpeedTree
- OnpreprocessTexture
后处理方法有:
- OnAssignMaterialModel
- OnPostprocessAnimation
- OnPostprocessAssetbundleNameChanged
- OnPostprocessAudio
- OnPostprocessCubemap
- OnPostprocessGameobjectWithAnimatedUserProties
- OnPostprocessWithUserProperties
- OnPostprocessMaterial
- OnPostprocessMeshHierarchy
- OnPostprocessModel
- OnPostprocessSpeedTree
- OnPostprocessSprites
- OnPostprocessTexture
- OnPostprocessAllAssets
## 4.8 重启 AssetDatabase 的 Refresh 处理
在上文中提到,重载脚本域将重启 AssetDatabase.Refresh() 方法。除此以外,还有其他情况会重启 AssetData base 的 Refresh 处理。例如:
- 如果某个资源导入失败
- 如果资源在 Refresh 中的导入阶段被更改
- 如果资源在导入时生成了其他资源
- 如果在预处理/后处理回调方法中强制重新导入某个文件,例如:在 OnPostProcessAllAssets 方法中使用 AssetDatabase.ForceReserializeAssets 方法或 AssetImport.SaveAndReimport 方法。注意避免无限重导入。
- 如果在编译完脚本后,某个程序集需要重新加载。
- 如果以“Text only”保存某个资源但是该资源必须被序列化为二进制格式就会触发 Refresh 处理。例如:带有地形的场景必须被序列化为二进制格式,因为文本格式太笨重。
## 4.9 热重载 Hot reloading
热重载是指在 Editor 不重启的情况下,导入并应用脚本和资源的变更。热重载在 Editor 的 Play Mode 和非 Play Mode 都有可能发生。
当你更改并保存一个脚本文件时Unity 首先保存所有已加载脚本的序列化变量,等脚本加载完成再恢复这些数据。在热重载完成后,所有非序列化的数据都将丢失。
## 4.10 更新 Artifact Database
这是 Refrech 的最后一步Library 文件夹中的 Artifact Database 被更新,导入结果被保存在硬盘上。
# 引用参考
[1] [The new Asset Import Pipeline: Solid foundation for speeding up asset imports](https://blogs.unity3d.com/cn/2019/10/31/the-new-asset-import-pipeline-solid-foundation-for-speeding-up-asset-imports/)
[2] [The Asset Database](https://docs.unity3d.com/Manual/AssetDatabase.html)
[3] [Refreshing the Asset Database](https://docs.unity3d.com/Manual/AssetDatabaseRefreshing.html)