PDA

View Full Version : game data and rendering mechanism



ericlangedijk
08-02-2013, 11:41 PM
Although I made one game several years ago, I want to make things more structured now.
In the old game (using graphics32) the game engine also handled the rendering directly.

Now I want to split up these things into TGame and TRenderer. TGame just handles mechanics and manipulates data.
TRenderer does the screen output.
This means that somehow the TGame has to inform the TRenderer what has happened.

What is the smart/common way to achieve this?

SilverWarior
09-02-2013, 12:21 AM
You don't need TGame part to inform TRenderer. What you do is that both TGame and TRenderner have acces to same data (gamemap, units position, etc).
So whenever TRenderer is doing a rendering pass you actually inform TGame part so that it doesn't process any game related data until renderning pass is compleete. This is to avoid corrupted graphics (graphics rendered from two different ingame states). Also this avoids any Acces Violation that may arise when two parts of your application try to acces the same data.

Dan
09-02-2013, 03:09 AM
SilverWarior, I have read ericlangedijk's post a few times, just to be sure. he does not seem to want to implement multithreading. which is what, I assume, you are talking about. perhaps it is intended to be implemented later with the structured approach that he is talking about. but I think what he wants here is to basically separate the rendering code from the game code.

What you do is that both TGame and TRenderner have acces to same data (gamemap, units position, etc). sorry, but this is just a bad advice. why does TRenderer need to know about the entire application's data set? it only needs to know what it has to render. a rectangle with this image at these coordinates, that's it.
ericlangedijk, I suppose the smart/common way to do what you want would be to just put all the rendering code in the TRenderer with a few public methods like TRenderer.RenderThisRectangleWithThisImageAtTheseC oordinates(...), or something like that. and in the TGame you will just need to call this method instead of having the rendering code right there. once that is done you can can change your rendering back end to whatever you want, if necessary, direct3d, opengl etc.

SilverWarior
09-02-2013, 09:42 AM
SilverWarior, I have read ericlangedijk's post a few times, just to be sure. he does not seem to want to implement multithreading. which is what, I assume, you are talking about. perhaps it is intended to be implemented later with the structured approach that he is talking about. but I think what he wants here is to basically separate the rendering code from the game code.

Yes I know he didn't mentioned or even indicated that he wants multithreading but the reason why I sugested this way is for him to be actually able to implement multithreading in the future if he needs it. Besides even if you have singlethreaded application you can benefit from this kinda approach all depending on what kinda game you are developing.


sorry, but this is just a bad advice. why does TRenderer need to know about the entire application's data set? it only needs to know what it has to render. a rectangle with this image at these coordinates, that's it.

I didn't say that TRenderer should have acces to all applications data. What I sad is that TRenderer has acces to some ingame map data using which it can then calculate where certain images must be rendered.


ericlangedijk, I suppose the smart/common way to do what you want would be to just put all the rendering code in the TRenderer with a few public methods like TRenderer.RenderThisRectangleWithThisImageAtTheseC oordinates(...), or something like that. and in the TGame you will just need to call this method instead of having the rendering code right there. once that is done you can can change your rendering back end to whatever you want, if necessary, direct3d, opengl etc.

@Dan now this is the bad advice. What are you suggesting is that he only moves the low-level methods used for rendering to seperate part and then calls theese from withing the game part. Your suggestion doesn't really seperate rendering part from game part since half of the work for rendering the scene is stil inside the game part.

Now when peepole decides to seperate the rendering portion of the game from the actuall game part is mostly becouse they want to be able to execute game part more often than rendering part.
For instance let us say that you have a game where you also want so do some physical simulation. What you will wan't is that physical siumulation part of the is executed quite often (maybe every millisecond). But due to rendering complexity you are not capable of executing rendering part so often. So in this case you would want rendering part and game part to be seperated and compleetly nondependant of each other.
And yes while using of multiple threads in this case would be best option becouse this way you can harnes the full power of moderndays computers it is not necessary. You can still process all of this in one thread which would still need to execute game part more often.

ericlangedijk
10-02-2013, 10:01 AM
I'm not using a rendering thread. I'm just painting after each gametick (which is fired 17 times per second).
My current idea is something about this (without the user interaction yet).
Indeed the renderer needs access to TGame as well as TLevelData (as well as user interface state) in my simple perception :)


TLevelData.Load(); // loads all needed graphics
TGame.Init(TLevelData); // prepare
TRenderer.Init(TLevelData, TGame); // prepare


The application loop:


if TGame.Tick then
begin
TRenderer.Render;
end;

laggyluk
10-02-2013, 06:47 PM
i'd just make TRenderer and TLevelData global vars ;)

ericlangedijk
10-02-2013, 10:01 PM
They are - more or less - global.
I have difficulty seperating and getting together all functionality: which objects 'know' or 'are responsible for' what...

