自定义编辑器Windows 它们可以简化您的工作流程 但创建和维护它们也会花费大量时间 Custom editor Windows, they can ease your workflow, but they can also take a lot of time to create and maintain.
有了Odin检查器 欢迎自定义编辑器 窗口几乎和创建自定义检查器一样容易 With Odin Inspector, greeting custom editor, windows is almost as easy as creating custom inspectors.
现在Odin有两类编辑器窗口 Now there are two classes of editor windows with Odin.
第一个窗口是OdinEditor窗口 它允许以与创建自定义检查器相同的方式创建自定义编辑器窗口 The first is Odin Editor window, which allows the creation of custom editor windows in the same way that custom inspectors are created.
定义字段和函数 然后使用属性创建编辑器窗口 这是最简单的了 You define fields and functions and then use attributes to create the editor window. That's about as simple as it could be.
第二种类型是Odin菜单编辑器窗口 这将是本视频的重点 它允许在窗口一侧轻松创建导航树 The second type is Odin menu editor window, which is going to be the focus of this video. It allows the easy creation of a navigation tree on the side of the Window.
在这个视频中 我将创建一个编辑器来创建和管理可编写脚本的对象 而导航树是完美的 For this video, I'll be looking to create an editor to create and manage scriptable objects, and the navigation tree is perfect for this.
首先 我将在脚本文件夹中添加一个编辑器文件夹 To get started, I'll add an editor folder to my scripts folder.
我需要这样做 因为unity将抛出一个错误 当构建一个项目 如果编辑器脚本不在编辑器文件夹 I need to do this because unity will throw an error when building a project, if editor scripts are not in the editor folder.
完成后 我将创建一个新的CSharpscript 名为任何Mediata编辑器 With that done, I'll create a new C Sharpscript called any Mediata editor.
打开脚本 我需要做的第一件事是添加一些库 包括Unity editor cerenics dot odin inspector Opening up the script, the first thing I need to do is add a handful of libraries, including Unity, editor, cerenics, dot, odin, inspector.
SirenexDOT odin 检查器 点编辑器 最后 Sirenex点实用工具 点编辑器 Sirenex DOT, odin, inspector, dot editor, and finally, sirenex Dot utilities, dot editor.
然后我需要更改与脚本 从继承到自己的菜单编辑器窗口 I then need to change with the script, inherits from to own menu editor window.
当我这样做 这 visualstudio将显示一个错误 因为我需要实现和覆盖功能 构建菜单树 When I do, this, visual studio will show an error, as I need to implement and override the function, build menu tree.
这是为窗口创建导航树的函数 但在添加该函数之前 我想添加另一个函数 允许从统一菜单打开编辑器窗口 This is the function that creates the navigation tree for the window, but before adding to that function, I want to add another function to allow the editor window to be open from the unity menus.
或者添加一个名为openwindow的私有静态函数 Or add a private, static function called open window.
在这个函数中 我只需要一行 In that function, I just need one line.
它的窗口在我 数据编辑器作为一个类型点显示 It's get window in me, data editor as a type dot show.
也在属性菜单项与参数 工具 前进 斜杠敌人数据 因此可以从工具菜单中打开编辑器 Also at the attribute menu item with the argument, tools, forward, slash enemy data. So the editor can be open from the tools menu.
完成后 窗口可以打开 但没有什么可看的 所以让我们修正一下 With that done, the window can be opened, but there's nothing much to look at, so let's fix that.
我们可以通过向构建菜单树函数添加几行代码来做到这一点 And we can do that by adding just a few lines to the build menu tree function.
第一个是创建一个名为tree的新变量 并说它等于一个新的Odin菜单树的实例 就像这样 The first is create a new variable called tree, and said that equal to an instance of a new Odin menu tree, like so.
这也是函数将返回的值 所以我将添加一个返回行 This is also the value that the function will return, so I'll add a return line.
接下来我想给树添加一些东西 在这种情况下 我想添加所有的敌人数据criptible对象 Next I want to add something to the tree. In this case, I want to add all the enemy datascriptible objects.
我可以只用一行命令树 在Path添加所有资源 And I can do this in just one line using the command tree, dot add all assets at Path.
这个函数需要几个参数 第一个是可折叠头文件的名称 我将在任何数据中为其指定名称 The function requires a couple arguments. The first is the name of a collapsible header, and I'll give it the name in any data.
第二个参数是资产的路径 在我的例子中就是资产 正斜杠脚本 The second argument is the path for the assets, which in my case is just assets, forward, slash scripts.
第三个参数是我们想要添加的一种酸 在本例中是敌对数据 The third argument is a type of acid that we want to add, which in this case is enemy data.
还有更多的参数来控制如何处理子原始文件 但是在我的例子中 我忽略了它们 因为默认值就可以了 There are more arguments to control how sub vulders are handled, but in my case, I ignore them, as the default values will do just fine.
快速保存和编译 然后回到unity中 我们可以看到编辑器看起来已经很不错了 A quick save and compile, and back in the unity, we can see that the editors already looking pretty good.
如果您曾经创建过自己的编辑器 窗口 那么您就知道创建它要花多长时间 在这里只需要大约20行代码 它就可以工作 看起来很漂亮 If you've ever created your own editor, windows, you know how long it can take to create, and here with just about twenty lines of code, it's working and looking pretty nice.
现在 虽然这对于查看和编辑数据很好 但我想进一步进行一些操作 Now while this is good to view and edit the data, I want to go a couple steps further.
我想添加创建新的可编写脚本的对象的能力 这很容易做到 我可以通过创建一个新类并添加到树来做到这一点 I'd like to add the ability to create new scriptable objects, and this is pretty easy to do. I can do this by creating a new class and adding to the tree.
因为这个新类只会被这个编辑器使用 我将把它添加到编辑器脚本中 并调用它 创建新的敌人数据 Since the new class is only going to be used by this editor, I'll add it to the editor script and call it, create new enemy data.
在向类添加内容之前 我想将其添加到导航树中 要做到这一点 我只需添加线树 点 添加到构建菜单树功能 Before adding content to the class, I want to add it to the navigation tree. To do this, I simply add the line tree, dot, add to the build menu tree function.
第一个参数给出导航树中项目的名称 第二个参数是将显示的对象 The first argument gives a name for the item in the navigation tree, and the second is the object that will get displayed.
保存脚本并让unity编译 我可以在编辑器中看到结果 Saving the script and letting unity compile, I can see the results in the editor.
编辑器中什么也不显示 因为类没有字段或函数 我需要像创建自定义检查器一样创建这些 Nothing is shown in the editor, as the class has no fields or functions. I need to create those just like I would for a custom inspector.
在这种情况下 类将由一个字段 一个函数和一个构造函数组成 In this case, the class is going to consist of one field and one function plus a constructor.
战场将是敌方数据类型 The field will be of type, enemy data.
我将它设为公共 并在行编辑器中添加属性 参数为 对象字段模式等于 在行编辑器中 对象字段模式 dot hidden I'll make it public and add the attribute in line editor with the argument, object field mode equals in line editor, object field modes, dot, hidden.
这隐藏了字段 但是显示了内联编辑器 This hides the field, but shows the inline editor.
接下来 我将创建一个构造函数 它将创建一个新的敌人datascriptible对象的实例 并将敌人名称字段设置为新敌人数据的通用值 Next I'll create a constructor that will create a new instance of the enemy datascriptible object, and set the enemy name field to a generic value of new enemy data.
像 所以 Like, so.
到目前为止 这看起来不错 但没有增加太多的功能 可脚本化对象的实例存在于内存中 但需要将其添加到项目文件中以使其更有用 So far, this is looking nice but hasn't added much functionality. The instance of the scriptable object exists in memory, but it needs to get added to the project files to be more useful.
为此 我将创建一个函数 当编辑器中按下按钮时将调用该函数 To do this, I'll create a function that will get called when a button is pressed in the editor.
我将创建一个新的私有函数 名为createnewData 并添加一个带有参数的按钮属性 添加一个新的enemyscriptable对象 给按钮一个自定义标签 I'll create a new private function called Create new Data, and add a button attribute with the argument, add new enemyscriptable object to give a custom label to the button.
这个函数需要创建一个新的资源并保存该资源 这可以只用两行代码完成 比如 This function needs to create a new asset and save that asset, and this can all be done with just two lines, like, so.
第一行有两个参数 第一个是将成为新资产的对象 第二个是新资产的路径和名称 The first line has two arguments, the first is the object that will become the new asset, and the second is the path and name for the new asset.
在这种情况下 我将使用敌人的名称作为资产的名称 In this case, I'm going to use the name of the enemy as the name of the asset.
第二行是保存项目中的所有资产 And then the second line, all that does is save all the assets in your project.
这将把可脚本化对象的实例转换为资产 因此代码还需要为编辑器窗口创建一个可脚本化对象的新实例 This will turn the instance of thescriptable object into an asset, so the code also needs to create a new instance of the scriptable object for the editor window.
为此 我可以从构造函数中复制这两行代码 如下所示 To do that, I can copy the two lines from the constructor, like so.
在unity中进行快速测试 我们可以看到一切都在运转 并且能够从编辑器中创建一个新的可编写脚本的对象 A quick test in unity, and we can see that things are working and were able to create a new scriptable object from the editor.
现在 虽然这是工作 我想添加更多的代码来帮助Unity清理和避免潜在的错误或警告 Now while this is working, I want to add a bit more code to help Unity clean up and avoid potential throwing of errors or warnings.
特别是 当编辑器窗口关闭时 我想销毁敌人可描述对象的实例 In particular, I want to destroy the instance of the enemy descriptable object when the editor window closes.
我将存储一个引用到创建新敌人数据类的实例它在菜单树中创建 我将通过创建一个新字段来做到这一点 So I'm going to store a reference to the instance of the create new enemy data class that's created in the menu tree, and I'll do this by creating a new field.
引用新实例创建新敌人的数据 并设置树打开这个新实例 Erence to the new instance of the create new enemy data, and set the tree to open This new instance.
完成后 我需要做的下一件事是重写ondestroy函数 With that done, the next thing I need to do is override the on destroy function.
在函数中 我将调用baseDoton destroy以确保不丢失任何功能 In the function, I'll call base Dot on, destroy to make sure to not lose any functionality.
然后我会检查在我的数据中创建你的实例不是全部 如果不是 我将使用DestroyImmediate来摧毁敌人数据的实例 脚本对象 I'll then check that the instance of creating you in me data isn't all, and if it isn't, I'll use Destroy Immediate to destroy the instance of the enemy data, scripttable object.
这就整理了一下确保我们没有让实例悬空并丢失在内存中 That tidy things up a bit and make sure we're not leaving instances dangling and lost in memory?
对于许多人来说 这可能已经足够有用了 但是我还想添加删除这些可编写脚本的对象的功能 For many, this might be enough to be useful, but I'd also like to add the ability to delete these scriptable objects.
从这个编辑器里面 使它成为一个一站式的地方来管理敌人的数据 From inside this editor and make it a one stop place to manage the enemy data.
当然 有很多方法可以做到这一点 但我认为一个更好的方法是在顶部添加一个按钮 它将删除当前选定的脚本对象 Now of course there are a bunch of ways to do this, but I think one of the better is to add a button to the top that will delete the currently selected scriptable object.
为了做到这一点 我可以重写函数 开始绘制编辑器 To do this, I can override the function on, begin draw editors.
我想在这个函数中做的第一件事是获得对当前选中项的引用 我可以用这个命令 这个点 minutri 点选择 The first thing I want to do in the function is getting reference to the currently selected item. I can do this with the command, this dot, minutri, dot selection.
接下来 O 用命令 cerenics编辑器和GUI标记工具栏的开始和结束 Next, O, mark the beginning and the end of the toolbar with the commands, cerenics editor, GUI.
点开始 水平工具栏和serenics编辑器 GUI 点和水平工具栏 DOT begin, horizontal toolbar and serenics editor, GUI, dot and horizontal toolbar.
然后在这些命令之间 我将添加一个粘性布局 圆点 灵活的空间 这将迫使按钮到工具栏的右边 Then in between those commands, I'll add a gooey layout, dot, flexible space, and this is going to force the button to the right of the tool bar.
然后我可以用这条线创建按钮 如果SirenicsEditor gooeyDot工具栏按钮 这个函数的参数给按钮一个标签 I can then create the button with the line, if Sirenics Editor, gooey Dot toolbar button, where the argument of this function gives a label to the button.
在if语句中 我将当前选择的对象转换为类型 敌人数据 就像这样 Inside the if statement, I'll cast the currently selected object to the type, enemy data, like so.
然后我将使用命令assetdatabase getassetpath来获得资源的路径 And then I'll use the command asset database, dot, get asset path to get a path to the asset.
完成后 我可以删除资产并通过调用资产数据库来更新资产数据库 点Saveassets With that done, I can delete the asset and update the asset databases by calling asset database, dot Save assets.
要知道 如果你的编辑器中有不同类型的可编写脚本的对象 你将需要更聪明地使用类型转换 可能需要更复杂地删除资产 Do know that if you have different types ofscriptible objects in your editor, you'll need to be more clever with the type casting and may need to be more sophisticated with the deleting of assets.
编辑器完成后 让我们快速浏览一下所创建的内容以及它是如何工作的 With the editor complete, let's take a quick run through what we've created and how it works.
从工具菜单中 我可以打开编辑器窗口 然后使用菜单树 我可以在我的脚本文件夹中导航所有敌人的数据criptable对象 From the tools menu, I can open the editor window, then using the menu tree, I can navigate through all the enemy datascriptable objects in my script's folder.
我可以轻松地修改脚本对象中的任何字段 这是调整游戏数据的一种超级便捷的方式 I can easily modify any of the fields in the scriptable objects, which makes for a super handy way of tweaking our game data.
如果我点击创建新按钮 我就可以为新敌人设置数值 包括关联新模型和属性 If I click on the create new button, I can set values for a new enemy, including associating a new model and stats.
单击按钮和底部将一个脚本对象添加到项目资产中 Clicking the button and the bottom adds a scriptable object to the project assets.
将可脚本化对象作为资产 我就可以在游戏中使用它 就像我在之前的视频中所做的那样 With thescriptable object as an asset, I can then use it in the game, just like I did in the earlier videos.
将新的脚本对象放入敌人控制脚本将加载模型并设置所有数据 Dropping the new scriptable object into the enemy control script will load the model and set all the stats.
希望您能看到Odin实现这一最终目标是多么容易 并且它为您提供了一些关于如何为您的项目创建定制ES的想法 Hopefully you can see how easy Odin makes this ultimate accomplish, and it gives you some ideas of how to create customs ES for your project.
我们很乐意听到你的想法 看看你正在用Odin创造什么 所以在你下方留下评论 或来分享失聪狗的不和 直到下次 快乐的游戏 设计 We'd love to hear your ideas and see what you're creating with Odin, so drop a comment below you, or a come shared on the deaf dog discord, and until next time, happy game. Designing.