[Translation] Evolutionary Game hierarchy-rebuilding your game entities with components

Source: Internet
Author: User

An article translated by myselfArticle, Hope to help you.

Link: http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

Evolutionary Game hierarchy-rebuilding your game entities with components

Until the last few years, the gameProgramMembers have been using classes with deep structures to represent game entities. The current trend is gradually changing from a deep structure to simply taking the game entity object as an aggregate component. This article explains what these changes mean and explores the benefits and practical use of this method. I will describe some of my personal experiences, how to implement this system in large projects, and of course how to sell your solutions to other programmers and managers.

 

Game entity

Different games have different needs, just like what a game entity needs. However, in most games, the concepts of entities are very similar. A game entity is an object in the game world. It is usually visible to players and can be moved around.

Some entity examples:

LBullet

LCar

LTank

LGrenade

LGun

LHero

LPedestrians

LAliens

LJet Aircraft

LMedical package

LStone

Entities can usually do many things. Here are some things you may want to do:

LRun a script

LMobile

LIt looks like a rigid thing.

LEmit particles

LPlay a specific sound

LPlayers can be placed in a backpack.

LCan be put on by players

LExplosion

LMagnetic

LTargeted by players

LFollow a path

LAnimation

Traditional deep-level structure

The traditional way of representing a set of entity sets is like decomposing the entity set we want to remove tables. The intention to do this is usually good, but with the development progress of the game, these things often need to change.-Especially when a game engine is used again by different games. Our final design is as follows: FigureB-1In that way, but the actual class hierarchy is more than the nodes in the graph.

 

FigureB-1

As development progresses, we usually need to add many different functions to entities. Objects must either encapsulate their own encapsulated functions or inherit from other objects with that function. Regular Functions are loaded on the Root Node close to the class hierarchy, for exampleCentityClass. One benefit of doing so is that all derived classes can have those functions. But the bad thing is that these classes bring related overhead.

Even a very simple object, such as a stone or a grenade, has a large number of additional functions (related member variables, or member functions that are not necessary to be executed) at the end ). Traditional game object hierarchies often end with"Group traces"(Fat ball) (The Blob). As one of the classic anti-pattern, the fat ball is represented as a huge single class (or has a large number of branches on the class hierarchy) and has a large number of complex intertwined functions.

When the fat ball anti-pattern often appears near the root node of the object hierarchy, it is displayed on the leaf node ). The most likely candidate is the player class. Because a game is usually programmed for a single role, it indicates that the role object often has a large number of functions. This is often implemented in a class suchCplayerClass, which has a large number of member functions.

The result of implementing such a function near the root node of the hierarchy is to overload a large number of leaf objects that do not require functionality. However, using the opposite implementation method to implement a large number of features on the leaf node is also unfortunate. The function is now broken down, so it can only be used by a specific function specifically programmed for that object. Programmers often copy the sameCodeTo mirror functions implemented by different objects. In the end, we need to re-organize the hierarchy of classes and perform dirty refactoring to move and combine functions.

Let's take an example. An object is physically functional as a rigid body. Not all objects need to do this. You canB-1As shown in, we just letCrockAndCgrenadeClass slaveCrigidClass. What will happen if we want to apply this function to the car? You don't wantCrigidMove the class to the top of the hierarchy to make it more like the heavy fat model at the root we saw before, all functions are chained into a narrow chain of classes starting from the first inherited classes.

 

Aggregation component

The component method is more and more recognized by current game development. It is a way to separate different functions into different components independent from other components. Traditional object hierarchies are removed, and an object is now created as an aggregation (accumulation of things) of an independent component ).

Each object now has only the functions it needs. Any different new colons are implemented to add a component.

An object system composed of aggregation components can3To transfer the object hierarchy to different stages of a composite object. The following describes3Phase.

 

Object as a fat ball

A common method to reconstruct a fat ball object is to distribute its functions to different sub-objects and reference it by the first object. In the end, the parent fat ball object is replaced by a series of pointers pointing to other objects. Finally, the member functions of the fat ball object program the interface functions of these sub-objects.

This may actually be a reasonable solution if the features in your game objects are within a suitable small range, or if time is limited. You can easily aggregate arbitrary objects by allowing some sub-objects to be empty (NullPointer to them ). If there are not many sub-objects, this still allows you to have a lightweight pseudo-composite object that does not implement a composite framework for managing this object.

The disadvantage is that it is still essentially a fat ball. All functions are encapsulated in a large object. It's not like you completely break down a fat ball object to a pure sub-object, so you still have some important overhead and will make your light object heavier. You still have to constantly check the idle pointer to see whether the overhead needs to be updated.

 

Object as a component container

The next stage is to break down each component (the "sub-object" in the previous example) to share a common base class object. Therefore, we can store a list of objects in the object.

This is an excessive solution, and we still have the root "object" that represents the game entity ". In any case, it should be a reasonable solution, or it is indeed a feasible solution in practice, if a majority of the Code libraries need game objects of this concept as a specific object.

Your game object then becomes an interface object that acts as a bridge between the legacy code in your game and is also a composite object of the new system. If time permits, you will eventually eliminate the concept of a game entity object as an integral object. On the contrary, the access object is more and more directly through its component. In the end, you can convert it to pure aggregation.

 