ericlangedijk
10-02-2013, 10:30 PM
Like defined here very clearly: http://gameprogrammingpatterns.com/component.html

User137
10-02-2013, 10:34 PM
I have a reasonably clear separation in game template, that's what should be used as a base for new nxPascal games. I admit it's not multithreaded. If one wants to use threading, he must understand the risks involved, and program alot of things accordingly. I didn't intend such to be a "default". Most games will not, and never should utilize over 30% of cpu power. Unless you're doing some scientific simulation, or just want to run empty loop to fill the gaps...
http://code.google.com/p/nxpascal/source/browse/#svn%2Ftrunk%2Fdemos%2Ffpc%2Fgametemplate

There is few classes:
nxGame.TGameHandler
-> GameUnit.TGame(inherits TGameHandler)
-> -> GraphicsUnit.TGraphicalGame(inherits TGame)

TGameHandler is core class in nxPascal, sorting out the framerate, input and so on invisibly. TGame class stores and handles all game data, and what happens in physics or otherwise in the game. TGraphicalGame finally holds the graphical data and does rendering. TGameHandler decides when to do game events and when to render, based on settings. For example, frameskipping can be 1 such setting. If game events take longer than intended, it can skip rendering on that frame, and do just game-loop until it catches up.

ericlangedijk
13-02-2013, 10:29 PM
Ok thanks. I think I understand your template.
But now I want the TGame (mechanics only) to be as basic/fast as possible, because later on I want TGame to be ready for running on a server too.
So: no graphics involved I think. Only areas (rectangles) for characters and a collision 'bitmap'.
And there comes the point of 'splitting' code up: TGame needs data and TRenderer needs additional data.
The problem is not the loading of the data, but loading the different data twice and linking those together when TRenderer comes into play.
How does TRenderer 'know' that Character[N] has a bitmap[N] for drawing?

Well I hope this kind of thoughts are a bit clear... If not tell me :)

User137
14-02-2013, 02:26 AM
How does TRenderer 'know' that Character[N] has a bitmap[N] for drawing?
The question is made slightly wrong. Character doesn't have any bitmaps, only different properties and states (such as "humanoid type 4 with blue helmet and white armor is jumping at animation phase 0.6, at coords X, Y"). How you define those is only limited by your imagination :) Only renderer class/unit needs to store the possible bitmap/texture/model data. Make good use of indexes sometimes. For example:

Renderer unit has:
model: array of T3DModel;

Game unit has:
TPlayer = class
modelIndex: integer; // This would refer to model in renderer class
animFrame, animDelta: single;
end;

ericlangedijk
17-02-2013, 04:35 PM
Ok making progres... running in GDI mode I have a form with Application.OnIdle set to the below method:

procedure TGameWindow.Idle(Sender: TObject; var Done: Boolean);
begin
CurrentTime := QueryTimer;
if fGame.CheckTick(CurrentTime, LastTime) then // check elapsed time (>= 60 ms)
begin
fGamePainter.HandleInput(fInput); // if vk_left in keyboard then scroll left
fGame.Tick;
fGamePainter.Update;
LastTime := CurrentTime;
end;
Done := False;
end;


Now the HandleInput (which stores keyboard state etc) is done in sync with the game ticks.
Now if I - for example - want to speed up scrolling, is the best way to do this to have the GamePainter have its own timing and put the HandleInput at the first line of the method?
Or else: what is a good central place to handle this? Tips are welcome :)

BTW: Fullscreen GDI StretchDIBits gives me about 3000 FPS. Is this method hardware accelerated??

User137
17-02-2013, 06:22 PM
BTW: Fullscreen GDI StretchDIBits gives me about 3000 FPS. Is this method hardware accelerated??
Depends what happens in fGamePainter.Update; If you are not using OpenGL or DirectX, then it is not accelerated.

While your loop timing works, it might have problems with no sleep() used, so the loop will use full potential of all allocated CPU cores. This can cause alot of heating and fan noise on powerful computers, or those with just a little faulty coolers. It can cause noise even from the monitor itself.

You do not need 2 tick timers. Scrolling faster simply means changing scroll value more per frame. With timing system you have, you can move things at constant speed. But if you would have possibility to change framerate, or not limit it, you can count

frameMove:=(CurrentTime-LastTime)/1000;
Using it as multiplicator for each movement, you can make things move as "per second".

player.X:=player.X+5*frameMove; // 5 units per second
(However this doesn't actually result in as smooth animation in my experience, when compared to constant speed and set framerate.)

ericlangedijk
17-02-2013, 07:08 PM
Ok thanks. I think that for smooth scrolling I need an extra time-measurement.

Update = StretchDIBits.

Strange thing is that on another computer - same Windows 7 PC and just a tiny fraction slower than my own - the framerate is about 64. Which is at least a factor 400 slower! What can be the causes of this?