unity为什么更改unity inspectorr里的Sensitivity了,测试的时候灵敏度还是没变

50个Unity的使用技巧_游戏蛮牛-爱微帮
&& &&& 50个Unity的使用技巧
关于这些技巧这些技巧并不是适用于每一个项目。1.基于我的经验它们适用于3到20人的小团队。2.一些结构性,重用性,清晰度等等上的技巧使用需要付出性能上的开销代价,根据你团队和项目的大小来决定是否需要付出这些开销代价。3.许多技巧的选择可能会有自己不同的喜好(它们可能有对比,但是这里列出来的都是可用的好技术)4.一些技巧可能和Unity官方提倡的用法大相径庭。例如,规模化的使用预设相对于使用实例来说是Unity官方不提倡的,开销的代价非常大(使用大量预设的时候)。然而我看到这些技巧能够带来很好的结果,即使它们看起来很疯狂。今天将给大家介绍前5个技巧,一共50个,Are you ready?进程1.避免资源分支。任何之源都应该只能有一个版本。如果你一定需要分支预设,场景或者网格,那就遵循一个清晰的进程已确定正确版本。“错误”分支都有个扯淡的名字,例如,使用双下划线作为前缀:__MainScene_Backup.预设分支需要一个特定的流程保证它们使用的安全(请看下面的预设部分)。2.每个团队成员都应该拷贝一份工程出来当做测试使用。如果你们使用项目版本控制。工程有更改时,这份清晰的拷贝工程要及时更新测试。没人应该去更改清理的拷贝工程。这对解决丢失资源非常有用。3.考虑使用外部关卡编辑器来编辑关卡。Unity不是一个完美的关卡编辑器。例如,我们使用TuDee来创建关卡编辑,这受益于我们使用tile-friendly工具(拍摄网格,多个90度的旋转,2D视角)。直接从XML文件初始化预设。关于&Guerrilla Tool Development的更多信息请访问原文。4.考虑把关卡信息储存在XML文件中而不是在场景里。这是个很棒的技巧:& && &1.这样可以避免在每个场景都重构数据。& && &2.这样加载更快(如果大多数场景对象之间共享)。& && &3.这样更容易合并场景(即使使用Unity新特征中的基于文本的场景,无论如何仍然有大量的数据在融合时不好实行)。& && &4.这样更容易追踪跨级别的数据。你仍然可以把Unity当做关卡编辑器使用(尽管你不需要。)你需要写一些代码序列化和反序列化你的数据,在游戏编辑和启动的时候加载关卡数据,并在关卡编辑器中储存数据。你可能还需要模仿Unity的ID系统来维护对象之间的引用。5.考虑使用泛型定义检查器代码。编写自定义检查器十分简单,但是Unity的系统有许多弊端:& && &1.不支持利用继承。& && &2.不支持定义一个字段类型的检查器组件,只支持类类型。例如,如果每个游戏对象都有一个字段类型SomeCoolType,你想让它在检查器面板中不同的显示,你就必须在你的所在类里写检查器。你可以从底层重新实现检查器系统来解决这个问题。使用反射的一些小窍门,这并没有看起来那么困难,细节在文章的最后章节有提供。组织场景6.使用命名为空的游戏物体作为场景文件夹。仔细组织你的场景便于更容易地查找相关对象。7.把相关预设和场景文件(empty game objects)放在(0, 0,0)点。如果一个transform不是专门用来确定物体的位置,那么应该把它放到远点。那样可以在处理当前和世界坐标系的问题时少出问题,而且代码十分简单。8.减少使用有偏移量的GUI组件。偏移量只应该在父容器里布局组件时使用;不应该让它们依靠祖父类来定位。偏移量不应该取消正确的相互显示。它基本上时为了防止类似以下这种情况:父容器任意定位到(100,-50)。子类,应该定位在(10,10),然后相对于父容器来说就定位在(90, 60)。当容器不可见或者无可视化表示的时候这种错误很容易出现。9.把你的世界场景地板坐标 y值设为0。这样把对象放到场景地板上时会更加简单,游戏逻辑,AI和物理特性可以把它们当做2D场景世界来处理。10.运行游戏的每个场景。这大大的减少了测试时间,让所有的场景都运行你需要做两件事:首先,提供一种方法来模拟之前需要加载的不可用的场景数据。其次,对象的产生必须保持在场景加载中,看一下代码:Art11.把角色和站立对象的基准点放在底部,而不是中间。这样更容易把角色和对象精确地放到场景层上。也更容易在游戏逻辑、AI甚至物理特性上适当的当做2D方式来处理。12.让所有网格的朝向保持一致(Z轴正向或负方向)。这适用于类似角色和其他有朝向概念的对象网格。如果所有物体的方向保持一致可以简化算法。13.一开始把scale属性设置好。可以把它们的缩放因子scalefactor设置为1,然后把transforms的缩放设置为1,1,1。使用一个对象引用(比如一个立方体)可以让缩放比较更容易。14.做一个plane 用作GUI组件或手动创建粒子。让plane面向Z轴正向可以更简单的使用公告牌属性、更便捷地生成GUI。15.制作和测试美术资源。& && &1.给场景加入天空盒。& && &2.网格。& && &3.各种纯色的shader测试:白色,黑色,50%的灰色,红色,绿色,蓝色,洋红色,黄色,青色。& && &4.渐变色的shader测试:黑到白,红到绿,红到蓝,绿到蓝。& && &5.白色和黑色的调色盘。& && &6.平滑和粗糙的标准贴图。& && &7.测试场景的光照快速设置。预设16.所有资源使用预设。在场景里唯一一个不使用预设的游戏对象就是文件夹。即使只使用一次的特别对象也应该使用预设。这样需要更改的时候只需要改变更改预设而不需要改变场景。(一个额外的好处是,使用EZGUI创建精灵集时更加可靠)17.使用单独的预设组合专业化,不要专门研究实例。如果你有两种敌人类型,只是属性上的不同,使用独立预设区分它们的属性,并把它们联系起来。这样做有可能& && &1.在一个地方就可以对每个类型进行修改& && &2.更改时没必要修改场景18.连接预设;不要连接实例。把预设拖入场景中的时会维持预设间的联系;连接实例则不会这样。任何时候尽可能的连接预设会减少场景的构建以及减少改变场景的需求。19.尽可能让实例之间自动建立连接。如果你需要连接实例,以动态程序简历连接。比如,玩家预设在开始的时候能通过GameManager来注册,或者可以通过GameManager找到玩家预设实例。如果你想添加其他脚本就不要网格添加到预设的底层。当你使用网格构建预设的时候,用一个空的游戏对象作为网格父类,并让它作为最底层根对象。然后把脚本放到这一次,而不是放到网格节点那一层。这种方法可以让你更方便的替换网格而不会失去任何你在inspector中创建的值。使用预设链接替代嵌套预设。Unity不支持嵌套预设,然而第三方解决方案放到团队工作中时又可能存在一定的安全隐患,因为与嵌套预设间的关联不明显。20.对分支预设使用安全进程。以下使用玩家预设作为例子来说明。对玩家预设做出的风险修改如下:& &&&1.复制Player预设。& &&&2.把复制的玩家预设重命名为__Player_Backup.& &&&3.修改Player预设。& &&&4.如果一切正常,删除__Player_Backup.不要命名复制预设 Player_New,对它进行修改!有些情况更复杂。例如,某个修改可能会涉及两个方面,参照上面的进程可能会破坏运行的场景除非做到两点:& & 1.方法1:& && && && &1.复制Player预设.& && && && &2.重命名为__Player_WithNewFeature或者__Player_ForPerson2.& && && && &3.修改复制的预设,然后提交/给 方法2& & 2.方法2:& && && && &1.修改新的预设。& && && && &2.复制Player预设,然后重命名为__Player_Backup.& && && && &3.拖动一个__Player_Backup和__Player_WithNewFeatrue的实例到场景中。& && && && &4.拖动实例到原件Player预设。& && && && &5.如果一切妥当,删除__Player_Backup和__Player_WithNewFeatrue.21.扩展继承至MonoBehaviour的创建类,然后获取所有的组件。这允许你实现一些基本功能,如安全类型调用和其他更复杂的调用(比如随机等)22.定义StartCoroutine和Instantiate的安全方法调用。定义一个委托任务,使用委托代替字符串名字来定义方法。例如:23.使用扩展和组件共享一个接口。有时候为了方便某个组件实现接口,或者通过类似组件寻找对象。使用typeof替代通用版本的这些函数来实现。通用版不使用接口,但是typeof可以。下面的这些方法可以整洁得覆盖通用方法。24.使用扩展让语法更便捷。例如:25.使用GetComponet获取范类型替代。有时候迫使组件依赖关系(通过RequiredComponent)是一种痛苦。例如,使得在inspector中更改组件变得更困难(即使他们有同样的基本类型)。作为一个选择方案,下面的GameObject扩展,在找不到组件并需要打印它的错误信息时使用。26.避免使用不同的方案完成同样的事情。在许多情况下不止一个惯用方法来处理事情。在这种情况下,选择一个在项目中使用,原因如下:&&&& &&1.一些方案并不适合放到一起。在一个方向上使用一种方案来做设计后,可能在使用其他方案就不合适。2.至始至终使用同一方案让团队成员对此的理解更加简单。对工程的构建和代码实现也更容易理解。这样一来就不容易犯错。方案组示例:& && &&&1.协同 vs 状态机。& && &&&2.嵌套预设 vs 连接预设 vs 神预设。& && &&&3.数据分离策略。& && &&&4.在2D游戏里使用精灵的方式。& && &&&5.预设结构。& && &&&6.生成策略。& && &&&7.定位对象的方法:用 类型 vs. 名字 vs. 标签 vs.层级 vs.引用(“链接”)。& && &&&8.编组对象的方法:用 类型 vs. 名字 vs. 标签 vs.层级 vs. 数组引用(“链接”)。& && &&&9.用寻找编组对象与对象注册机制。& && &&&10.控制执行顺序(使用Unity的执行顺序机制与yield逻辑,依赖Awake/Start和Update/LateUpdate一系列方法与方法指南以及其他顺序排列架构)。& && &&&11.在游戏中用鼠标选择objects/positions/targets:选择管理器与自我管理。& && & 12.场景切换时保留了数据:通过PlayerPrefs,或者当加载一个新场景时对象没有被销毁。& && &&&13.动画相结合的方式(混合,添加和分层)。时间27.保持自己的时间类来简化暂停功能。封装Time.DeltaTime和Time.TimeSinceLevelLoad来计算暂停和time scale.按照需求酌情使用,会让开发更加简单,特别是执行多个时间系统时(比如动画接口和游戏游戏动画)。生成对象28.不要在游戏运行时生成对象来打乱你的层级。[size=+0]游戏运行时给场景中的对象设置父容器能更容易找到对象。你可以使用一个空的游戏对象,甚至或者一个没有默认基类的单例都可以很容易的访问代码。我们把这种对象叫做DynamicObjects.类设计29.方便使用单例。下面的类将会使任何类继承至它的单例:单例模式对于管理器非常有用,比如ParticleManager或者AudioManager又或者GUIManager。& && &&&1.避免对不是管理器的单一预设实例使用单例(比如Player).不遵守这个原则会让继承层次变得复杂,改变某个类型也会更加困难。宁愿在GameManager里保持这些引用(或者其他合适的神类别 )& && &&&2.定义静态属性和方法,外部会经常调用这些公共变量。你可以用GameManager.Player代替GameManager.Instance.player.30.对于组件,绝对不要设置公共变量,也不应该在inspector中去调整。否则就会被设计者调整,特别是在不清楚它要干什么的时候。但在一些罕见的情况下这是不可避免的。在这种情况下使用两个甚至或者四个下划线的前缀的变量名来修饰:31.从游戏逻辑中分离接口。这个本质是MVC模式。任何输入控制器只应该给适当的组件发送命令,让它们知道控制器已经被调用。例如在控制器逻辑中,控制器可以根据玩家状态决定发送哪些命令。但是这样也不好(例如,如果添加更多的控制器会导致更多的重复逻辑)。相反,玩家对象应该通知向前移动,然后基于当前状态(例如放缓或不知所措)设置速度,更新玩家朝向。控制器只做涉及他们自身状态的事儿(如果玩家改变状态,控制器不会改变状态,因此,控制器根本不应该知道玩家的状态)。另一个示例是改变武器。正确的做法是用GUI访问Player的一个方法SwitchWeapon(Weapon newWeapon),GUI不应该操作transforms和父类和其他所有东西。任何组件接口都只应该维护与它自己状态相关的数据和进程。例如,显示一个地图,GUI能根据玩家的移动计算怎么显示。然而,这是一个游戏状态数据,不属于GUI。GUI仅仅应该只显示任何应该保留的游戏状态数据。而地图数据应该在任何地方都保留(例如在GameManager里面)。游戏对象几乎对GUI一无所知。暂停行为除外,它可以通过Time.timeScale控制全局(这不是一个好主意,看吧)。游戏暂停的时候所有游戏对象应该能知道。因此,没有游戏对象和GUI组件连接。一般来说,如果你删除所有的GUI类,游戏仍然能够编译。你也应该能够重新实现GUI和输入,而不需要编写任何新的游戏逻辑。32.状态分离和记录。记录变量对快速便捷的开发很有用,也可以恢复到之前的状态。通过分离,你能更便捷的实现:& & 1.储存游戏状态& & 2.调试游戏状态实现它的一个方法是给每一个游戏逻辑类定义一个SaveData类。33.独立的专业化配置。考虑到两种敌人都使用了完全相同的网格,但是不同的扭力(例如不同的力和不同的速度)。有两种方法可以分离数据。有一种方法是我很喜欢的,特别是当有对象生成时,或者游戏储存时(扭力不是状态数据,而是配置数据,所以它不需要被储存。当对象加载或生成时,扭力数据会自动独立加载)& && & 1.给每个游戏逻辑类定义一个模板类。例如,Enemy类,我们也定义一个EnemyTemplate.所有不同类型的扭力值都被储存在EnemyTempate里。& && & 2.在游戏逻辑类中,定义一个模板类型变量。& && & 3.创建一个敌人预设,两个模板预设WeakEnemyTemplate和StrongEnemyTemplate.& && & 4.当加载或者生成对象时,设置模板变量为正确的模板,这个方法十分复杂(有时没必要这么复杂,所以要小心)。例如,更好的利用通用的多态性,我们可能这样定义我们的类:34.不要使用字符串显示文本。特别是不要使用字符串识别对象或者预设等。但是动画例外,通常用字符串访问它们。35.避免使用公共索引链接的数组。例如,不要定义武器数组,子弹数组和特效数组,你的代码看起来应该如下:问题主要不是用代码解决,而是在inspetor中正确设置。相反,定义一个类,封装了三个变量然后创建一个数组:代码看起来很整洁,但是最重要的是,在inspector里设置数据会更加简单。36.避免使用数据结构以外的序列。例如,一个玩家可能有三种攻击方式。使用当前的武器时,各自拥有不同的子弹和不同的行为。你可能想把三种子弹放进数组,然后使用下面这样的逻辑:枚举能让代码看起来更简洁......但不要在设置在inspector面板里。最好使用独立的变量名字来帮助显示哪些内容。封装到一个类里会更简洁。37.序列类中的数据组在inspector设置时更简洁。一些实体类可能会有许多扭力参数。要在inspector中寻找它们是一件可怕的事。跟着以下步骤做,会更简单:& & & & 1.定义一个独立的类,并把公共序列化的变量放到类里。& && &&&2.在主类里,给以前独立类里的每种类型定义公共变量。& && &&&3.不要在Awake或者Start函数里初始化这些变量;这些变量序列化后,Unity会自动处理。& && &&&4.你可以指定默认为像以前一样的赋值定义。这组变量在inspector面板中可以折叠下拉,方便管理。文本38.如果有很多剧情文本,把它放到一个文件夹里。别放到inspector的编辑字段里。这样不用打开Unity的编辑器就能简单修改,尤其是不用保存场景。39.如果你准备做本地化,就单独把所有字符串放到一个地方。有许多方法可以实现。其中一个方法就是给每个字符串都用公共字符串字段定义一个文本类,默认设置为英语,例如,其他语言的子类,用等效重新初始化字段。更可靠的做法是(当文本字体很大或者语言数量很高的时候)读取数据表格,在选择的语言基础上,为选出的正确字符串提供逻辑。测试和调试40.实现一个图形化物理日志记录器来调试图形,动画和AI。这样调试起来相当快。41.实现一个HTML的日志记录器。在某些情况下,记录日志非常有用。有日志更容易解析(颜色编码,多视图,记录截图),也能让记录调试更加愉快。42.实现自己的FPS计数器。是的,没人知道Unity的FPS计数器的真正原理,不是用帧速率。实现自己的计数器,这样可以用更直观可见的检查对应。43.实现屏幕截图的快捷键。很多bug是可以看见的,这时候如果能截图下来就更好做反馈报告。理想的系统应该在PlayerPrefs里保持计数器,这样能成功处理截图而不必覆盖它。截图应该储存在工程外的文件夹里避免开发人员不小心提交到工程库里。44.实现快捷键打印玩家的世界坐标。这样可以更容易报告在特定定法的坐标错误问题,也更容易调试。45.实现调试选项让测试更简单。例如:& && &&&1.解锁所有项。& && &&&2.禁用敌人。& && &&&3.禁用GUI。& && &&&4.让玩家无敌。& && &&&5.禁止所有游戏操作。46.如果是小团队,让每个团队成员组合调试选项。把没有提交的用户标识符放到一个文件夹里,在游戏运行时读取它。原因如下:& & 1.团队成员不会意外提交他们的调试选项而影响其他人。& & 2.修改调试选项不用改变场景。47.保持所有的游戏元素在一个场景。例如,把所有敌人放在一个场景,所有的对象你都能支配,等等。着样更容易测试功能而无需玩太长时间的游戏。48.为调试快捷键定义常量,并把它们放到一个地方。调试键像其他的游戏输入一样,在同一个位置冲突时不好处理。为了避免截图键冲突,在中心位置定义常量是很好的办法。另一个方法是在一个地方处理所有键,不管它是否调试功能。(不好的方面是这个类可能需要额外的对象引用这个)文档49.文档设置。大多数文档应该写在代码中,但是某些东西应该被记录在代码之外。让设计者筛选代码设置会是浪费时间。记录设置会提高效率(如果是当前文档)。文档如下:& && &&&1.层级使用(碰撞,选择以及光线投射应该在哪一层)。& && &&&2.标签使用& && &&&3.GUI层级深度设置(什么应该显示在什么上面)& && &&&4.场景设置& && &&&5.用语偏好& && &&&6.预设结构& && &&&7.动画层级命名标准和文件结构50.遵循一个记录命名约定和文件结构。统一的命名和文件结构会更简单的找到你想要的东西,也更容易区分。你很可能需要创建自己的命名约定和文件夹结构。下面是一个示例:命名一般原则& && &&&1.是什么就命名为什么。鸟就应该命名为Bird.& && &&&2.选择的名字容易发音和记忆。如果你制作一款玛雅游戏,不要用QuetzalcoatisReturn命名关卡.& && &&&3.保持一致性。保持使用选择的名字。& && &&&4.使用Pascal案例,如:ComplicatedVerySpecificObject.不要使用空格,下划线,或者连字符,有一个除外(命名同一事物的不同方面)。& && &&&5.不要使用版本数字,或者文字来表示他们的进展(WIP,final)。& && &&&6.不要使用缩写:DVamp@W,应该写成DarkVampire@Walk.& && &&&7.使用设计文档中使用的术语;如果文档调用死亡动画Die,使用DarkVampire@Die命名,而不是DarkVampire@Death.& && &&&8.保持左边的描述符特定具体;用DarkVampire代替VampireDPauseButton代替ButtonPaused。例如在inspector里如果不是所有的按钮都以这个文字初始化那就能更简单的找到暂停按钮。【很多人喜欢反过来,因为这样可以使分组更加明显形象。虽然名字不适合分组,文件夹也是。名字是区别相同类型的对象,这样就可以快速定位】& && &&&9.一些名字会形成一个序列。在名字里使用数字命名,例如PathNode0,PathNode1。一般从0开始,而不是1.& && &&&10.没有序列的名字不要使用数字。例如,Bird0,Bird1,Bird2应该是Flamingo,Eagle,Swallow。& && &&&11.临时对象使用双下划线作为前缀。__Player_Backup.同一事物的不同方面命名在核心名字之间使用下划线隔开,用具体的“方面”来描述,例如:& &&& & 1.GUI按钮状态&EnterButton_Active,EnterButton_Inactive& &&2.纹理&DarkVampire_Diffuse, DarkVampire_Normalmap& &&3.天空盒&JungleSky_Top, JungleSky_North& &&4.LOD组&DarkVampire_LOD0, DarkVampire_LOD1不要使用约定来区分不同选项类型,例如Rock_Small,Rock_Large换成SmallRock,LargeRock更好。结构场景组织,项目文件和脚本文件也应该遵循类似模式。文件结构MaterialsGUIEffectsMeshes& &Actors& && &DarkVampire& && &LightVampire& && &...& &Structures& && &Buildings& && &...& &Props& && &Plants& && &...& &...PluginsPrefabs& &Actors& &Items& &...Resources& &Actors& &Items& &...Scenes& &GUI& &Levels& &TestScenesScriptsTexturesGUIEffects...场景结构CamerasDynamic ObjectsGameplay& &Actors& &Items& &...GUI& &HUD& &PauseMenu& &...ManagementLightsWorld& &Ground& &Props& &Structure& &...脚本文件结构ThirdParty& &...MyGenericScripts& &Debug& &Extensions& &Framework& &Graphics& &IO& &Math& &...MyGameScripts& &Debug& &Gameplay& && &Actors& && &Items& && &...& &Framework& &Graphics& &GUI& &...如何重现Inspector绘制1.为所有编辑器定义一个基类2.使用反射和递归绘制组件以上方法使用可以使用以下助手:请注意,它使用一个注释类代码在Inspector中生成工具提示。3.定义新的自定义编辑器不幸的是,你仍然需要为每个MonoBehaviour定义一个类。幸运的是这些定义都可以为空;所有的实际工作都由基类完成。理论上可以自动完成这一步,但是我还没有试过。???本文由蛮牛译馆倾情奉献,除 合作社区 及 合作媒体 外,禁止转载。蛮牛社区()分享最新的游戏研发和虚拟现实相关技术内容。
点击展开全文
悄悄告诉你
更多同类文章
还可知道有多少人阅读过此篇文章哦
阅读原文和更多同类文章
可微信扫描右侧二维码关注后
还可知道有多少人阅读过此篇文章哦
游戏蛮牛 --- 中国最大的手机游戏开发者技术社区!
您的【关注和订阅】是作者不断前行的动力
本站文章来自网友的提交收录,如需删除可进入
删除,或发送邮件到 bang@ 联系我们,
(C)2014&&版权所有&&&|&&&
京ICP备号-2&&&&京公网安备34扫一扫,访问微社区
后使用快捷导航没有帐号?
签到成功!您今天第{todayrank}个签到,签到排名竞争激烈,记得每天都来签到哦!已连续签到:{constant}天,累计签到:{days}天
关注:1390
当前位置: &
__________________________________________________________________________________
开发者干货区版块规则:
  1、文章必须是图文形式。(至少2幅图)
