U3DC.COM | 优三帝研究院

Menu

Now You’re Thinking With Components

组件是unity 中非常重要的组成部分,甚至说,组件的配合使用就是unity的精髓。以下来自gamedevelop的一篇文章,博主尝试给它“汉化”了一下,各位将就看。

While Unity is an amazing gamedev platform, getting used to it will require a bit of initial work, as you'll likely need to shift your cognitive cogs to grasp its component-based architecture.

Unity  是一个强大的游戏开发平台,使用它来开发我们需要一些初始化工作,当然你可能需要改变你的认知架构:它是一个基于“组件”工作的结构。

While classic Object Oriented Programming (OOP) can be, and is, used, the Unity workflow highly builds around the structure of components—which requires component-based thinking. If you're familiar with components, that's great; if not, that's not a problem. Here, I'll give you a crash course on components in Unity.

Unity使用经典的面对对象方法编程,unity的工作流是围绕组件的构架,所以这里我们需要有一个基于组件构建的思考。当然,如果你很熟悉组件,那很好。如果没有这个概念,那也没什么事儿,看完我今天的讲解你会明白的。

Preview image: Old Cogs by Emmanuel Huybrech.

Before we proceed with how to work and think with components, let's make sure we fully understand what exactly they are.

在开始这个“思考”之前,我们先弄清楚:这个“组件”到底是什么?

In the world of programming, the concepts of components and decoupling go hand in hand. A component can be thought of as a smaller piece of a larger machine. Each component has its own specific job, and can generally (and optimally) accomplish its task or purpose without the help of any outside sources. Additionally, components rarely belong to a single machine, and can be joined with various systems to accomplish their specific task, but achieve different results when it comes to the bigger picture. This is because components not only don't care about that bigger picture, but also don't even know it exists.

在编程的世界里,组件的概念和分离齐头并进。一个组件可以被认为是一个小的一个更大的机器。每个组件都有自己特定的工作,通常可以(优化)的帮助完成它的任务或目的没有任何外部资源。另外,组件很少属于一个单独的机器,并且可以与各种系统来完成特定的任务,但实现不同的结果时,更大的图。这是因为组件不仅不关心,更大的照片,也不知道它的存在。

A classic example of components are the pieces of a car—but that's boring, as I'm not too into cars. Instead, consider an Xbox 360 controller. Tt has two analog sticks, various buttons, triggers, and so on. Not only is the entire controller itself a component, but each individual aspect of the controller is a component.

组件的一个典型的例子是停车场,但这很无聊。相反,举例说一个Xbox 360的手柄。Tt有两个模拟摇杆,各种按钮、触发器、等等。整个控制器本身就是一个组件,并且控制器的每个独立单元都可以是一个组件。

xbox-controller

 

Photo by Futurilla.

The X button can: be pressed; send off the information that it's been pressed; be released; and send off information that's it's been released. It has no idea there are various other buttons right next to it, nor does it care.

X键可以被按下,并且发送一个信息告知系统它被按下了。抬起的时候,又发送一个信息告知说它抬起了。对于它旁边的其他各种按钮,它从来都不关心。

The controller itself is a component, composed of other components (all of the buttons, joysticks, and triggers), because it can send data to whatever it's plugged into, but it doesn't care what that object is (Xbox, PC, some Arduino creation, or whatever). Neither the X button, nor the controller itself, needs to know what game you're playing, as it'll still do its job regardless of the receiver of its information.

手柄本身就是一个组件,由其他组件(所有的按钮、操纵杆和触发器)等组成,因为它可以将数据发送给任何的接入设备,但它并不在意对象是谁(可以是Xbox啊,电脑啊,一些Arduino产品,或其他)。X按钮,和控制器本身,需要知道你玩什么游戏,因为它仍然会做它的工作不管其信息的接收者。

The function of the controller is a one-way street, and its task will never change due to what it's plugged in to. This makes it a successful component, both because it can do its job as a standalone device, but also because it can do its job with multipledevices.

手柄的功能是单通道的,它的工作不会因为接入设备而改变,这样就成就了组件,因为它能为独立工作在单设备上,也能工作在多设备上。

Unity was built with components in mind, and it shows. One of the most valuable and distinctive aspects of Unity is that it's a very visual program. I've been working in game development for years now, and aside from my very early Flash IDE days, I've mostly worked with PNG sprite sheets and a code editor such as FlashDevelop—which isn't visual at all.

Unity采用组件构建,显而易见。unity最有价值、最有特色的一个方面是,它是一个可视化的程序。我一直在游戏开发工作多年来,除了早期使用Flash IDE的日子,我主要是使用PNG 精灵图片集合和一个代码编辑器,FlashDevelop就不是可视化编辑。

Unity is the exact opposite. Unity lets you see everything you're working on, and in real time. This means you can test your project, see your project running in a separate window, make edits to your code or game objects, and see those edits reflected live. The amount of power this system gives to a developer is immense, and is now, in my opinion, an essential aspect of modern game development. All of this is made possible by Unity's component-based architecture.

Unity是完全相反的。Unity能实时让你看到你工作上的一切。这意味着您可以直接测试您的项目,参阅您的项目运行在一个单独的窗口,让你的代码或编辑游戏对象,实时显示编辑状态。这个系统的强大给开发人员带来更多的便利,现在,在我看来,这样的方式(可视化)已经是现代游戏开发的一个重要方面。所有这些都是通过Unity的基于组件的架构。

In case you're unfamiliar with Unity, I'll explain the Inspector. This is a panel in Unity that shows you all of the properties of a game object. If you click on your player in the world (either at run-time, or before) you'll be able to see everything about that object.

