Engine design question

Started by
0 comments, last by Shaarigan 7 years, 12 months ago

Hello. As (literally every) programmer id like to create simple framework + game with it. Id like to ask about some guidance, to not get stuck :)

My current design:

main (capacious) class framework,
interface gameapp for game application with virtual methods:
OnStartInit() called by framework on the very beginning, where concrete app can initialize its resources
OnUpdateWorld(/* maybe pass elapsed time*/) every frame to let app update its state
OnRenderWorld(/*some rendering interface*/) as name suggests, but i think ill get rid of it, and make framework store every obiect and take care of rendering.

So, should framework enforce base class of any obiect of the gameapp (Like UObiect from unrealengine), and manage them itself, and game app could view, spawn through the framework?

The program itself runs the framework, the framewrok creates window, d3d, and all the "background" stuff etc, basically framework is "hosting" concrete game app implementatin in itself.
So, the basic idea was to separate the framework from game app to make it reusable, and it works pretty nice now (I got rotating triangle "game" right now tho :) but it prooves that everything is goin right way and working properly ).

The ammount of components i got in mind (all the timers, shader classes, camera classes and millions of other) make me worry tiny bit that i will mess up something on the way (like dependencies)
Im usin design patterns and cheked solutions, but anyways do you have any tips for further development, good practices and such? And what do you think about the starting design?

Advertisement

Hey QQemka

it is quite dificult to answer your questions when there is so little information about what you intend to do. The design propabilities higly depend on the programming language are you using that may be different in C# versus C++ for example. But I will try to go into the provided details. I'm working in C++ for something arround 4 Years on my own game engine/framework and other engines as part of my job and could compare some technics ife seen and worked with over that time, but keep in mind that this is just my opinion of the things to work that may be different on the terms on what you or anybody else is working on.

1. UObiect/Gameobject pattern

I would advice to avoid such base object inheritance constructs because they may be usefull in some cases but mostly waste a lot of space unused in your code base and runtime. Take a look on Unity3D where management scripts (Sound, Network, Gameplay ..) inherit 3D transformation and rendering properties, have a null field to physics objects (collision, rigidbody) and so on where it isnt needed to do the managing job it was programmed for. Therefore I'm using little inheritance just for memory management in some classes that may need to allocate space where the base class holds an allocator object and one single access function. This design is based on the capability to have objects allocate space in different managing areas (heap, memory chunks, VRAM ..) and code anything else explicitely for the job it is used for.

2. OnStartInit

It could be difficult to tell your game to just use a specific entry point when you are working in a framework. The problem is that you either not have access to tell your game "please use the main entry point from a different assembly" or you need to expose a staticaly structured code class that your game is needed to call for starting the framework. I like the approach Urho3D is driving where you have a macro to use anywhere in your code specifying the main entry point. I have expanded that to also pass two functions that are called before and after the main loop to initialize/cleanup necessary stuff. In my case it is at least to instantiate the main allocator in a fixed area of memory in my framework assembly and to set the first time frame for the rendering loop.

3. OnUpdateWorld/OnRenderWorld

This may be complicated and time wasting depending on your implementation. Unity3D uses such events in every class inheriting from Gameobject so on every frame every object is called for the different update functions regardless if anything needs to be updated. Therefore such components as NodeCanvas use there own update mechanism where update is called once from the engine into NodeCanvas and distributed into the Tree of nodes. In a different project we have had our own timer class (that called the update function on a tick rather than a frame). The main question here is when are your objects updating themself and in my opinion could there only be a few situations when this may happen during gameplay.

- User Input changes an objects state (walking, attacking, clicking a menu)

- Timer ticks an event (Particle system, Skybox, AI made a decision, a Countdown runs out)

- A callback returns (Network transmission, a thread ended work e.g. loading an Asset)

So lets take the OnUpdate approach in account. In the example you are playing a network game with your friend over Lan. Your game now updates every frame and your code classes check for input each on its own, for having a network transmission receipt, update the AI states and so on. For the time passed function parameter, that isnt necessary at all because normaly you are using a static time frame from last rendering frame to current rendering frame in everything (Animation, Movement ..) called delta time. This may be scaled or unscaled but is always accessed staticaly.

4. General

A general advice I missed in the past is to have your framework use less classes/objects as they are not necessary most of the time. I also would point out that the lower you are the less classes are necessary where the higher you go into youre coding level the more probable it is that you will need a class. It is up to you to think of the coding level where a few questions could help you

- Am I using API functions (low level)

- Am I using mostly static functions on an object (may be low level at all)

- Am I wrapping different data arround static/API functions (seems high level)

Dont fail for the look of beeing high level where something is low level in real. This may be true for the shader class caused on the design template. Hardware is storing shader code and taking account of the data in modern graphics systems. On creating a shader you will get a hardware handle used to tell GPU using the one specific shader it is bound to. Information about what uniforms are set values for is the task for the object using the shader so in this case your Player/Enemy class because data may be changing from object to object (position, rotation, scale, skin color, animation state ..)

I've currently mixed C-style code with C++ OOP design for better performance for example I'm not using a timer class but a static function that returns current CPU tick (same as delta time is based on) as 64 bit integer. Camera class is basicly not needed because anything will be done on the shader side with a transformation and a view matrix that are stored as array in memory (camera may be one single transformation matrix, projection matrix is normaly not changed except for a window resize). Math especialy is quite important to be fast so the static function approach seems to be the best here avoiding the thiscall overhead.

5. Conclusion

Designing a framework/an engine is not that simple as a text-book algorithm rather than knowing capabilities from the language you are working at and design your code for easy use. Think atomic (what is it worth to build a class arround, do I realy need that information on this point) while complexity will arrive on its own during development. And at least test your code and keep it if it results in the desired use and outcome.

Game engine engeneer is a higly paid experts job so dont worry when you will need to change your implementation a few times, we do it too ;)

This topic is closed to new replies.

Advertisement