- 博客(53)
- 收藏
- 关注
原创 MRTK 2.8.3
(3)ConstraintManager:约束管理器(限制某些操作),可添加自带约束,也可添加自定义约束(创建一个继承自TransformConstraint的脚本,并实现抽象的 ConstraintType属性和抽象的ApplyConstraint方法)MaintainApparentSizeConstraint:被附加到对象时,无论对象与用户有多远,它都将保持与用户相同的表面大小(即它将占据用户视野的相同比例)。这适用于盖板或面板,因为它可确保被操作对象始终向用户显示与操作开始时相同的人脸。
2024-07-01 10:39:25 453
原创 XR Interaction Toolkit
XRSocketInteractor:用于通过套接字保存可交互对象(套接字被定义为特定可交互对象的目标,例如钥匙的锁孔或电池的电池插座。XRSimpleInteractable:最简单的交互对象,只是有一个具体的交互实现,一般用在对交互事件进行响应,没有实际的交互手段(静态物体)XRDirectInteractor:用于直接与接触的交互设备进行交互的交互器(物体添加碰撞体并开启IsTrigger)XRInteractionGroup:交互者的中介,一次只允许组中的一个交互者进行交互(悬停或选择)
2024-07-01 10:37:02 386
原创 Unity小知识
6.Preset可以保存组件对象属性的资源,选择某个Preset文件(如XROrigin),点击Add to XROrigin default,则以后物体添加这个脚本,会自动覆盖XROrigin的值。(3)Gizmos.DrawLine()画线(代码随意挂载,需要放在OnDrawGizmos或OnDrawGizmosSelected函数中[显示在Scene视图,Game视图若开启了Gizmos,也能显示])此外,需要实时更新反射效果并且人物会移动,反射探针应作为人物的子物体。
2024-07-01 10:32:31 305
原创 Unity如何使用adb工具安装APK
3、使用数据线连接设备,查看设备信息(设备需进入开发者选项,打开USB调试,并允许应用安装)把platform-tools的路径添加进去就行。打开cmd,输入adb,即可查看版本信息。路径可直接通过拖拽apk文件生成。
2024-05-08 15:30:50 500
原创 Dynamic Water Physics 2动态水系统使用指南
1.任何处于活动状态并带有WaterObject组件的物理对象都将与水交互,WaterObject工作的两个要求:刚体和网格过滤器(MeshFilter)。刚体不必与WaterObject在同一个物体上,但必须存在于其父物体之一。这允许使用复合对象:一个刚体有多个船体——比如三体船。2.设置可与水交互的物体,可添加WaterObjectWizard脚本(处理所有的浮力和流体动力学计算),然后点击Auto-Setup。
2024-03-13 16:12:21 1485
原创 Unity 离谱报错(Bug)大全(持续更新)
1.坐标2022.3.20f1,未运行情况下报错:RenderTexture.Create failed: width & height must be larger than 0。解决办法:调整窗口布局。
2024-03-07 09:03:07 869 1
原创 Addressable使用指南
如果勾选了Include Build Settings Scene,那么所有Build Setting中的场景都会被打包成AssetBundle,被打包的场景不应该再在Build Setting中加载,否则会造成重复加载。每次修改远程加载路径等一系列配置,都必须清除缓存,清除.json(保存了加载地址)和.hash文件,重新打包,并且配置地址时注意前面不能有空格(或者直接编辑.json文件中的路径)如果删除了缓存,又会从服务器中读取。3、想要资源与程序分开,也就是跨工程加载资源,可以参考这位老哥的做法。
2023-10-22 14:06:02 582
原创 Steam VR Plugin 2.7.3爬坑指南
(5)导入插件之后,无论运行哪个场景,都会自动打开Steam VR,很多时候这不是我们想要的,可以在Project Setting->XR Plug-in Management → Initialize XR on Startup取消勾选(不用VR的时候最好禁用,否则可能出现相机画面正常而Game视图中看不见物体的情况)有些解决了,有些没有,等待后续更新或者有好心人指点一下啊,进入正题。(1)导入插件之后,运行示例场景,那两只手跟打了兴奋剂一样飞来飞去,重复导入数次无果,关键有些工程中又不会。
2023-09-19 15:00:18 744 1
原创 Quaternion常见方法
(4)SetFromToRotation(Vector3 fromDirection, Vector3 toDirection),创建一个从向量fromDirection到向量toDirection的旋转(首先将对象自身坐标系x、y、z轴方向和世界坐标系的x、y、z轴方向一致,然后将对象自身坐标系中fromDirection指向的方向旋转到toDirection)(2)SetLookRotation(Vector3 v1),设置Quaternion实例的朝向(Z轴)与向量v1指向的方向相同。
2023-04-10 10:51:28 385
原创 UGUI中不同Render Mode下的坐标问题
当使用Screen Space-Camera,若未指定Render Camera,那么可以正常通过Input.mousePosition来获取当前屏幕中的鼠标位置,并应用在UI上(比如UI跟随鼠标)。若指定了相机,就必须使用。同样,Camera.main.WorldToScreenPoint无法获取真正的UI屏幕坐标系。使用Camera.main.WorldToScreenPoint获取ScreenPoint。获取UIpoint(这是LocalPosition)。来转换到UIcamera的世界坐标系。
2023-03-17 14:43:18 148
原创 输出exe遇到错误:ArgumentNullException: Value cannot be null. Parameter name: shader
出现这种情况就是缺少了某些Shader,在Editor-Project Settings-Graphics中,找到对应缺失的Shader添加即可。
2023-03-03 09:24:04 1362
原创 单方向缩放物体的方法
Unity的缩放功能是整体缩放,想要有单边缩放的效果,需要做一些特殊处理。以下方法前提是物体缩放方向必须等宽,否则效果不佳。(3)将这个游戏对象作为这个空游戏对象的子对象。现在,尝试缩放空的游戏对象,它将在一个方向上缩放。(2)移动要缩放的游戏对象,使空游戏对象的中心位于您要缩放游戏对象的边缘。(1)创建一个空的游戏对象并重置位置、比例。2.缩放物体的同时进行位移。
2023-03-02 15:07:26 793
原创 80.用Task代替ThreadPool
你也许会奇怪,我们的任务是通过Cancel的方式处理的,为什么完成的状态IsCanceled那一栏还是False。在任务结束求值的方法TaskEndedByCatch中,如果任务是通过ThrowIfCancellation Requested方法结束的,对任务求结果值将会抛出异常OperationCanceledException,而不是得到抛出异常前的结果值。ContinueWith方法可以在一个任务完成的时候发起一个新任务,这种方式天然就支持了任务的完成通知:我们可以在新任务中获取原任务的结果值。
2023-02-07 13:39:45 91
原创 93.构造方法应初始化主要属性和字段
类型的其他引用类型字段也应该在构造器中初始化,比如specialB,因为需要保证类型的其他地方用到该字段的时候不会因为它是null而产生混淆。在构造方法中,必须首先为CEO赋值。因为只要存在公司实体,那么它首先就会有一个CEO。类型的属性应该在构造方法调用完毕前完成初始化工作。如果字段没有在初始化器中设置初始值,那么它就应该在构造方法中初始化。类型一旦被实例化,那么它就应该被视为具有完整的行为和属性。上面演示的是一个字段初始化。也就是说,可以将初始化器理解为构造方法的一部分。,它在经编译后,在构造方法的。
2023-02-07 10:20:49 124
原创 101.使用扩展方法,向现有类型“添加”方法
我们也许会考虑修改设计,直接修改sealed类型,然后为其发布一个新的版本,但这依赖于你拥有全部的源码。值得注意的一点是,扩展方法还能够扩展接口。它相当于让继承自IEnumerable接口的任何子类都拥有了Select方法,而这些Select方法在调用者看来,就好像是IEnumerable接口所声明的一样。但是我们知道,可以有更优美的形式让调用者像调用Student类型的实例方法一样来调用GetSexString了。(3)扩展方法的第一个参数必须是要扩展的类型,而且必须加上。
2023-01-30 15:58:36 74
原创 103.区分组合和继承的应用场合
到目前为止,似乎一直在说继承的优点。一个类,如果其继承体系达到3层(当然,凡事都有例外,WPF体系中的控件集成体系,以Shape为例,多达7层),就可以考虑停止了。随着项目的发展,组合的优势会逐渐体现出来,它良好的封装性使类型可以对外宣布:我只做一件事。从设计的角度来看,继承代表的是“Is a”,组合代表的是“Has a”。如果组合太多的类型,就意味着当前的类很可能做了太多的事情,它就需要拆分成两个类了。继承不具有这样的特性,在C#中,子类只能有一个基类(接口则放开这种限制,子类可以继承自多个接口)。
2023-01-30 15:18:30 287
原创 106.为静态类添加静态构造函数
比较理想的做法是,在类型SampleClass的内部对fileStream进行初始化。在上面的代码中,如果类型初始化不成功,会在类型的内部处理完毕,并不会将异常抛给调用者。因为有时候调用者甚至都不知道类型需要初始化什么内容,所以将初始化失败的异常处理交给上层是不合理的。使用静态构造方法的好处是,可以初始化静态成员并捕获在这过程中发生的异常。静态类可以拥有构造方法,这就是静态构造方法。(2)代码无法调用它,不像实例构造方法使用new关键字就可以被执行。对静态引用类型的初始化应该使用静态构造方法。
2023-01-30 14:51:47 385
原创 111.避免双向耦合
双向耦合在同一项目下,不会存在太多的问题,带来的只是设计问题。不过,如果两个类在不同的项目中时,就必须考虑解耦了,因为.NET不允许项目之间相互引用。一般来说,类型之间不应该存在双向耦合,如果有此类情况出现,则应该考虑重构。在类型B中,我们针对接口编程,也就是说,在B中的字段a不再是A类型,而是将其修改为ISample类型。如果A、B类型分别在两个项目中,则提炼出来的接口要放在新起的项目中,然后让A、B所在的两个项目分别引用这个接口所在的项目。在实际的编码中,可以考虑使用这些框架设计我们的项目。
2023-01-29 17:31:02 84
原创 126.用名词和名词组给类型命名
类型对应着现实世界中的实际对象。对象在语言中意味着它是一个名词。所以,类型也应该以名词或名词词组去命名。类型定义了属性和行为。虽然它包含行为,但不是行为本身。动词类的命名更像是类型内部的一个行为,而不是类型本身。
2023-01-29 17:20:38 79
原创 128.考虑让派生类的名字以基类名字作为后缀
Exception及其子类就是这样一个典型的例子。所有的异常都应该继承自System.Exception。派生类的名字可以考虑以基类名字作为后缀。这带来的好处是,从类型的名字上我们就知道它包含在哪一个继承体系中。在FCL中,这类常用的例子还有Attribute、EventArgs等。从这里我们可以看出,微软支持让派生类的名字以基类名字作为后缀。
2023-01-29 17:14:06 68
原创 129.泛型类型参数要以T作为前缀
我们在使用SampleMethod方法的时候,如果将类型的泛型由T改为Person,很容易在类型内部会不自觉人为Person是一个类型,而不是一个泛型。而SampleMethod2带来的困扰就会少一些,因为泛型在使用它的地方被声明了。当然,无论如何,我们都不应该为泛型指定一个模棱两可的命名。记住,只要是泛型,就应该以T作为前缀命名。当然,这仅仅是一种习惯,若果使用第二种命名方式,编译器并不会报错,但是作为调用者,也许不能意识到这里是一个泛型类型参数。作为一种约定,泛型类型的参数要以T作为前缀。
2023-01-29 17:08:06 259
原创 133&131.用camelCasing命名私有字段和局部变量,用PascalCasing命名公开元素
我们可以看到,所有私有字段,包括方法的参数及局部变量全部遵循首字母小写的cameCasing规则。一旦脱离了这种规则,在编码过程中很容易给自己造成混淆。私有变量和局部变量只对本类型负责,它们在命名方式也采用和开放的属性及字段不同的方法。之所以要采用这两种不同的命名规则,是为了便于开发者自己快速地区分它们。camelCasing和PascalCasing的区别是它的。我们首先会怀疑name是什么类型,其次也会怀疑其可访问性。
2023-01-29 16:52:06 197
原创 134.有条件地使用前缀
各类设计规范也总建议我们保持一个娇小的类型,但是往往事与愿违,大类型常常存在。在这种类型中,如果不使用前缀,我们很难区分一个类型是实例变量还是静态变量,或者是一个const变量。在这个例子中,我们知道,即使类型本身不是很长,但是存在方法参数和类型实例变量重名的情况下,为实例变量或者静态变量使用前缀也是必要的。注意,有时候,如果类型只有实例变量或者只有静态变量,我们也直接使用前缀,以区别该变量不是一个局部变量。最典型的前缀是m_,这种命名一方面是考虑到历史沿革中的习惯问题,另一方面也许我们确实有必要这么做。
2023-01-28 11:22:47 65
原创 135.考虑使用肯定性的短语命名布尔属性
肯定性形容词或者短语虽然表达了一个肯定的含义,但是这些单词或者短语现在都被用于命名事件或者委托,所以不应该用于布尔属性。布尔值无非就是True和False,所以应该用肯定性的短语来表示它,例如,以Is、Can、Has作为前缀。
2023-01-28 10:42:30 82
原创 137.委托和事件类型应添加上级后缀
如果用传统方式,我们可能看不出来这些类型是有基类的,但是委托和事件的关键字delegate和event已经指明了后面类型的基类是Delegate。委托按照委托类型的作用又单纯分为Delegate结尾和CallBack结尾,我们在声明委托的时候一定要注意区分这一点。委托类型本身是一个类,考虑让派生类的名字以基类名字作为后缀。事件类型是一类特殊的委托,所以事件类型也遵循本建议。,则使用CallBack结尾。
2023-01-28 10:34:58 67
原创 150.使用匿名方法、Lambda表达式代替方法
上面的代码中,SampleMethod方法需要完成的功能是查看list中有没有长度等于5的元素。Predicate是一个委托,它接收元素值,并返回元素是否符合要求这一结果。而真正工作的代码只有1行。引领的语句就是一个匿名方法。其次,匿名方法经过编译器编译之后,就和普通方法没有任何区别了。匿名方法带来的只是简化程序员的部分工作而已。方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐。更好的简化方法就是Lambda表达式。”连接(读作“goes to”),符号。左边是参数列表,右边是方法体。
2023-01-28 09:50:25 70
原创 Unity编辑器扩展使用总结
编辑器扩展这块,网上能搜到的大多是基础api讲解或者各种copy,至少我找许久也没找到实用的例子,没办法只能自己边搜边查api了。使用下来,发现还是得亲手实践做些小工具,否则光知道那些方法,真的使用的时候会发现很多问题,它的实现思路和UGUI还是不太一样的。(3)EditorWindow的控件刷新并不一定是每帧更新,如果希望编辑器界面可以实时响应我们的操作,通过GUI.changed = true来强制刷新界面状态。(4)希望多个控件均匀分布,可使用扩展,如。
2023-01-18 13:41:46 257
原创 71.区分异步和多线程应用场景
是的,上面的程序解决了界面阻滞的问题,但是,它高效吗?当开始I/O操作的时候,异步会将工作线程还给线程池,这时候就相当于获取网页的这个工作不会再占用任何CPU资源了。直到异步完成,即获取网页完毕,异步才会通过回调的方式通知线程池,让CLR响应异步完毕。可见,异步模式借助于线程池,极大地节约了CPU的资源。可以预见,如果该网页的内容很多,或者当前的网络状况不太好,获取网页的过程会持续较长时间。为了获取网页,CLR新起了一个工作线程,然后在读取网页的整个过程中,该工作线程始终被阻滞,直到获取网页完毕为止。
2022-12-20 17:42:53 172
原创 58.用抛出异常代替返回错误代码
在catch (CommunicationException)代码块中,代码所完成的功能是“通知发送”,而不是“发送”本身,因为我们需要确保在catch和finally中所执行的代码是可以被执行的。不应该将异常机制用于正常控制流中,异常的发生是一个小概率事件,所以异常带来的效率问题会被限制在一个很小的范围内。在本例中的catch代码块中,不是要真的编写发送邮件的代码,因为发送邮件的这个行为可能会产生更多的异常,而“通知发送”这个行为稳定性更高(即“不出错”)。但是,现在有了另一种选择,既使用异常机制。
2022-12-20 15:38:15 256
原创 53.必要时应将不再使用的对象引用赋值为null
当检测到方法内的“根”时,如果发现没有任何一个地方引用了局部变量,则不管是否已经显式将其赋值为null,都意味着该“根”已经被停止。然后,垃圾回收器会发现该根的引用为空,同时标记该根可被释放,这也代表着类型对象所占用的内存空间可以被释放。但是,在另一种情况下,却要注意及时地将变量赋值为null,那就是类型的静态字段。在CLR托管的应用程序中,存在一个“根”的概念,类型的静态字段、方法参数、以及局部变量都可以作为“根”的存在(值类型不能作为“根”,只有引用类型的指针才能作为“根”)。中c1 = null;
2022-12-20 15:08:35 163
原创 40.使用event关键字为委托施加保护
这应该是不允许的,因为什么时候通知调用者,应该是FileUploader类自己的职责,而不是调用者本身来决定的。event关键字正是在这种情况下被提出来的,它为委托加了保护。事件“MyTest.FileUploader.FileUploaded”只能出现在 += 或 -= 的左边(在类型“MyTest.FileUploader”中使用时除外)以上代码将编译不通过。
2022-12-15 15:25:22 73
原创 38.小心闭包中的陷阱
所谓闭包对象,指的是上面这种情形中的TempClass对象(在第一段代码中,就是编译器为我们生成的c__DisplayClass2对象)。如果匿名方法(lambda表达式)引用了某个局部变量,编译器就会自动将该引用提升到闭包对象中,即将for循环中的变量i修改成了引用闭包对象的公共变量i。这样,即使代码执行离开了原局部变量i 的作用域(如for循环),包含该闭包对象的作用域还存在。这段代码并不像我们想象的那么简单,要完全理解运行时代码是怎么运行的,首先必须理解C#编译器为我们做了什么。
2022-12-15 14:54:11 143
原创 37.使用Lambda表达式代替方法和匿名方法
使用匿名方法后,我们就不需要再Main方法外部声明两个方法了,可以直接在Main这个工作方法中完成所有代码编写,而不会影响代码清晰性。,其本质是匿名方法。实际上,经过编译后的Lambda表达式就是一个匿名方法。我们应该在实际编码中熟练运用它,避免出现繁琐且不美观的代码。实际上要完成相同的功能,还有很多种编码方式。注意:上面的语法虽然繁琐,但是我们可以从中加深对委托本质的认识:委托也是一种。Lambda表达式操作符“=>”的左侧是。,跟任何FCL中的引用类型没有差别。),我们都建议采用这种方式来编写。
2022-12-15 10:13:55 262
原创 36.使用FCL中的委托声明
在FCL中每一类委托声明都代表一类特殊的用途,虽然可以使用自己的委托声明来代替,但是这样做不仅没有必要,而且会让代码失去简洁性和标准性。在我们实现自己的委托声明前,应该首先查看MSDN,确信有必要后才这样做。FCL中存在3类这样的委托声明,它们分别是:Action、Func、Predicate。注意:很少方法的参数能够超过16个,如果真有这样的参数,首先要考虑自己设计是否存在问题。Action的重载版本有17个,最多参数的重载有16个参数。Func的重载版本有17个,最多参数的重载有16个参数。
2022-12-15 09:33:38 82
原创 34.为泛型参数设定约束
但是,在添加了约束后,我们会发现参数t1和t2变成了一个有用的对象。“约束”这个词可能会引起歧义,有些人可能认为对泛型参数设定约束是限制参数的使用,实际情况正好相反。没有“约束”的泛型参数作用很有限,倒是“约束”让泛型参数具有了更多的行为和属性。在编程过程中应该考虑为泛型参数设定约束,约束使泛型参数成为一个实实在在的“对象”,让它具有了我们想要的行为和属性,而不仅仅是一个object。(7)可以对同一类型的参数应用多个约束,并且约束自身可以是泛型类型。(4)指定参数必须是指定的基类,或者派生自指定的基类。
2022-12-13 17:36:55 84
原创 104.用多态代替条件语句
随着DriveCommand元素的增加,采用if或switch语句将带来可怕的混乱状态是显而易见的。在一个复杂的控制系统中,命令可能会多达上百条。原来的设计理念也是欠妥当的,它不遵守设计模式中的“开闭原则”。开闭原则是指:对扩展开发,对修改关闭。遵从开闭原则的一次重构是,使用多态来规避不断膨胀的条件语句。可见,代码简洁了不少,而且,可扩展性增强了。即使未来还需要增加命令,扩展相应的子类就可以了。而且我们关闭了修改,即对Drive方法,即使增加再多的命令,也不需要对其进行修改。假设要开发一个自动驾驶系统。
2022-12-13 14:44:24 87
原创 149.使用表驱动法避免过长的if和switch分支
枚举元素代表的整型值,很容易和字符串数组索引结合起来,用两行语句就解决了GetChineseWeek方法。但是,这种方法有局限性,如果需要换成:星期一Mike打扫卫生、星期二Rose清理衣柜、星期三Mike和Rose没事可以吵吵架、星期四Rose要去Shopping,也就是说需求由静态属性变成了动态行为,那么事情就变得复杂了。当然,星期制已经是固定的了,应该不会出现扩展情况。如果增加条件分支,不必修改源代码,直接增加子类就可以了。利用多态避免分支,详见建议104,本建议要采用的是“表驱动法”。
2022-12-13 14:39:56 111
原创 21.选择正确的集合
在命名空间System.Collections.Concurrent下,还涉及几个多线程集合类:ConcurrentBag、ConcurrentDictionary、ConcurrentQueue、ConcurrentStack,分别对应List、Dictionary、Queue、Stack。队列Queue遵循的是先进先出模式,它在集合末尾添加元素,在集合的起始位置删除元素。,就是相互之间存在一种或多种特定关系的数据元素的集合。
2022-12-13 10:43:49 80
原创 1.正确操作字符串
当然,我们需要注意,StringBuilder指定的长度要合适,太小了,需要频繁分配内存;对CLR来说,string对象(字符串对象)是个很特殊的对象,它一旦被赋值就不可改变。在运行时调用System.String 类中的任何方法或进行任何运算(如“=”赋值、“+”拼接等),都会在内存中创建一个新的字符串对象,这也意味着要为该新对象分配新的内存空间。在使用其他值引用类型到字符串的转换并完成拼接时,应当避免使用操作符“+”来完成,而应该使用值引用类型提供的ToString方法。[会分配新的堆内存]
2022-12-13 09:04:27 53
Shiny SSRR 2 - Screen Space Raytraced Reflections
2024-04-15
Multi Projector Warp System
2024-04-15
动态水系统插件 Dynamic Water Physics 2 v2.4.2
2024-03-19
RuntimeTransformGizmos.unitypackage
2023-07-10
Unity天气系统(Enviro - Sky and Weather)插件
2023-06-12
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人