可能你还不太熟悉unity,我解释下inspector,其实这个就是一个对象属性的显示面板。如果使用鼠标点击在世界坐标内(层级面板)的角色,你将看到所有关于角色的属性(运行中或者非运行状态皆可)。

If your player avatar has six components on them, each will be listed in a separate tab, and every public variable will be available for you to see, and tweak. If your player avatar has an inventory, you'll not only see that he has an inventory, you'll also be able to see the items in that inventory, and which index in the list or array each particular item occupies. If you pick up a new item in-game while you're testing, you'll see it added to the inventory—live. You can even add or remove items from that inventory, which would allow you to quickly test new items, which you could even be creating while the game runs.

unity-inspector-01

While live editing is insanely powerful, it's not exactly reliant on the use of components. You could change a script, and see those edits reflected live, but that's limiting compared to what components allow you to do.

Consider a vertical space shooter. When you test your project in most other environments, you'll see how your game plays, take notes, then go back into the code and tweak things, only to compile the project again and test those points. If you have a live setup, you can tweak that code on the fly, and see those changes while you play, which is even better. That being said, if you're not using components, you're going to have to change a lot of code to see any major effects, which takes time, and this rather defeats the purpose of live editing.

If you are working with components, you can add new components in two seconds flat. You can swap out your ship's guns for the guns a boss uses (assuming you programmed your components to function on their own, as good components should do), you can change your five-hit health system to that cool Halo-like recharge shield you programmed for another game. you can add an array of spells to one of your characters, and all in seconds.

component-inspector-02

You don't need to change any code, you don't need to recompile, you simply drag and drop, or select your desired component from a drop-down list, and it's added. That kind of power is invaluable to game balancing, and it saves tremendous amounts of time.

The hardest part about working with components is learning how to structure your projects when using them. For most programmers, this will likely mean that you'll be creating a lot more scripts, with each doing smaller, more specific tasks.

How you communicate between scripts is also a decent hurdle, as you'll have a lot more pieces and fewer giant classes where every object knows about every other object. There are obviously ways around this, such as static variables for core components of your game (players, score, and so on), but that rarely works for everything (and is not advised), and there are advanced methods to properly structure your components, and to stay decoupled.

Fortunately, since Unity was built with components in mind, it has a number of built-in functions that help us achieve this. There are functions to get references to a specific component, to check all objects to see which contain a specific component, etc. With these various functions, you can easily retrieve the information needed to create that magical one-way street of knowledge where components can communicate with objects they affect, but the component itself has no idea what exactly that object is. Combine this with the use of interfaces, and you've got enough programming power to take any approach to the matter, simple or complex.

In an OOP inheritance system, you could have a base Enemy class that contained any and all functions that most of your enemies would use, and then you could extend that to add specific functionality.

If you've ever actually implemented such a system, you're aware that between your base Enemy class, and perhaps your base GameObject (or equivalent) class, you end up with a lot of unneeded clutter from having variables and functions that some classes need, but many don't. Interfaces can help with this, but they're not always the solution.

Now, let's take a look at the same setup, but thinking with components. You still have various enemies, all of which share a lot of common functionality, but each of which has unique characteristics.

The first step is to break all functionality into pieces. One might think that having health and dying are part of the same system, but even that example can be broken up into a health system component, and a death system component. This is because your health is your health, and nothing more. When it reaches zero, it's not up to the health system to decide what happens next, it's only up to the health system to know that it is, in fact, at zero. Other systems, such a death system, can read this information, and then choose to do as they please.

Maybe the death system will spawn a new enemy (think of a large enemy breaking into bits); maybe it'll drop a power-up; maybe it'll add an explosion effect to the screen. Regardless of what happens, the health system isn't a part of that, and this is how we make clean and useful components.

When we think of movement, we might think that all movement needs to be in a single script. But some enemies in some games can't walk; they can only jump. Some enemies can walk, but can't jump. Thinking about these things is how we spot where components could, and should exist. When it comes to mobility, we could separate the jump from walking or running, separate flying, and so on—doing so will give us cleaner code, and more versatility.

components-enemy-behavior

Components make our code neater (no unnecessary variables and functions), but they also make the process of creating enemies far more flexible and enjoyable. With each piece of enemy functionality set up as a component, we can drag and drop aspects of enemies, and see how they behave—and even in real time, if we're using Unity.

Let's assume all of the following characteristics are already programmed. During our enemy creation process, we could create three blank enemies, which are all just empty prefabs in Unity. We can then drag on a health system, an item drop system, and a death system, as we know that all of our enemies, regardless of differences, will have health, die, and drop an item. We can actually select all three prefabs at once, then drag and drop these components into the Inspector panel, and update all three at the same time.

Next, we know that one enemy will be able to fly, so we select that one enemy, and drag a flying component onto it. Another can spot a target in the game, and fire at it, so we toss on a fire at target component script. The third can throw up a barrier that blocks all attacks for a short duration, so we toss on the barrier component.

We now have three unique enemies, all sharing certain components, but all also having components that apply just to them. The enjoyable part is that making these enemies is simple, and experimenting with new variations is as easy as dragging and dropping. Want a flying enemy, with a barrier, that can target an enemy and fire at it? Drag all the above components onto a single enemy, and you've got just that!

Thinking with components may not be easy, but it certainly has its benefits. You'll continue to use both components and inheritance in your future programming, but it's extremely valuable to expand your plethora of ways to approach the same problem by seeing various perspectives.

When it comes to Unity, you can use whichever method you prefer, but components are definitely favored, and it just doesn't make sense to fight against such an amazing workflow. Learning Unity and switching my way of thinking to work with components has been a moderately difficult obstacle to overcome, but now that I'm here, I don't see myself returning any time soon.

link from:game develop

打赏
— 于 共写了10748个字
— 文内使用到的标签:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据