Snake game finished - check it out

Pages: 1234
closed account (zwA4jE8b)
I finished my snake game, check it out and let me know what you think. <windows only, sorry>

http://www.mediafire.com/?db959tciirdd0

There is a .exe file which is the finished game, a zip file containing all the complete VS2010 folder with all source code and .sln file.

I wrote it all and did not use any third party libraries so the graphics are pretty basic but the gameplay is good.

It should be 100% bug free. The only thing you may notice is that the score and highscore do not show during level changes. I could have fixed that but it would have required a lot of restructuring and because this is just for fun, I did not want to spend the time.
Last edited on
You said the high score doesn't show during level changes, but for me the highscore always displayed 0 the rest of the time too, but other than that, good job =) I would've just used a graphics library though it would've saved you a lot of time and you don't lose out on anything, in fact it would be multi-platform with a graphics library so you actually gain something
closed account (zwA4jE8b)
Thank you. Im thinking of making one with SDL or something like that.

Oh and the highscore gets written after the first play so when reopened it should show up.
Last edited on
closed account (zb0S216C)
I've noticed something. I don't know if it's a design fault or what but should it say Game Over if I press quit? and not something like Exit Confirmation or something like that?

Apart from the latter, it's a nippy game. Good job :)

Wazzak
closed account (zwA4jE8b)
Thanks. Do you mean when you push escape and it bring up the game over screen? I did that so I could just use the same screen.
It runs incredibly jittery on my machine. To the point of being practically unplayable. It's like it doesn't update for 10 frames, then skips 10 frames, etc.

I'll take a look at the source to see if I can find out what's going on.

*cringes at the sight of "prefix everything with an underscore"*

OK -- figured it out. You're doing 2 things very wrong.

1) You're doing a GetDC() and never releasing the DC, which is very taxing. GetDC effectively "locks" the DC so that nothing else can use it. Calling ReleaseDC is like saying "okay, I'm done drawing to this DC now" and allows other things (Read: the OS) to use the DC.

In my case, this was causing a problem because Windows is likely trying to display that DC but it can't because it thinks your program is still drawing to it (because you never release the DC), which is probably why it's not drawing properly.


2) You're doing a naive "Sleep(_speed)" call. Sleep does not sleep for the time you specify. It sleeps for at least the time you specify. What's worse, it often has a granularity of 10 milliseconds. This means that Sleep(1) might actually sleep for 10 milliseconds, not 1 ms.

The result here is that the game is going to run at different speeds on different machines.

Furthermore, you aren't taking into account the CPU time used for game logic and drawing. Which means that this game is going to run at a slower speed (easier) on slower machines, and a faster speed (harder) on faster machines.


EDIT:

Although I should say that for an early project, this is very good. Way better than the crap I started out doing =)
Last edited on
closed account (zwA4jE8b)
I agree with you about using sleep, I just wasn't sure yet how exactly to implement a timer.

I did not know about releasing the DC. Where should I do that? I have to go to school shortly but will read about it later.

Do i need to GetDC() prior to every draw, then ReleaseDC() after every draw?
Or more easily place it here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if(msg.message == WM_QUIT)
				break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
                             //getDC();
			_game.game_state();
                             //ReleaseDC();
		}
	}
	return msg.wParam;
Last edited on
That would be the easiest way to do it, yeah.

Actually, after these changes the jitteriness goes away:

1
2
3
4
5
6
7
		else
		{
			HDC hDC = GetDC(hWnd);
			_game.game_getvars(hDC, hWnd);
			_game.game_state();
			ReleaseDC(hWnd,hDC);
		}



I just wasn't sure yet how exactly to implement a timer.


If you want to do it right, it's actually kind of tricky. Here's a thread where I explain a clock based approach:

http://nesdev.parodius.com/bbs/viewtopic.php?p=57398#57398



One other thing I noticed: You shouldn't be able to move backwards into yourself. Like if you're moving to the right and you press 'a' to move left, you instantly die. You shouldn't allow that.
closed account (zwA4jE8b)
The snake does not allow backwords movement into self. Is it for you? I check for that collision.

And I made those changes. Thank you.

