1.Unity工程里的Library、Plugins、StreamingAssets、Standard Assets等东东
2.Unity初级模型渲染原理: 纯代码创建一个三角面并给其贴图测试
3.Unity 关于安卓和各平台读写本地json文件,WWW读取本地文件,Unity各路径API目前较完整的酷菠萝溯源码详解
4.关于Unity中的UnityWebRequest
5.Unity新HL网络API——NetCode 0.1.0-preview6 文档翻译 第一篇 入门
6.《Unity_API解析》 第十章 Rigidbody类
Unity工程里的Library、Plugins、StreamingAssets、Standard Assets等东东
在Unity工程中,有四个特殊的文件夹和文件组织结构,它们各司其职,共同构建了项目的基础架构。以下是这四个部分的详细解析:
1. Assets: 这是资源的根目录,存放所有项目所需的Asset,包括各种脚本、模型、音频等。Unity的许多API都是基于这个目录,比如AssetDatabase。
2. Library: Unity将Asset转换为内部可识别的格式,并将编译后的代码存储在这个文件夹中。它包含了资源编译后的DLL文件。
3. ProjectSettings: 这是编辑器中的设置文件夹,用于存放各种参数和配置。
4. Plugins: 包含第三方插件、工具代码和SDK,分为Managed和Native两种。Managed plugins是.NET编写的,而Native plugins是原生代码编写的库。
5. StreamingAssets: 在打包时会完整包含在包中,但只读不可写,常用于存放初始的AssetBundle资源。
6. Standard Assets: 存放导入的第三方资源包,通常包含高质量的预设和模型。
7. Editor和Editor Default Resources: Editor目录用于存放扩展编辑器工具和资源,Editor Default Resources则包含编辑器使用的特定资源。
8. Gizmos: 用于在编辑器中绘制辅助线或进行场景视图的定制。
9. Resources: 存放资源文件,会被打包进最终的包中。每个Resources文件夹下的资源会被打包为一个缺省的AssetBundle。
. Hide Assets: 隐藏的文件和文件夹,通常以"."或"~"开头,或者名字包含"cvs"或".tmp"。
. Asset Types: 包括Image、Model、Mesh和Animations、Audio Files等,Unity支持多种格式。
. Asset Store: 提供了大量免费和付费插件,便于开发者获取和使用。
这些文件夹和结构有助于保持项目组织清晰,便于管理资源和脚本,确保在不同平台上的兼容性。理解这些组成部分对于有效使用Unity开发至关重要。
Unity初级模型渲染原理: 纯代码创建一个三角面并给其贴图测试
创建空物体,添加MeshFilter与MeshRenderer组件,并为MeshRenderer配置贴图。涨指标源码材质仅为默认材质,附加一张。此过程构建基础图形结构与外观。
使用纯代码生成三角面并贴图。此操作仅需五行代码实现,简化了模型创建过程。
生成三角面的具体步骤包括覆盖mesh组件的3个数组,即顶点位置、UV坐标和三角面索引数组。顶点位置数组包含所有顶点相对于模型本地0点的位置,UV数组表示贴图上的位置比例,三角面数组则通过这三个数组索引识别每一个三角面。
创建底为1、高为1的三角面,贴图则与素材裁剪后的三角形匹配。复杂模型可通过增加更多数组实现,如添加法线贴图数组。
在代码实现时应注意以下事项:
1. 注册三角面数组时需使用Unity提供的API,并提供材质索引。此操作确保模型具有多个材质时,正确绑定到指定材质的三角面。
2. 渲染遵循左手法则,提供三角面点顺序时应遵循顺时针方向,以正确绘制模型的正面。数组顺序可随意,但须确保顺时针排列。
3. 创建Collider时省略UV数组,其mesh直接通过GetComponent().sharedMesh获取,并无需通过API设置三角面,简化了Collider创建过程。
Unity 关于安卓和各平台读写本地json文件,WWW读取本地文件,Unity各路径API目前较完整的详解
关键点:
使用C# API和Unity API读写本地json文件
Unity API包括JsonUtility.fromjson和JsonUtility.tojson,以及WWW方法
UnityAPI提供的路径参考:
Application.dataPath, Application.streamingAssetsPath, Application.persistentDataPath
txt格式的json文本文件,编码(UTF-8、Unicode、Ascii),Bom字符问题
研究背景:在安卓游戏应用中读取和写入本地json文件,如武器信息、人物属性、得分结算。通过研究和实践,整理出Unity下不同平台读写本地json文件的方法。
教程使用的是windows系统,安卓真机测试,Mac/Linux/IOS未测试。
使用Unity自带API,无需额外插件,JsonUtility类方便进行json操作。
JsonUtility.fromjson将json字符串转换为对象,JsonUtility.tojson将对象转换为json字符串。
在编辑器模式下,使用StreamReader和StreamWriter读写本地文件,Unity的WWW方法用于从网络下载文件。
注意不同平台路径差异,如Resources、源码买卖之家StreamingAssets、persistentDataPath。
Resources文件夹用于资源管理,加载资源、模型,可以使用Resources.Load方法。
StreamingAssets文件夹存储资源,只读不写,路径在不同平台有所变化。
Application.persistentDataPath用于保存运行时数据,支持读写。
使用示例代码展示不同文件夹的路径和读写操作。
说明Bom字符问题,Windows默认在txt文件开头添加Bom字符,影响json解析。
解决方法:使用StreamReader时需要忽略Bom字符,或者在读取json字符串前移除Bom字符。
总结,通过详细介绍Unity下的json文件读写方法,提供不同文件夹的路径和解决Bom字符问题的策略,帮助开发者在不同平台下顺利完成json文件操作。
关于Unity中的UnityWebRequest
HTTP Webrequest unity:
Unity中的UnityWebRequest是一款功能强大的API,用于开发者与Web服务和API进行交互。
无论是下载数据、发送HTTP请求还是上传内容,UnityWebRequest都提供了一种灵活且功能丰富的解决方案。
近期项目中有涉及,整理并留存UnityWebRequest基础知识及其各种组件的使用方法。
UnityWebRequest基础知识:
Unity中的UnityWebRequest是处理HTTP请求的内置系统,支持各种HTTP方法如GET、POST、PUT、DELETE等,与Web服务器和服务通信。
1. 创建一个简单的GET请求:
示例:向一个URL发出GET请求。
在协程中通过UnityWebRequest创建请求,并使用SendWebRequest发送请求,等待完成。
笔记:C#中的using语句确保资源正确清理,不再需要时释放其关联资源。它将创建和实现IDisposable的对象代码封装在try-finally块中,即使发生异常,Dispose方法仍将被调用。
此行声明一个名为www的UnityWebRequest对象,使用对特定URL的GET请求初始化它。using语句确保当括号内的块退出时调用www的Dispose方法。
2. 处理POST请求:
UnityWebRequest允许在POST请求中发送数据。
3. 下载处理:
UnityWebRequest使用DownloadHandler来管理下载内容,默认为DownloadHandlerBuffer,也可使用其他值,如DownloadHandlerTexture用于图像。
DownloadHandlerTexture检索下载的纹理,并将其存储在texture变量中。
4. 上传处理:
上传数据时,UnityWebRequest利用UploadHandler来管理发送的内容。
通过Encoding.UTF8.GetBytes将字符串转换为byte数组,kettle源码变异再通过UnityWebRequest创建访问定向URL的POST请求发送。
将上传处理程序分配给UnityWebRequest对象。
Unity新HL网络API——NetCode 0.1.0-preview6 文档翻译 第一篇 入门
翻译者:BolanT
注:转载时应标注原文链接,以便在NetCode版本更新、文档内容改变时查阅。
原文链接(官方文档):
本文档将提供一个使用Unity NetCode创建基本客户端/服务器结构联机游戏的实践教程。
译者注:建议在学习NetCode前对Unity ECS有较深入了解,因为当前版本NetCode的API和功能还在发展中,没有ECS基础可能会难以理解其中概念。在翻译中,对文档中模糊、版本变化、缺乏解释的内容进行了注释,但可能对无ECS基础读者仍较为困难,甚至可能增加困惑。
一、创建项目
启动UnityHub并创建一个新项目。
(注:使用Unity NetCode需要的Unity版本至少为.3.b及以上。)
打开Package Manager(目录:Window->Package Manager),在包管理器窗口顶部栏,选择Advanced下拉菜单,勾选Show preview packages。
至少安装以下Package:
注:某些包可能为其他包的依赖项,无需过多关注,只需确保上述包的右侧图标显示为箭头或勾选状态且无报错,随意升级或卸载某些包可能会导致难以解决的错误。
二、创建初始场景
为了在客户端和服务器之间共享数据,需要为每个客户端和服务器创建不同的World。首先在NetCode中实现这种分离,创建一个客户端World和一个服务器World。
注:当前版本的NetCode会自动创建ClientWorld和ServerWorld,并注入所需官方System。使用NetCode自带的世界注册前,可能需要编写脚本找到这两个World并用代码管理System。ClientWorld在World.AllWorlds中的Index为1,ServerWorld在World.AllWorlds中的Index为7。原有的World.AllWorlds[0](即DefaultWorld)失去作用,它不会注入任何有意义的System,同时原有的Convert To Entity组件也因此失去作用,需要用新的ConvertToClientServerEntity组件代替。在将非NetCode ECS游戏迁移到NetCode时需特别注意。
创建一个空GameObject(示例中称为SharedData),添加ConvertToClientServerEntity组件。
设置好后,在客户端和服务器世界中生成一个平面。右键单击SharedData Prefab,选择3D Object -> Plane,创建嵌套在SharedData下的Plane。
三、创建ghost预制件
为了在客户端/服务器结构下运行游戏,需要为联网对象创建一个定义,称为ghost。创建ghost预制件需要以下步骤:在场景中创建一个Cube(右键SharedData,选择3D Object > Cube),然后将创建的灰色app源码Cube拖动到Project窗口的Asset文件夹。这创建了一个Cube的预制件。
注:创建完Prefab后可删除场景中的Cube。若遇到问题,使用搜索引擎搜索如何在Unity中创建Prefab即可。
NetCode使用PlayerId来识别不同的玩家。要将之前的Cube预制件作为玩家,需创建一个包含以下简单代码的组件。
创建新文件MovableCubeComponent.cs,并添加GenerateAuthoringComponent注解(关于使用和理解可参考B站视频av)。将此组件添加到Cube预制件,然后添加Ghost Authoring组件,点击Update Component List按钮更新组件列表。
完成后,Unity会为Translation和Rotation组件添加默认值,并将组件展开到列表中,让用户选择它们在客户端或服务端的存在。
注:例如,输入和渲染组件仅在客户端存在,不应当在客户端操作的内容(如物理/可见性更新)仅在服务端存在。
在示例中,服务端关闭了PerInstanceCullingTag和RenderMesh。客户端上的插值物体不进行任何物理模拟。
注:原文未关闭客户端的物理模拟,有时在需要高同步且不担心外挂的物理模拟游戏时,客户端模拟物理可以提升视觉效果。此外,原文未提及关闭RenderBounds,该组件也应在服务端关闭。
将Default Client Instantiation更改为Owner Predicted,以便在本地预测运动。
四、创建Ghost集合
说明:为了向NetCode提供所知Ghost的信息,需要设置GhostCollection,并将其添加到SharedData下。客户端和服务端都需要了解当前的Ghost。
右键SharedData,选择Create Empty,将新建的GameObject命名为GhostCollection,添加GhostCollectionAuthoringComponent组件。
在组件中点击Update ghost list按钮,然后点击Generate collection code按钮。
五、建立连接
服务器开始监听连接,客户端连接至服务端,并标记为“游戏中”,开始发送快照。此案例只需简单编码使游戏启动即可。在Assets文件夹下创建Game.cs文件,并输入以下代码。
Game.cs:
注:原文可能未直接在OnCreate方法中添加连接逻辑,这是因为当系统发现断开连接时,只需重新CreateEntity触发连接,这也是一种系统间触发方式。官方可能要求我们完成这样的任务。
客户端需要告诉服务端已准备好开始游戏,使用NetCode提供的Rpc功能实现。
在Game.cs文件中,添加如下的 RpcCommand来告知服务端已准备好开始游戏:
注:别忘了在InvokeExecute前添加BurstCompile属性。
为了使用NetCode发送此RpcCommand,需在Game.cs中增加一个继承自RpcCommandRequestSystem的系统。
注:类里无需添加额外内容,若想传输其他RpcCommand无需重写override,直接继承RpcCommandRequestSystem并替换<>内的类型即可。
接下来,创建一个实现ICommandData接口的结构体,负责序列化和反序列化输入信息。创建CubeInput.cs脚本文件,并输入以下代码:
原文代码(现有版本0.1.0-preview6下已无法使用,下面提供基于0.1.0-preview6 API修改的代码):
0.1.0-preview6版本下的代码:
注:简要解释序列化与反序列化过程。序列化是从内存数据提取为网络传输或本地存储的string或Byte[],反序列化是读取数据并存储到内存、触发对应方法的过程。在实时游戏环境中,Unity NetCode提供DataStreamWriter与DataStreamReader让我们自己组装序列化与反序列化工作,而非完全接管。
命令流包含当前tick与水平、垂直的速度,类似之前的Rpc,可使用创建并继承系统的方式来同步ICommandData接口数据。
接下来,编写一个获取输入信息、将信息发送出去的系统:
注:部分读者可能找不到EnableNetCubeGhostReceiveSystemComponent问题。使用GhostCollectionAuthoringComponent生成代码,类名默认为项目名称,若未更改NamePrefix,则类名应为{ 项目名称 } + GhostReceiveSystemComponent。修改NamePrefix后,类名应为{ NamePrefix} + GhostReceiveSystemComponent。
译者碎碎念:官方似乎喜欢使用单例component来传递信息?
最终,创建一个读取CommandData的系统,并移动玩家方块:
六、最后一步
最后一步是创建一个连接成功时使客户端进入游戏状态、通知服务端也进入游戏状态的系统,需要在连接时向服务器发送Rpc表示客户端已准备开始游戏:
在服务端上,确保在收到GoInGameRequest时为该玩家创建并生成一个Cube。
注:部分读者可能找不到NetCubeGhostSerializerCollection问题。使用GhostCollectionAuthoringComponent生成代码,类名默认为项目名称,若未更改NamePrefix,则类名应为{ 项目名称 } + GhostSerializerCollection。修改NamePrefix后,类名应为{ NamePrefix} + GhostSerializerCollection。
七、测试
现在,已完成代码编写,打开Multiplayer> PlayMode Tools并设置PlayMode Type为Client&Server。进入播放模式。生成Cube,并按下A、S、D和W键移动Cube。
回顾所做的工作:
《Unity_API解析》 第十章 Rigidbody类
Rigidbody类是Unity中用于模拟物理特性的组件,包括重力、阻力、质量等。脚本的OnFixedUpdate方法中常赋值Rigidbody对象属性。
Rigidbody类实例属性包括:
1. collisionDetectionMode:碰撞检测模式,有Discrete(默认)、Continuous、ContinuousDynamic三种,可防穿越。
2. drag:刚体阻力,drag值大,速度减慢快。
3. inertiaTensor:惯性张量,影响刚体倾斜方向。
4. mass:刚体质量,一般取值在0.1附近,最大不超过,以免模拟不稳定。
5. velocity:刚体速度,单位为米每秒。
Rigidbody类实例方法包括:
1. AddExplosionForce:模拟爆炸力,参数包括爆炸点、作用力大小和有效半径等。
2. AddForceAtPosition:为刚体点增加力,参数包括力、作用点坐标和力的作用方式。
3. AddTorque:刚体添加扭矩,参数为扭矩向量和力的作用方式。
4. ClosestPointOnBounds:爆炸点到刚体最短距离。
5. GetPointVelocity:获取刚体点速度。
6. GetRelativePointVelocity:获取刚体点相对速度。
7. MovePosition:刚体位置移动。
8. Sleep/WakeUp:使刚体进入休眠状态或唤醒。
9. SweepTest/SweepTestAll:探测碰撞器。
关键属性和方法如useGravity(决定是否接受重力)、isKinematic(决定是否接受动力学模拟)和密度(与质量的计算关系)需注意。力的作用方式通过ForceMode枚举控制,包括默认、加速、瞬时和速度变化四种。
通过理解Rigidbody类的属性和方法,开发者可以更精确地模拟物理效果,增强游戏或应用的真实感。
C#/Unity3D 入门 SourceGenerator
C# Source Generators是一种在编译时生成额外C#代码的机制,旨在简化代码生成和提高性能。它们只添加代码,不修改已有代码,确保安全。下面将引导您如何在Unity中使用Source Generators以及它们的基本概念和API。
在Unity项目中使用Source Generators并不推荐,可新建一个控制台项目存放Source Generators代码。选择.NET Standard 2.0作为项目类型,注意目前只支持此版本。打开项目文件.csproj,添加`true`标签。安装所需的NuGet包,确保版本兼容,目前Unity中仅支持3.8.0。
在生成器项目中,创建新的类,并添加`Generator`或`Generator[LanguageName.CSharp]`特性。实现`ISourceGenerator`接口。避免详细讨论源生成器API,后续会提供更详细的说明。遇到警告时,检查Roslyn编译器版本,确保符合NuGet包要求,可更新Visual Studio或降低版本。在VS中切换到发布模式,生成或重新生成项目,得到生成器dll文件,只拷贝此文件至Unity中,注意避免生成器dll进入包中。
在VS中添加内置的RoslynAnalyzer标签,并等待编译,源生成器将出现在项目中的引用->分析器列表中。在C#控制台项目里,直接添加源生成器引用,并手动补上`OutItemType`和`ReferenceOutputAssembly`属性。配置源生成器项目以在生成后自动拷贝到特定目录,使用bat脚本实现。
源生成器入门包括概述、表达式、语句、命名空间和引用的基本概念。了解这些概念有助于掌握源生成器的使用。初始化方法`Initialize`主要注册`SyntaxReceiver`以遍历语法节点,执行方法`Execute`则具体编写生成过程,围绕`context`进行操作。理解`SyntaxReceiver`、`context.AdditionalFiles`、`context.ParseOptions`、`context.AnalyzerConfigOptions`和`context.Compilation`属性有助于实现源生成器的功能。使用语法树(Syntax Tree)构建和操作代码是核心任务,通过查找和手动创建节点,将生成的源代码加入上下文参与编译。
若担心语法树构建过程复杂,可采用更简单的字符串拼接方式生成代码,避免名称冲突时使用`global::System.Buffers`进行引用,以防止与其他代码冲突。通过逐步学习和实践,源生成器将帮助您更高效地管理C#代码生成任务。
如何为 Unity 项目的 C# 代码生成 API 文档
编写代码时,注释往往被视作文档的来源。然而,编写和维护API文档却是一件耗时且繁琐的工作。为了解决这一问题,本文将介绍一种快速生成C#代码API文档的方法。
传统的API文档维护方式是直接在代码注释中编写文档,以减轻额外工作。然而,如何确保注释格式一致并易于提取成为关键。DocFX是一个优秀的工具,能够将代码注释自动转换为API文档。
使用DocFX,首先需要按照特定格式在代码注释中添加文档信息。以C#为例,常用的注释格式如下:
/// 描述函数或方法的主要功能
/// 参数描述
/// 返回值描述
确保在敲出“///”时,IDE会自动生成这一格式。推荐使用VSCode并启用“Editor: Format On Type”选项。
为了将Unity项目中的C#代码转换为API文档,只需在项目根目录下执行相关命令。命令执行后,会在根目录生成一个名为“docfx_project”的文件夹,用于存储生成的文档。
注意:默认配置会仅生成具有命名空间的API文档。生成的文档位于“docfx_project/_site”文件夹中,并且会启动一个本地网页服务以方便访问。
使用DocFX不仅限于Unity项目,所有C#代码均可利用其生成API文档,前提是代码注释遵循统一格式。通过标准化的注释格式,代码文档的生成变得高效且易于维护。
unity可以用python写脚本吗?
Unity确实支持使用Python编写脚本,这是一个常见的疑问。
具体方法有两类:首先,你可以选择使用IronPython,这需要一定的C#基础。只需启动IronPython,这一C#包即可完成工作。
其次,你还可以通过重新编译Python解释器的方法。然而,这种方法对于大多数用户来说难度较大,因为编译后你需在Python环境中声明所有UnityAPI。
综合考虑,直接学习C#知识可能更为可行。在遇到后续开发中出现的许多坑时,你可能后悔选择使用Python编写Unity脚本。再者,一旦你熟悉了C#并使用过宇宙第一IDE,你或许会逐渐放弃使用Python编写Unity相关的内容。
用Unity实现FXAA
为了在Unity中实现FXAA,我们将从零开始构建一个抗锯齿解决方案,以改善游戏画面的清晰度。首先,我们需要设定一个测试场景,将游戏视图的缩放比例调整至2倍,以便于观察画面锯齿的严重程度。通过观察,我们发现锯齿现象明显,接下来,我们将逐步实现FXAA功能以解决这一问题。
FXAA的核心原理是通过降低整个画面的对比度,以消除锯齿和孤立像素。我们可以通过计算像素亮度来实现这一目标。为此,我们创建一个后处理效果,并使用Unity内置的API LinearRgbToLuminance计算画面中每个像素的亮度。
有了亮度信息后,我们接下来需要计算对比度。具体而言,我们选取当前像素周围上下左右四个像素的亮度值,分别求出它们的最大值和最小值,并计算出最大值与最小值之差作为当前像素的对比度。
为了过滤掉对比度较低的像素,我们设定绝对阈值和相对阈值来剔除那些亮度差异较小或与周围像素相比差异不明显的像素。接下来,我们考虑如何根据对比度对像素进行融合。显然,对比度越高的像素,融合的比例越高。我们采用融合系数来实现这一过程,并对邻近像素进行融合,同时考虑对角像素的权重。
为了使融合系数更加平滑,我们引入了smoothstep和square等技巧。在融合过程中,我们首先需要将tex2D替换为tex2Dlod以避免纹理映射带来的干扰。然后,我们使用纹理过滤自动进行融合,使采样点位于两个像素之间,并根据融合系数调整采样点与两个像素的距离。
为了动态调整FXAA的强度,我们还可以引入一个外部参数来控制融合系数。这样,我们便能观察到在不同融合强度下的画面效果。
在实现分隔线查找时,我们通过计算当前像素和分隔线另一侧像素的亮度平均值,作为分隔线的亮度。然后,我们沿着这条线向两端进行采样,直到找到亮度差异明显的位置,即分隔线的末端。我们设定每端的最大查找次数为次。在超过最大迭代次数后,我们可能会向前步进一个步长,作为预测结果。
在确定融合系数时,我们考虑两个因素:靠近端点的像素融合系数较大,且端点像素的亮度应在分隔线的同一侧。最后,我们结合两种计算方式得到的融合系数,采用max作为最终效果。