[C#] Game Loop

Started by
18 comments, last by samirleal 12 years, 4 months ago
Hi, this is my first post here on the forums.

What I'd like to say is that I am a novice in game programming. I have experience in Actionscript, VB.NET, HTML, Javascript, and PHP.

I have just begun working with C# in my brand new project for school, a 2D RPG.

I have been using these two books for help:
  • Visual C# Game Programming for Teens
  • Visual Basic Game Programming for Teens

They are complete beginner books.

The game loop provided with the books are very strange. It does not make sense to me.
It feels like the frame rate is not constant because the game freezes every couple of seconds (not at specific intervals, just randomly pauses everything).

I don't know exactly how to explain it, but the game is unplayable like this.
I know for a fact that it has to do with the game loop. I ran it on two different computers.
My home computer was absolutely unplayable. The game frame rate went down to 3 FPS. My home computer has a Quad Core processor with 8GB of RAM.
My school computer is playable, but like I said, it freezes every couple of seconds. This PC is a dual core with only 2GB of RAM.

Here is some code that I have:

This function is true while gameOver is equal to false.
private void GameLoop()
{
frameRate = game.FrameRate();
ticks = Environment.TickCount;
lastTime = 0;
if (ticks > lastTime + 16)
{
lastTime = ticks;

#region CHECK GAMESTATE
//check which gameState is on and update accordingly
switch (game.gameState)
{
#region STATE_TITLE
case Game.GameStates.STATE_TITLE:
game.titleScreen.Draw();
break;
#endregion
#region STATE_PLAY
case Game.GameStates.STATE_PLAY:
game.playScreen.Draw();
break;
#endregion
#region STATE_OPTIONS
case Game.GameStates.STATE_OPTIONS:
switch (game.optState)
{
case Game.OptionStates.STATE_CONTROLS:
game.optScreen.DrawControls();
break;
case Game.OptionStates.STATE_HELP:
game.optScreen.DrawHelp();
break;
case Game.OptionStates.STATE_SETTINGS:
game.optScreen.DrawSettings();
break;
}
break;
#endregion
#region STATE_CHARACTER
case Game.GameStates.STATE_CHARACTER:
game.charBuilder.Draw();
break;
#endregion
#region STATE_LOAD
case Game.GameStates.STATE_LOAD:
game.loadScreen.Draw();
break;
#endregion
#region STATE_PLAYING
case Game.GameStates.STATE_PLAYING:
//game.gameDevice.Clear(Color.Black); MIGHT CAUSE LAG??
doScrolling();
doHero();
doSide();

//print info
game.Print(50, 10, "Player Position " + game.hero.Position.ToString());
game.Print(50, 90, "Scroll Position " + game.world.ScrollPos.ToString());
break;
#endregion
}
#endregion

//refresh window
game.Print(50, 50, "Frame rate: " + frameRate.ToString());
game.Update();
Application.DoEvents();
}
else
{
System.Threading.Thread.Sleep(1);
}
}


and

public int FrameRate()
{
//calculate core frame rate
int ticks = Environment.TickCount;
count += 1;
frames = count;
if (ticks > lastTime + 1000)
{
lastTime = ticks;
frames = count;
count = 0;
}
return frames;
}


I would really appreciate some help in making this game loop as good as possible.

Thank you for all your time.
Advertisement
I took a quick look and noticed you use Application.DoEvents. This creates garbage, and may be the culprit (or at least contribute) in your lack of performance. The generally accepted correct way is using P/Invoke. The SlimDX guys have a good tutorial explaining it (scroll down to Message Loop.

Edit:

And I'm pretty sure putting the thread to sleep isn't a good idea either. There are a lot of resources on gameDev and the net about putting together game loops. e.g. here and here

I took a quick look and noticed you use Application.DoEvents. This creates garbage, and may be the culprit (or at least contribute) in your lack of performance. The generally accepted correct way is using P/Invoke. The SlimDX guys have a good tutorial explaining it (scroll down to Message Loop.

Edit:

And I'm pretty sure putting the thread to sleep isn't a good idea either. There are a lot of resources on gameDev and the net about putting together game loops. e.g. here and here


Thank you for the response!

When I stopped putting the thread to sleep I did see a little bit of improvements.
I looked at the P/Invoke but I'm having trouble understanding the set up.

Also are there any other tips that could improve my game loop?

Edit: Never mind about the set up. However, isn't it inefficient to use this SlimDX? Because now users who want to play this game have to install the end user runtime in order to play. RPG games such as Warcraft 3 don't necessarily have us install extra runtime packages that I know of (unless it's in the installer itself and we don't see it happen).
Sorry for all the questions.

Thanks again.
The link provided gives you the information required to build your own game loop in .NET and does not require SlimDX libraries at all. P/Invoke is the method used by .NET to make calls into native C libraries. Basically, the example just emulates the basic C/C++ message pump.
Firstly, let me admit I don't know exactly what "Environment.TickCount" returns, but I assume it's the number of ticks since the last time it was called? Anway...
I think I know one of your problems:

frameRate = game.FrameRate();
ticks = Environment.TickCount;

lastTime = 0;
if (ticks > lastTime + 16)
{
lastTime = ticks;

frameRate does nothing. You calculate it, then don't use it. But, that's not the real problem.

You're resetting lastTime to 0 before every loop, so, it doesn't matter what FrameRate() set for lastTime, it will be reset to 0 before checked.

So, all the check if (ticks > lastTime + 16) is doing is checking you've have 16 ticks from the last time you checked.

The reason it works better on a slower PC is it has a better chance of reaching the magical 16 ticks than a faster PC does.

You really need to double check how the book is using the framerate calculations as this way is way off.




[font="arial, verdana, tahoma, sans-serif"]
[/font]

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Edit: Thanks BeerNutts I made some changes and it is again running smoother, but after a couple of seconds of just moving the player around the game begins to slow down. Enviornment.TickCount returns the number of time the application has been running in milliseconds.


Ok let's forget about SlimeDX and that other link that Starnick provided. Both just made my form unable to be debugged. (Stayed at a white screen with my mouse at the loading wheel). Thank you for trying though, I could have done something wrong so I'm not blaming you two.

I need a basic game loop that will do the following:
  1. Stay at a constant 30-60 FPS.
  2. Update information of the player.
  3. Update the screen with drawing.

And now I am completely confused because of all these different ways to do it.
http://blogs.msdn.com/b/tmiller/archive/2005/05/05/415008.aspx

This is pretty much the default standard for game loops in .NET, and is the result of a series of blog posts exploring the topic thoroughly. It is also the inspiration behind the code linked in the SlimDX tutorial.

Once you have this game loop working without any frame limiting logic, then you should look at the other links provided that allow you to fix your timestep.

Edit: Thanks BeerNutts I made some changes and it is again running smoother, but after a couple of seconds of just moving the player around the game begins to slow down. Enviornment.TickCount returns the number of time the application has been running in milliseconds.


Ok let's forget about SlimeDX and that other link that Starnick provided. Both just made my form unable to be debugged. (Stayed at a white screen with my mouse at the loading wheel). Thank you for trying though, I could have done something wrong so I'm not blaming you two.

I need a basic game loop that will do the following:
  1. Stay at a constant 30-60 FPS.
  2. Update information of the player.
  3. Update the screen with drawing.

And now I am completely confused because of all these different ways to do it.


Here's a simple way to do what you want (in C++, since I'm not familiar with C# calls)


// holds the number of milliseconds for each frame; ~16 mS for 60 FPS, 33 for 30 FPS
#define FRAME_TICK_TIME 17

// hold the last tick count acquired, in milliseconds since beginning of program
uint32_t LastTime = 0;

while(bRunning)
{
// timeGetTime() returns the current system time, in milliseconds
while (timeGetTime() < LastTime + FRAME_TICK_TIME) {
// you could sleep, if you have a high-resolution sleep available or just spin here
}
LastTime = timeGetTime();

// Do game Loop stuff, check input, perform logic, draw everything, etc.

}


You can pretty it up, but that's one general solution.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


[quote name='Starnick' timestamp='1323114956' post='4890810']
I took a quick look and noticed you use Application.DoEvents. This creates garbage, and may be the culprit (or at least contribute) in your lack of performance. The generally accepted correct way is using P/Invoke. The SlimDX guys have a good tutorial explaining it (scroll down to Message Loop.

Edit:

And I'm pretty sure putting the thread to sleep isn't a good idea either. There are a lot of resources on gameDev and the net about putting together game loops. e.g. here and here


Thank you for the response!

When I stopped putting the thread to sleep I did see a little bit of improvements.
I looked at the P/Invoke but I'm having trouble understanding the set up.

Also are there any other tips that could improve my game loop?

Edit: Never mind about the set up. However, isn't it inefficient to use this SlimDX? Because now users who want to play this game have to install the end user runtime in order to play. RPG games such as Warcraft 3 don't necessarily have us install extra runtime packages that I know of (unless it's in the installer itself and we don't see it happen).
Sorry for all the questions.

Thanks again.
[/quote]

What exactly are you using? If you're working on your game loop, then you're probably not using XNA. That leaves SlimDX, OpenTK (if you're using opengl and not direct3d), or MDX (Managed DirectX). MDX is deprecated and users should choose either XNA or SlimDX (or SharpDX I guess). The message loop link from the SlimDX site also links to the original Tom Miller blog post, but at least shows how to use his method in a context where it's actual code and window setup to play with. Even if you're using OpenTK the same principles will apply - although I don't know of a tutorial on the OpenTK site that is equivalent to the SlimDX/Tom Miller one.

Lots of games have runtimes they install, but that's during the installer you run - like many times they check if DX is up to date and some may have to install a visual studio runtime. So it's not inefficient, nor abnormal.

What exactly are you using? If you're working on your game loop, then you're probably not using XNA. That leaves SlimDX, OpenTK (if you're using opengl and not direct3d), or MDX (Managed DirectX). MDX is deprecated and users should choose either XNA or SlimDX (or SharpDX I guess). The message loop link from the SlimDX site also links to the original Tom Miller blog post, but at least shows how to use his method in a context where it's actual code and window setup to play with. Even if you're using OpenTK the same principles will apply - although I don't know of a tutorial on the OpenTK site that is equivalent to the SlimDX/Tom Miller one.

I'm not using any of these. I have XNA installed but I am not coding with it. I am just using C# with no libraries. The book's I am reading are directing me to "Lua Script" but I plan on replacing that with something else. I would like a way to code in XNA but I need to now learn the syntax of that language and then translate my code into it.


Lots of games have runtimes they install, but that's during the installer you run - like many times they check if DX is up to date and some may have to install a visual studio runtime. So it's not inefficient, nor abnormal.
[/quote]
I see. Then I have no problem with installing these runtimes so that my game will run more efficient.

This topic is closed to new replies.

Advertisement