I know of using clock_t start/end to time programs. Should I use that in a timer/tick function.
so basically while in play state i would just call the timer function with the speed as the variable and it would 'pause' for that long.

Last edited on
Yeah it was letting me. I died a few times because I would try to do a U-turn by pressing up,left really fast when moving right, but if I did it too fast I would die. Eventually I figured out that I could just press left when moving right to die.

I'll check it out more when I get home from work.
closed account (zwA4jE8b)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void game::game_play()
{
//insert timer function here?
	_SNK->snake_nextpos();
	_SNK->snake_animate(_hDC);
	switch (_SNK->snake_collisions())
	{
	case 'e':
		break;
	case 'f':
		_foodeaten++;
		_score += _level * 5;
		_LVL->level_update(_hDC, _score, _highscore);
		if(_foodeaten == _foodneeded)
		{
			_level++;
			_state = 'r';
			break;
		}
		_LVL->level_shownext(_hDC, _foodeaten, _SNK->snake_getsegs());
		for(int i = 0; i < _level; i++)
			_SNK->snake_addseg();
		break;
	case 'o':
		_SNK->snake_dead(_hDC);
		_state = 'o';
		break;
	}
	Sleep(_speed);  //change to timer function here?
}


I think the wierd movement has to do with getting the direction from the message loop. But don't really know why.
Last edited on
//insert timer function here?


Not there. It needs to go higher up in the logic. Typically it should be in the main loop alongside the message polling.

From that other thread:

1
2
3
4
5
6
7
8
9
while( emulator_running ) 
{ 
   ProcessMessagesAndUserInput(); 

   if( user_is_pressing_fastforward) 
      RegulateFrameRate_Clock( fastforward_fps ); 
   else 
      RegulateFrameRate_Clock(0); 
} 


Or in your case:

1
2
3
4
5
6
7
8
9
while( game_running )
{
  while(PeekMessage(...))
  {
    // translate/dispatch messages
  }

  RegulateFrameRate_Clock( desired_game_fps );
}
Last edited on
closed account (zwA4jE8b)
cool thank you much. I will work on implementing that.
closed account (zwA4jE8b)
Updated code, removed Sleep() and replaced with timer using clock_t, also utilized ReleaseDC().

Should run great now.

http://www.mediafire.com/?db959tciirdd0

p.s. it's not a true framerate but it regulates the speed well enough.

closed account (zwA4jE8b)
lol, seems a little advanced for my game but thanks for the links, great reading material.
Runs fine here. =)

More things I noticed:

1) Moving backwards is still allowed. I don't see anywhere where you're trying to prevent it. Looks like keydown messages go straight to game_input which directly sets the snake's direction.

2) You have a small memory leak. ~8K a second. Run the program with Task manager open and watch the memory footprint of the program climb and climb. It only happens in the actual game part, so the issue is likely in game_play or one of the functions it calls. I haven't looked any more into it.

3) You get a compiler warning, and for good reason:

1
2
3
4
5
	HDC hDC;

	MSG msg;

	_game.game_getvars(hDC, hWnd);


hDC is uninitialized, so you're basically giving game_getvars a bad DC. It doesn't seem to affect anything so the DC probably just isn't being used. If that's the case, you should probably get rid of that function (or at least don't pass a DC to it)


4) Your while(clock() < wait){} loop does not play nice in multitasking environments and sucks life out of laptop batteries. Failure to sleep causes your program to eat up 100% CPU time.


5) You don't seem to be doing complete rendering, but rather are only updating the snake as he moves. This also doesn't play nice in a multitasking environment. Try this out:

- start the game
- switch to another window... one that overlaps your game window or is maximized.
- switch back to your game
- game is now unplayable





It's also worth noting that most of these tricky problems are due to the complexities of WinAPI. If you were using a game lib like SFML you wouldn't be having these issues.


CreativeMFS wrote:
It should be 100% bug free


It never is. ;)
closed account (zwA4jE8b)
Well it was a fun project. Guess it is time to move to a graphics lib.
I recommend SDL.
I recommend SFML (you can use C-SFML for C, PySFML for Python or SFML.Net for C#).
Pages: 1234