Object as pure Aggregation

In the final layout diagram, an object is the sum of all parts. FigureB-2Shows a scheme where each object is composed of many different components. There is no "game entity object" here ". Each column represents the same component in the icon, and each row can represent an object. Components can also be seen as independent from the objects that make up them.

 

FigureB-2

Practical experience

The first combination system of objects implemented by components isNeversoftCompanyTony HawkA series of games. Our game Object System has been evolving along with three continuous releases of the game, guiding us to a game object hierarchy to restructure the fat ball anti-pattern I mentioned earlier. It suffers from all the same problems: objects tend to be heavyweight. The object has unnecessary data and functions. Sometimes unnecessary features make the game slower. Features are sometimes repeated on different tree branches.

OnSweng-gamedevI have heard of this new invention about the object-based component system in the mail list. I think that sounds like a good idea. I started to reorganize the code and completed it two years later.

Why is it so long? Because, first of all, we work hard every year.Tony HawkGame, so we only have a small amount of time to invest in restructuring. Second, I mistakenly calculated the scale of the problem. A three-year code group already contains a large amount of code. A large amount of code has gradually become some inflexible code in a year. Because the Code depends on the game object to become the game object, especially some game objects. That means there is a lot of work to be done to make everything work in a component-based way.

 

Expected Resistance

The first problem I encountered was how to explain the system to other programmers. If you are not particularly familiar with object combination and aggregation, it will be considered unintentional, complex, and unnecessary work, which will put you under a blow. Programmers have been working on the object hierarchies of traditional systems for many years and are very accustomed to that kind of work. They even become good at that way to solve those problems.

It is also difficult to sell this solution to the manager. You need to be able to accurately describe in a plain language how this solution can make the game faster. The following is the reason for saying:

"When we add new features to the game, it will take a long time to complete, which will leadBugs. If we use this new component object, it will allow us to add new features faster, with fewerBugs"

I adopt a quiet method. I first discuss this idea with some programmers and finally persuade them that this is a good idea. I then implemented the basic framework of general components, and also implemented a small part of the game object function as a component.

I then presented these results to the remaining programmers. They have some doubts and conflicts, but since it has been implemented and it is not a big controversy to work there.

 

Slow progress

When the framework is linked, the convenience from the static hierarchy to the object combination is very slow. It is a thankless job. Even if you spend many hours and many days re-constructing code that looks decent, it is no different from the replaced code. We are still doing this, and we are still implementing new features for the next game.

Earlier, we hit refactoring our largest class.-Problems with the ski class. Because it contains a large number of functions, it can hardly be reconstructed for a period of time. In fact, it cannot be restructured unless other object systems in the game are already in the form of components. In other words, other object systems are not easily componentized, unless the ski is already a component.

The solution here is to create a "fat ball component ". This is a separate giant component that encapsulates the functionality of a large number of ski classes. A small number of other fat ball components also need to be used elsewhere. We finally forced the object system into the component. When this is done, the fat ball component can be re-formed to form more atomic components.

 

Result

The initial reconstruction result is not so obvious. However, over time, the Code becomes clearer and easier to maintain, and functions are encapsulated into scattered components. Programmers start to create new types of objects with less time, simply combine some components and then add a new one.

We have created a data-driven object creation system, so the entire new type of object can be created by the designer. This proves to be very valuable for quickly creating and configuring new types of objects.

Finally, programmers began to accept componentized systems (at different speeds. And they become very skilled in adding new functions through components. Common interfaces and strict encapsulation makeBugsReduced, the code is easier to read, and easier to maintain and reuse.

 

Implementation Details

A common interface for each component means that it inherits from the same base class with virtual functions. This will incur additional costs. But do not contradict this method because of this. The cost savings are not important compared with the simplicity of objects.

Since each component has a public interface, it is very easy to add additional debugging member functions to each component. This makes it easier to add a diagnosis object that can export the readable information of component composite objects. Then, this can be evolved into a remote debugging tool with complex functions, which can always obtain the latest information about almost all types of Game objects. This may be annoying to implement and maintain in a traditional hierarchical system.

Normally, components do not know each other. In the real world, there is always a dependency between specific components. Performance issues also determine that the component should be able to quickly access other components. At the beginning, we made reference to all components through the component manager, but at the beginning we only used5%OfCPUTime, we allow the component to store pointers to other objects, and directly call member functions in other components.

In components, it is very important to combine the sequence of objects. In our initial system, we stored components in a container object as a linked list. Each component has an update function. Each object is called every time the component list is iterated.

Because object creation is data-driven, it will cause trouble if the components in the linked list are not in the expected sequence. If the physical content of an object is updated before the animation content, but the animation content of another object is updated before the physical content, they will lose synchronization. Mutual dependencies such as this must be found, and then define mandatory rules in the code.

 

End

One of the best decisions I have made is to use components to transform an object hierarchy from a fat ball style to a composite object structure. The initial result was disappointing. It took too much time to refactor the existing code. In any case, the final result is very worthwhile, lightweight, flexible, robust, and reusable code.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.