Are you considering building a game engine? Do you have a clear meaning to how to build a game engine?
Plan? Have you had a pass between the relationship between the various modules of the game engine? if there is not,
Then this article will make some useful programs for you to build a good gaming architecture. If you have already had a problem with the above problem
A clear answer, then this article is not what you need to read. The purpose of this article is to give those nothing to build a complete game
Optics experience provides some entry-sex knowledge, so that they will initially understand how to build a game engine and build a game
The problem should pay attention to what kinds of problems, and provide some mature design templates and pointed out the scope of these design templates, I
I hope that these contents also have a good reference to those intermediate programmers. The content of this article is derived from some popular programming
For books, please see the last part of this article, because this article is an article introduced the nature, if you are in the content
Very interested, please refer to the corresponding book, this article may have a lot of mistakes, if you have any opinions, you can pass
Email and I discuss, my address is Dreams_Wu@sina.com.
Here, you must remind you again, this article introduces some universal game programming skills, although it is common but may not
Very comprehensive, there may be such or such defects, so if you want it to play the biggest utility, you must use it.
Instead of misuse of abuse. Remember to remember, an incorrect mistake of an initiator is to use some design templates,
Guide the range of use.
What kind of questions do you need to consider first when you start building a game engine? This is the problem you have to consider carefully.
My answer is to first consider the readability of the code, especially when multiplayer is developed, if you write
Code other people need to spend a lot of energy to read, then there is no effort to improve work efficiency, and below is increasing code
Some good suggestions for reading:
1. Establish a simple name rule. A good naming rule can significantly increase the readability of the code, the rules must
Simple, usually only two or three minutes of reading should allow others to master, such as directly using Hungary in the code.
Nomenclature is a well-known rule, using letter I as the first letter of the interface class, using C as the first letter of implementing the class,
Use the variable name starting with G_ as a global variable, S_ starts as a static variable name, M_ starts as an internal variable name, use _ open
As a function name used inside the class, the first use, you can give you a scope and basic functions of the object through the name.
2, don't hate your comments. An error that the programmer is easy is not to write a comment, think it will increase its own workload, but
He didn't take into account the corresponding workload has been transferred to the code reading reader, and people who may see the code will spend more written.
Two times or three times the time to read the code, this is a very irresponsible behavior that can be read through a short comment
The reader quickly understands the functionality of the code, so that the time is morely used to extension of the function. Here are some good suggestions:
The amount indicates its function to each variable. The function declared for each function, indicating its function, and should be complicated.
The role of writing parameters and returns, note that in the header file of the declaration function. Write its role in key code, especially
It should be the case when performing complex operations. A brief introduction to its functionality in every class declaration.
3, reduce the inheritance level of the class. Usually, the inheritance level of each class is preferably not more than 4 layers for game programming, because too many
The inheritance not only reduces the readability of the code, but also makes the class pointer, the code volume is increased, and the efficiency of the class is reduced. also
Be careful to reduce multiple inheritance, because it is not careful that it will form a "diamond" shape that the programmer is very annoying. At the same time, pay attention to
If you use a combination of classes, then try to minimize the inheritance of the use class, of course, this is a problem with design techniques.
4, reduce the length of each line of code. Try not to complete a complex operation in a line of code, this will increase the difficulty of reading.
At the same time, it does not meet the implementation of modern CPUs. Since the CPU has now used the design of the ultra-long flow wire, it is ideal for implementing those per line.
The code is very short and a lot of code, such as a complex mathematical operation, is not as written in each step.
The above suggestions are some of my rough ideas, if you have any good view, you can give me a good point, and the above suggestions
Not absolute, such as the inheritance of the class, is not absolutely unable to exceed 4 layers. If you need, you can use more inheritance, before
This is the benefit of this greater than the loss of code execution efficiency.
Then look at what should be considered, a "an object-based game architecture" in Game Programming Gems3
It is pointed out that several problems worth considering are the first is the problem of platform correlation and independence and game correlation and independence.
Speaking that the architecture of the engine should be not related to the platform and game. Why do you have no relationship with the platform? This is because you must
Start the architecture engine considering its portability, if you don't pay attention to this problem, then once after the game is completed
To port it to other game platforms, you will find the trouble, you need to modify the place, all the platforms
Related API calls need to be modified, all modules that use platform-specific features need to be modified, this is a very consumable energy
Things, you may need to spend and develop a game, and if you start, take this question,
So very simple, just write a module of a corresponding platform to replace the original module, so that you can put it on
Fully use the ability of a specific platform to improve the performance of the game, not the code modification. Let's talk about how
Make the engine to be unrelated to the platform.
1, pay attention to the difference in operating system. The mainstream operating system is mainly two kinds of Windows and Linux, of course, UNIX and Mac
When programming, you must pay attention to this, when you need to include Windows header files, you must include it in Hong_WIN32
In the following is a simple example:
#ifdef _win32
#include "windows.h"
#ENDIF
This should also be used when you use the Windows platform-specific API, so you can guarantee the Windows platform when compiling on other platforms.
The corresponding code will not be compiled. This should be used for other platforms.
2, pay attention to the difference between the compiler. Now general compilers have several several VC, BC, and GCC, when performing a Windows platform programming,
You usually use VC or BC, and you usually use GCC when programming for Linux platform, you can't compile for Linux using the VC compiler.
The platform of the platform, therefore also needed attention when programming, you can use the above method to pass different compilers through a specific macro
Separate. Have a simple example:
#ifdef _win32
#ifDef _MSC_VER
TYPEDEF SIGNED __INT64 INT64;
#ENDIF
#elif defined _Linux
TYPEDEF Long Long Int64;
#ENDIF
Naming of 64-bit variables in different compilers is different because it is not part of the C standard, but the compiler's expansion
Exhibition section. Another example is the inline assembly code used by the compiler, you can use _ASM in the VC, and for
The compiler of the Linux platform you need to use its dedicated keyword.
3, pay attention to the difference between the CPU. For different platforms, it usually uses different CPUs, but fortunately, Windows and Linux support x86 CPU, which is the mainstream CPU platform of the PC game, and XBOX is also the X86 CPU, unless you need to port to the PS2 platform
Otherwise, this will greatly reduce your programming burden, provide a CPUID instruction to check CPU on the X86 platform.
Features, if you support MMX, SSE, SSE2, 3DNOW! Technology, etc., through it you can use a specific CPU feature to speed you
The code execution speed.
4, pay attention to the difference in graphics API. Now the graphic API mainly has two mainstream platform DirectX and OpenGL, DirectX can only be used for
Windows platform, while OpenGL is almost supported by all platforms. So you need to encapsulate different graphics APIs, do it
Being different modules, switching when needed. The best way to complete this work is to use the type of factory model described later.
5, pay attention to the difference between the graphics card. Now the graphics card has two major mainstream ATI and NV, although the graphics card can be supported by the mainstream operating system, but
Be careful to use different GPUs on different gaming platforms, and there is a corresponding function extension between GPUs, so
You must check if you are supported by the graphics card using a specific extension.
6. Pay attention to the difference between the Shader language. The appearance of programmable graphic language is the most important invention, now almost every game
In the use of this technology, because of its importance, there are several standards, HLSL can only be used in DX, while OpenGL is due to
The standard openness is more confusing, and each graphics manufacturer implements the corresponding extension directive according to its own product.
And NV has introduced GC can be applied to DirectX and OpenGL at the same time. This is a very good idea, but because this is not a
Open standards have no support from other manufacturers, running GC code on the ATI graphics card, you will find a few more slower than in the NV graphics card.
Quantitative levels, due to the above case you need to package, methods, and article 4 according to different platforms. The following suggestions are worth
You should consider that when you use the DirectX platform, you should use HLSL, and for OpenGL can be packaged for two modules, according to the graphics card
Different for switching, you can also use GC to encapsulate one module for graphics cards for NV.
It is necessary to add a little bit here, if you can make a different operating system as possible as possible, so convenient
Switch between different systems.
Then look at how to achieve the game innocence, usually the game engine is very difficult, this is also
It is said that your engine is suitable for all game types, which is too difficult, consider a RPG game engine if used to do an RTS
The game is simply impossible, similar to you can't take Q3 engine to do RTS games, but if the engine design is very good
It is still possible to achieve part of the game independence. That is to say, you can design a part of the engine into a universal module, so
This part of the code can be reused when developing other types of games, including the underlying display, sound, network, input, etc.
Part, you must ensure that they have good versatility when designing them.
After these issues, you should consider the internationalization of the program. This is also very important because your game may be
Other countries are issued, mainly to pay attention to language issues, especially the processing of strings, and provide one in the C standard library.
String container, it provides a good support for internationalization, so you need to use it from beginning to end in the engine.
Next we look at the most important content of this article, how to organize an engine architecture. This is the most important part of the engine, why is it important? If we think of the engine as a house, then the architecture can be seen as a frame of the house, when you finish this framework
Afterwards, you can add bricks to the frame. Let's take a look at how to build this framework, usually a large software
The engineering is built in modular way. Before programming, the necessary demand analysis is performed, and software projects according to different functions.
Divided into a few larger functional modules, you may also need to divide it into several submodules, and need to give each
The logical relationship between modules. When you write a engine, you need to make a corresponding functional analysis, let us see how to divide
The function module of the engine, if we analyzed in accordance with the above games, we can find it into a game
The related layers and unrelated layers, the game-related layers are also referred to as logic layers due to the logic code containing the game. The logical layer should be in
The top level of the engine, if you develop a local area network or online game, according to the C / S development mode of the network program, this layer
It should be divided into two modules, servers, and client modules, which contain all features related to specific games, such as AI, game roles,
Game event management, network management, etc. It is the game unrelated layer below it, including the engine core module, GUI module, file
System management module, etc., where the core module of the engine is the most important part, the logical layer mainly derived by it and the underlying module
Road, it should include scene management, special effects management, console management, graphics processing, etc. It is some underlying module downwards.
, Such as graphical rendering modules, input device modules, sound modules, network modules, physical modules, role model modules, etc., all
These underlying modules must interact with the logical layer through the core module, so the core module is the hub of the entire engine, all
The modules are interacting through it.
Let's take a look at how you should design, there are some general rules that you should follow:
1. Reduce the relationship between the modules. We know that there is a large number of objects that usually exist inside each module need in each module.
Mutual calls, if we assume that the number of internal objects per module is n, then between each module
Relationship complexity is n * n, this complexity is unacceptable, why? First of all, it is very disadvantageous to manage, due to each
There are a large number of global objects, and there are interdependent relationships, and each built time is different, which exists.
The contradiction of the initialization order, considering this situation, there is an object in one module that requires an object in another module to do
Initialization, when this object is initialized, the additional object is not initialized before, and the crash will be triggered. Secondly,
It is not conducive to multiplayer development, because each module has interdependent relationship, when complexity is very high, module
The high dependence with the module, that is, one module does not complete the next module, so it is necessary to have a module.
The module is programmed in accordance with its dependent relationship without synchronization. So the first thing when designing modules
It is a complexity between the modules, and you must design a interactive interface for the module when designing modules, and agreed to all modules.
The interaction between the intercom has to be carried out through this interface. This complexity between the modules is reduced to 1 * 1, which is very convenient to manage,
This is very good to develop between many people. If everyone is responsible for the development of a module, then you only need to complete this.
Interface class, others can use this interface to develop other modules, without having to wait until all classes are completed, so all modules are synchronized, saving a lot of valuable development time.
2. Programming for the abstract interface of the class rather than class. This is the Suggestions of "Design Patten" book author for all software programmers
It also has a big guiding significance for game programming. Establish an abstract interface for all classes used by other modules in the module.
Other modules should be programmed using this abstract interface so that other modules can be implemented without knowing how the class is implemented.
Perform programming. The benefit of this is to change the implementation of the class without changing the interface without changing without having to notify others.
Very useful for multi-person development.
3, layers according to the different parsives of the call object. In fact, this article is still supplemented with article 2, and the layering is still in order to better hide the bottom.
Realization of the layer. Usually a class is not only used by other modules, but also being called by its own modules, and their needs are also different.
So we can make a class to display an interface to the outside and also show an interface internally, which is the same as the above.
Because a complex module is also multi-person in progress.
4. Reduce the number of classes by making a class except to appear multiple interfaces. One way to reduce relationship complexity is to reduce the number of classes,
So we can combine the classes of different functions into a class, and let it behave outside the export, which is a class.
Implementation can inherit multiple interfaces.
The above suggestions simply play the reference, and you should use it flexibly according to the situation, not any mess.
The following content involves specific programming skills.
For global objects in the engine you can use Singlet, if you don't understand what it is, what you can read, "Design Patten
", There is a detailed introduction to it, and specific use can be obtained through the OGRE engine.
Objects within the call module can be implemented by class. COM can be seen as a typical class, DX is to use it
Designed, and the famous open source engine CRYSTLE SPACE is also implemented by building a similar COM object, but I am not
It is very comparable to it. First, a class similar to COM is very complicated. The overhead is a bit big, and one of the second COM is that it can be done.
The order implementation is compatible, which is also an important reason for DX using it, and a game engine does not need. A class plant is also implemented in OGRE
Structure, this is a relatively universal class, but it is still necessary to write a code. I am more appreciation of the practices of Valve, it
By using a macro, this problem is solved, very efficient, very convenient to use. This is very simple, it puts each
The interfaces that need to be exposed to the module are connected to an internal maintenance linked list, each interface is connected to an interface name.
The sample external module can get the pointer of this interface by incorporating a interface name to the CREATEINTERFACE function, very simple
single. Let's take a look at its specific implementation. The structure of its internal saved is as follows:
Class InterfaceReg
{
PUBLIC:
InterfaceReg (InstantiateInterfacefn Fn, Const Char * PNAME);
PUBLIC:
InstantiateInterfacefn m_createfn;
Const char * m_pname;
InterfaceReg * m_pnext;
Static InterfaceReg * s_pinterfaceregs;
}
And define two function pointers and a function
#define createInterface_procname "createInterface"
typedef void * (CreateInterfaceFn) (const char * pName, int * pReturnCode); typedef void * (InstantiateInterfaceFn) (void); DLL_EXPORT void * CreateInterface (const char * pName, int * pReturnCode); take a look at how it macros establishing list #define EXPOSE_INTERFACE (className, interfaceName, versionName) / static void * __ Create ## className ## _ Interface () {return (interfaceName *) new className;} / static InterfaceReg __g_Create ## interfaceName ## _ Reg (__Create _ ## className ## _ interface, version; if you have a class cplayer it wants to expose the interface iPlayer, then it is very simple, you can do this #define player_version_name "iPlayer001" Expose_Interface (CPlayer, iPlayer, Palyer_Version_name); if you need to get in other modules This interface can do this createInterfacefn factory = reinterpret_cast
Solved the problem of the class factory, let us see how to establish a module external interface, in the "an object-based game architecture" article in the "Object-based Game Architecture" one, this architecture is effective in the Half Life2 engine. Extensions, you can use this architecture for all external exposed interfaces, provided that the module has only one interface to expose. Class Iappsystem {public: // here's where the app systems get to learning = 0; virtual void disconnect () = 0;
// Here's where systems can access other interfaces implemented by this object // Returns NULL if it does not implement the requested interfacevirtual void * QueryInterface (const char * pInterfaceName) = 0;
// init, shutdownvirtual initreturnval_t init () = 0; Virtual void shutdown () = 0;}; through the Connect method You can establish a connection relationship through the QueryInterface method, you can retrieve other exposure interfaces, this The method is very good for all modules to establish a standard external interface, which greatly reduces the complexity of programming, unfortunately, only some of the modules in the HL2 engine use this method, maybe this interface is too late. . (Renew) original blog: http://blog.gameres.com/show.asp? Blogid = 118 & color = 0