& && &2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
& && &3、本版块只支持在游戏蛮牛原创首发,不支持转载。
& && &4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
& && &5、......
__________________________________________________________________________________
查看: 2805|回复: 16
刨根问底U3D---如何退出Play模式后保留数据更改
本帖为抢楼帖,欢迎抢楼!&
9排名<font color="#FF昨日变化3主题帖子积分
在线时间175 小时
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
才可以下载或查看,没有帐号?
本帖最后由 tunied 于
15:58 编辑
实际中遇到的需求
在做一款对抗类游戏,目前正在调整游戏的平衡性 所以就产生了一个需求 希望可以在Play模式时候对数据源做的更改可以在退出时候被保存下来。
举个Case, 比如 有一个炮塔 可以发射子弹, 然后有一组敌人 去攻击这个炮塔.
首先点击Play按钮 开始执行游戏逻辑
接着在Inspector中调整相应的数值,比如 射速啊,血量啊,敌人移动速度等等.
按原始的做法 就是调整以后 把所有的数据记录下来(截图或者写纸上)
点Stop进入编辑模式,所有数据回滚原始的 然后再一个一个把刚才改过的再重新填上去
一次两次还好,不过平衡性这东西 必然要经常调整 每次这样调整 非常影响工作效率,那有没有办法 可以让在退出Play模式后保留对应的修改呢?
就此我还提了一个/question/37917 不过也没得到比较满意的答案 :(
只好自己瞎折腾了..
实现这个Case的思路
其实思路很简单, 因为 MonoBehaviour 有 void OnApplicationQuit (){} 函数 所以 在该函数内部 序列化相应的Class 然后保存到本地
当下次Awake 时候在反序列化 即可
& &&&-&&1·从本地Load
& &&&-&&2·反序列化
OnApplicationQuit
& && && &-&&3·序列化
& && && &-&&4·保存到本地
想法很简单 不过却遇到了不少问题..
LitJson 无法序列化float类型
LitJson 用的人应该很多吧,反正我自己一直在用,序列化首先就想到它了,不过JsonMapper.ToJson (this); 直接报错
JsonException: Max allowed object depth reached while trying to export from type System.Single
问答里面一个哥们儿说他那里没问题,我就Google了一下 发现也有几个人遇到了我同样的问题,并且我把所有float都去了 一切就都ok了
网上帖子里面是建议用doulbe然后再自己转换,想想实在太麻烦. 后来又在GoogleCode搜到一个自己改过的LitJson不过也觉得不好
最后还是在GitHub上发现一个很NB的库 Full Serializer /jacobdufault/fullserializer
代码结构很清晰 并且使用起来也很简单. 试了一下float的问题 完美Fix了. 这样第一个问题就算搞定了
MonoBehaviour 无法被New 出来
序列化的问题是解决了,不过反序列化时候就又有问题了.. 写好反序列化代码 然后运行 直接报Warning
You are trying to create a MonoBehaviour using the 'new' keyword.&&This is not allowed.&&MonoBehaviours can only be added using AddComponent().&&Alternatively, your script can inherit from ScriptableObject or no base class at all
写的很清楚了, MonoBehaviour 不能用new,只能AddComponent, 并且直接序列化MonoBehaviour到JSON以后里面有很多乱七八糟的东西,比如gameobjct,transforme等等.. 所以看来这条路是走不通了.
嵌套类或Dictionary&string,object&
因为是希望Play时候可以在Inspector中编辑,但是同时又不能是MonoBehaviour(否则无法反序列化) 所以想到的两个解决方法 一个就是用单写一个Vo类,然后在MonoBehaviour里面写get/set 方法
[C#] 纯文本查看 复制代码
public class MetaManger:MonoBehaviour
class MetaVo
private MetaVo mVo;
public float Speed
get{return mVo.}
set{mVo.speed =}
这样做应该是可以的(抱歉我没有尝试),不过问题就是 每次新加入一个属性时候要相应的写get/set方法 很麻烦.
第二个方法就是 使用反射,在序列化时候把所有Property Add 到 一个Dictionary&string,object&里面 然后反序列时候再 反射还原。
理论上这个应该是可行的,不过反射弄起来很费劲 尤其是如果出现嵌套Array,枚举啊 什么这种不太普通类型时候.. 应该是个坑 果断放弃了这个思路
那有没有简单可行方法 来实现这个需求呢? 答案是有的(折腾了一天啊...), 不过在这之前 还是先了解一些知识(开始刨根问底..)
为什么U3D 在退出编辑时候无法保存数据?
Google了很多不过没有及时保存 已经找不到了 不过大体的意思就是
会在Play时候 把当前所有所有的数据 序列化一份,然后在退出的时候再全部反序列化回去 就相当于RollBack了 所以 所有的改变自然都回去了.
[System.Serializable] 标签
这个也是我Google时候查到的,
在之前Case中 我也尝试过不对MetaVo的每个属性写get/set方法 就是在MetaManger中 直接public MetaV 这样Inspector中 无法看到
MetaVo中的内部属性,只能看到一个Vo,但是 如果对MetaVo加上了[System.Serializable]标签 则可以在Inspector中查到了
Google了一下 大部分人都是在复制粘贴 就说加上以后Inspector中就可以显示了. Ok 可是为什么呢?
首先来看下官网这篇文章 /Manual/script-Serialization.html(这篇文章写的很好,如果没读过的朋友建议仔细看看)
Inspector window. The inspector window doesn’t talk to the C# api to figure out what the values of the properties of whatever it is inspecting is. It asks the object to serialize itself, and then displays the serialized data.
个人理解的inspector组件的工作流程(未被证实,但是可以解释通)
我们先假设inspector是用js写的,脚本代码是用C#写的,底层U3D是C++写的. 序列化的方式采用JSON 那假象的交互流程就是
首先点击Play按钮
Unity通过momo 把C# 中的代码都序列化成JSON 保存在一块内存里面
inspector中读取这块内存中的JSON,然后反序列化成js中可识别的数据类型 接着显示在面板上面
用户在inspector中修改相应数据,inspector把修改的数据再序列化成JSON 放回那块内存里面
底层U3D代码 反序列化那个JSOn到C++中可识别的数据类型,然后再根据相应的数值 操作场景上面的对象渲染
这个整个流程肯定是YY的 不过里面的逻辑我觉得应该是对的:)
那整个又和[System.Serializable]标签有什么关系呢?
其实这个是因为,Unity只能序列化MonoBehavior和后面要提到的ScriptableObject 对于其他类型 他不知道这是什么东西 所以自然无法序列化了,无法序列化 自然也就无法在inspector中显示出来了
/oldman/articles/2409523.html 这篇也提到了我说的这个问题
有时候我们会自定义一些单独的class/struct, 由于这些类并没有从 MonoBehavior 派生所以默认并不被Unity3D识别为可以Serialize的结构。自然也就不会在Inspector中显示。我们可以通过添加 [System.Serializable]这个Attribute使Unity3D检测并注册这些类为可Serialize的类型
当然U3D 自己的序列化中还有很多需要注意的,比如什么类型无法序列化,包括对于复杂类型如何写自己的序列化Callback函数. 我就不一一说了
/Manual/script-Serialization.html 这篇文章已经说的很全了.
第二个要说的就是ScriptableObject
Unity对于这种Vo数据类型的存储及序列化有着自己的解决方案 就是 ScriptableObject
/Manual/class-ScriptableObject.html
ScriptableObject is a class that allows you to store large quantities of shared data independent from script instances.
具体如何使用 可以参考
/gamedev/unity3d/unity-serialization-behind-scriptableobject/
/_archive.html
/2012/02/unity-3d-scriptableobject-assetbundle.html
思路就是 首先通过编辑器先产生一个ScriptableObject类型的asset文件,然后在对应的把GameObject和这个文件Link起来. 具体的思路在解决方案二中有提及
有一点需要仔细理解一下 就是文档中提到的那个4MB 和 40MB 的例子 我个人认为 这个应该是ScriptableObject的核心。
ok废话就到这里 说两种我已经试验成功的解决方案
解决方案一
使用 [System.Serializable]标签 + Full Serializer。&&这个方案应该很好理解 还是之前Case中的四步 Full Serializer解决的是
无法序列化float类型的问题,[System.Serializable]标签 解决的是直接public MetaVo vo 无法在inspector中显示的问题
[C#] 纯文本查看 复制代码public class MetaManger:MonoBehaviour
[System.Serializable]
class MetaVo
public MetaV
(抱歉 代码没有试 感觉应该可以,因为我实际的代码 要设计到单例 以及个个Serializable的类嵌套 比较复杂 无法直接贴上来)
只要把MetaVo 前面加上[System.Serializable]Tag 即可 目前实际项目中 使用一切都Ok ,其中包括
1· 对于 [System.Serializable]内部嵌套另一个 [System.Serializable] 的 类, inspector中显示OK 并且有折叠 编辑起来很舒服
Full Serializer序列化和反序列化也Ok 毕竟这只是普通类而已..
2· 类中包含有枚举类型,inspector显示ok ,Full Serializer 序列化也ok 并且序列化后的JSON中枚举类型被转化为String,这样即使以后枚举中有增删改 照样可以反序列化回来 不知道LitJSON是不是 没有试过
解决方法二
第一种方案 其实是挺正统的一种方法,就是 做一个单例的MetaManger 然后所有的实例对象 比如炮塔啊 子弹啊 敌人啊 当需要相应数据时候 向MetaManger中去要.
不过 用ScriptableObject的特性 可以用另外一种方式 来做.
把刚才的例子变得复杂一些, 炮塔变成 红黄两种, 炮塔属性相同 都只有一个speed,和damage项需要配置 此时可以
1· 写MetaClass
[C#] 纯文本查看 复制代码public TowerMeta:ScriptableObject
2· 执行命令生成两个asset 一个交 RedTowerMeta.asset, 一个叫 YellowTowerMeta.asset
3· 写TowerRender类
[C#] 纯文本查看 复制代码public TowerRender:MonoBehaviour
public TowerM
4· 在场景上建立 红黄两个塔实例,然后分别对应拖入RedTowerMeta.asset和YellowTowerMeta.asset并存成两个Prefab
5· 用代码或者直接拖拽都行,在场景上 建立10个红塔 10个黄塔
6· 点击Play按钮 然后 点击 Hierarchy中的RedTowerMeta.asset或者YellowTowerMeta.asset 此时 Inspector中 应该可以显示出来对应的数值的, 并且可以直接更改 即使退出Play模式以后不发生回滚
这里其实就是用了ScriptableObject得特性, 即使产生了10个红塔 10个黄塔 但是他们引用的Meta(ScriptableObject) 是同一份.
方案一和方案二的优劣性
方案一 最终生成的是JSON,优势是明文可读 项目大了以后 可以单独写编辑器解析对应JSON 进行编辑适配。劣势 就是JSON体积大 体积大 需要自己压缩.
方案二 优势是生成的asset是被压缩过的体积小,并且和Unity配合很紧密 一切托托拽拽即可 也不用管初始化 每个类Start()以后直接取用就好
劣势 就是一个是要写命令产生对应的asset 第二个就是 如果数据格式发生变更 比如 TowerMeta中加入新的属性 int cost ,那之前的asset就不能用了
因人而宜吧,我个人是比较倾向于 [System.Serializable] + Full Serializer 操作起来很方便 :)
Ok 就叨唠这么多好了
(9 Bytes, 下载次数: 19, 售价: 1 蛮牛币)
23:59 上传
点击文件名下载附件
售价: 1 蛮牛币 &
unity unity unity unity serialize dictionary
蛮牛币 +30
赞一个! 真的只是打赏啊,
确实干货!!!!支持下!!!!!.
每日推荐:
4342/500排名<font color="#FF昨日变化6主题帖子积分
四处流浪, 积分 342, 距离下一级还需 158 积分
四处流浪, 积分 342, 距离下一级还需 158 积分
蛮牛币1343
在线时间76 小时
确实干货!!!!支持下!!!!!
每日推荐:
7排名<font color="#FF昨日变化4主题帖子积分
蛮牛币1046
在线时间498 小时
确实干货!!!!支持下!!!!!
每日推荐:
7排名<font color="#FF昨日变化主题帖子积分
蛮牛币2023
在线时间451 小时
assetstore中搜索 : playmodepersist
每日推荐:
5924/1000排名<font color="#FF昨日变化7主题帖子积分
熟悉之中, 积分 924, 距离下一级还需 76 积分
熟悉之中, 积分 924, 距离下一级还需 76 积分
蛮牛币1340
在线时间254 小时
确实是干货啊 学习了
每日推荐:
262/150排名<font color="#FF昨日变化14主题帖子积分
初来乍到, 积分 62, 距离下一级还需 88 积分
初来乍到, 积分 62, 距离下一级还需 88 积分
在线时间19 小时
太给力了,刚好在找这方面的资料,感谢!
每日推荐:
4327/500排名<font color="#FF昨日变化6主题帖子积分
四处流浪, 积分 327, 距离下一级还需 173 积分
四处流浪, 积分 327, 距离下一级还需 173 积分
在线时间57 小时
使用插件 easy2save
。。。。。。。。。。。。。。。。
7排名<font color="#FF昨日变化5主题帖子积分
在线时间84 小时
71880/5000排名<font color="#FF昨日变化1主题帖子积分
日久生情, 积分 1880, 距离下一级还需 3120 积分
日久生情, 积分 1880, 距离下一级还需 3120 积分
蛮牛币3545
在线时间473 小时
好东西,支持。谢谢楼主辛苦分享。加油
71747/5000排名<font color="#FF昨日变化主题帖子积分
日久生情, 积分 1747, 距离下一级还需 3253 积分
日久生情, 积分 1747, 距离下一级还需 3253 积分
蛮牛币4787
在线时间501 小时
思路不错,赞个
4359/500排名<font color="#FF昨日变化6主题帖子积分
四处流浪, 积分 359, 距离下一级还需 141 积分
四处流浪, 积分 359, 距离下一级还需 141 积分
在线时间120 小时
看看这个是个啥………………
9排名<font color="#FF昨日变化主题帖子积分
蛮牛币4682
在线时间899 小时
为什么不能把数据写到xml 或者写到文本保存
9排名<font color="#FF昨日变化3主题帖子积分
在线时间175 小时
为什么不能把数据写到xml 或者写到文本保存
序列化的选择看个人需求
自定义格式的文本 : 格式相对自由 不过反序列化需要手动处理,相比没有写入二进制实用
JSON 和 XML: XML和JSON都很成熟,个人倾向于JSON, JSON没有XML那样臃肿体积小 可读性高一些.
9排名27昨日变化主题帖子积分
在线时间1394 小时
你那打赏,改成捐赠比较时髦,哈哈
这些修改我们的做法是配表,但是比你说的这种方式要麻烦一些,回头改成你的帖子里的这样试试。
9排名<font color="#FF昨日变化3主题帖子积分
在线时间175 小时
你那打赏,改成捐赠比较时髦,哈哈
这些修改我们的做法是配表,但是比你说的这种方式要麻烦一些,回头改成 ...
恩 人多 配表方便 弄个Excel2Json 然后丢给策划就行了
像我这种一人瞎搞的 直接在IDE里面 调来调去 还是挺方便的. 哈
游戏蛮牛给予质量较高、影响力较大的unity相关技术开发者的荣誉称号
七夕浪漫情人
2015年蛮牛社区浪漫七夕 最美情话活动获奖者
社区QQ达人
使用QQ帐号登录论坛的用户
连续签到30天
蛮牛论坛干货区作者
认证开发者
经过游戏蛮牛认证的独立开发者

我要回帖

更多关于 unity inspector 数组 的文章

 

随机推荐