Right, this is how the snake project stands at the moment:
Features:
- Slider Bar to control speed
- Food to eat
- Gets bigger when it eats food
- Scoring system dependent on the speed
- About, Start, Stop and Pause buttons
- A Redraw button to redraw the snake and the food
Source, also included in ZIP.
Code:
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#define RSTPIX(x,y) SetPixel(hDC,x,y,RGB(255,255,255))
#define SETPIX(x,y) SetPixel(hDC,x,y,RGB(255,0,0))
#define FOOD_SIZE 5
// Width of snakes food in pixels (Square)
#define SNAKE_INCREASE 50
// Amount to increase snakes tail by when eating food (Pixels)
#define WIN_SPOS 2
#define WIN_SLEN 300
BOOL playing, pause, redraw;
HWND start_game, score_win, speed_bar, pause_button,redraw_win, about_win;
unsigned int game_score;
unsigned char SNAKE_SPEED;
unsigned int random_no(void){
static unsigned short kvar = 23;
return ((GetTickCount() * kvar) % (WIN_SLEN - FOOD_SIZE - 2) + 3);
}
DWORD WINAPI SnakeThread(LPVOID lParam){
HDC hDC = GetDC((HWND)lParam);
char score_buf[30];
game_score = 0;
pause = FALSE;
SetWindowText(score_win,"0");
unsigned int SNAKE_LENGTH = 100, *snake = (unsigned int*) LocalAlloc(
LPTR,
sizeof(int) * (SNAKE_LENGTH * 2)
), i, hold, food[2];
unsigned char direction = 0;
BOOL eaten = FALSE, start_ = TRUE;
LPVOID temp_ptr;
if(!snake) return 0;
snake[0] = 20;
snake[1] = 20;
while(1){
while(pause || redraw){
if(redraw){
SetPixel(hDC,food[0],food[1],RGB(0,0,255));
StretchBlt(hDC,food[0],food[1],FOOD_SIZE,FOOD_SIZE,hDC,
food[0],food[1],1,1,SRCCOPY
);
for(i = 0;i < SNAKE_LENGTH;i++){
SETPIX(snake[i * 2],snake[(i * 2) + 1]);
}
redraw = FALSE;
}
if(!playing) break;
Sleep(30);
}
if(snake[(SNAKE_LENGTH - 1) * 2] && snake[((SNAKE_LENGTH - 1) * 2) + 1]){
RSTPIX(
snake[(SNAKE_LENGTH - 1) * 2],
snake[((SNAKE_LENGTH - 1) * 2) + 1]
);
}
for(i = ((SNAKE_LENGTH - 1)*2) + 1; i > 1; i--){
snake[i] = snake[i - 2];
}
if(GetAsyncKeyState(VK_RIGHT) && direction != 1) direction = 0;
else if(GetAsyncKeyState(VK_LEFT) && direction) direction = 1;
else if(GetAsyncKeyState(VK_DOWN) && direction != 3) direction = 2;
else if(GetAsyncKeyState(VK_UP) && direction != 2) direction = 3;
switch(direction){
case 0:
snake[0]++;
break;
case 1:
snake[0]--;
break;
case 2:
snake[1]++;
break;
case 3:
snake[1]--;
break;
}
if(GetPixel(hDC,snake[0],snake[1]) == RGB(255,0,0) ||
snake[0] <= WIN_SPOS + 1 || snake[0] >= WIN_SLEN ||
snake[1] <= WIN_SPOS + 1 || snake[1] >= WIN_SLEN ||
playing == FALSE){
if(playing){
MessageBox(NULL,"You Lose","Uranium-239",MB_OK);
}
for(i = 0;i < SNAKE_LENGTH;i++){
RSTPIX(snake[i * 2],snake[(i * 2) + 1]);
}
SetPixel(hDC,snake[0],snake[1],RGB(255,255,255));
RSTPIX(food[0],food[1]);
StretchBlt(hDC,food[0],food[1],FOOD_SIZE,FOOD_SIZE,hDC,
food[0],food[1],1,1,SRCCOPY
);
LocalFree(snake);
SetWindowText(start_game,"Start");
playing = FALSE;
EnableWindow(speed_bar,TRUE);
EnableWindow(pause_button,FALSE);
EnableWindow(redraw_win,FALSE);
if(pause){
SetWindowText(pause_button,"Pause");
pause = FALSE;
}
return 0;
}
SETPIX(snake[0],snake[1]);
if(snake[0] <= food[0] + FOOD_SIZE && snake[0] >= food[0] &&
snake[1] <= food[1] + FOOD_SIZE && snake[1] >= food[1]){
eaten = TRUE;
game_score += ((SNAKE_SPEED & 0xF)* 3) + 2;
sprintf(score_buf,"%i",game_score);
SetWindowText(score_win,score_buf);
if(temp_ptr = LocalReAlloc(
snake,
sizeof(int) * (2*(SNAKE_LENGTH + SNAKE_INCREASE)),
LMEM_FIXED
)){
snake = (unsigned int*)temp_ptr;
SNAKE_LENGTH += SNAKE_INCREASE;
}
}
if(eaten || start_){
if(!start_){
RSTPIX(food[0],food[1]);
StretchBlt(hDC,food[0],food[1],FOOD_SIZE,FOOD_SIZE,hDC,
food[0],food[1],1,1,SRCCOPY
);
}else start_ = FALSE;
food[0] = random_no();
food[1] = random_no();
SetPixel(hDC,food[0],food[1],RGB(0,0,255));
StretchBlt(hDC,food[0],food[1],FOOD_SIZE,FOOD_SIZE,hDC,
food[0],food[1],1,1,SRCCOPY
);
SETPIX(snake[0],snake[1]);
eaten = FALSE;
}
Sleep((15 - (SNAKE_SPEED & 0xF)) + 5);
}
return 0;
}
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "Snake";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil){
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_WINLOGO);
wincl.hIconSm = LoadIcon (NULL, IDI_WINLOGO);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
if (!RegisterClassEx (&wincl))
return 0;
hwnd = CreateWindowEx (
0,
szClassName,
"Snake",
WS_SYSMENU | WS_MINIMIZEBOX,
100,
100,
310,
422,
HWND_DESKTOP,
NULL,
hThisInstance,
NULL
);
ShowWindow (hwnd, nFunsterStil);
while (GetMessage (&messages, NULL, 0, 0)){
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
LRESULT CALLBACK BlockUserInput(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CHAR:
return 0;
break;
case WM_GETDLGCODE:
return DLGC_WANTALLKEYS;
break;
}
return CallWindowProc((WNDPROC)GetWindowLong(hWnd, GWL_USERDATA),hWnd,message,wParam,lParam);
}
PAINTSTRUCT Ps;
HFONT font;
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HDC hDC = 0;
static HANDLE hThread = 0;
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_PAINT:
hDC = BeginPaint(hwnd, &Ps);
font = CreateFont(25,12,0,0,FW_NORMAL,FALSE,FALSE,FALSE,
ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,DEFAULT_PITCH | FF_ROMAN,"Courier New"
);
SelectObject(hDC, font);
SetTextColor(hDC,RGB(255,0,0));
SetBkColor(hDC,RGB(0,0,0));
TextOut(hDC,2,365,"Speed:",6);
TextOut(hDC,2,340,"Score:",6);
DeleteObject(font);
Rectangle(hDC,WIN_SPOS,WIN_SPOS,WIN_SLEN + WIN_SPOS,WIN_SLEN + WIN_SPOS);
EndPaint(hwnd,&Ps);
break;
case WM_COMMAND:
if(LOWORD(wParam) == 34){
if(playing){
playing = FALSE;
}else{
SNAKE_SPEED = ((float)SendMessage(speed_bar,TBM_GETPOS,NULL,NULL)/100)*15;
EnableWindow(speed_bar,FALSE);
EnableWindow(pause_button,TRUE);
EnableWindow(redraw_win,TRUE);
playing = TRUE;
hThread = CreateThread(0,0,SnakeThread,hwnd,0,0);
SetWindowText(start_game,"Stop");
}
}else if(LOWORD(wParam) == 37){
if(playing){
if(pause){
pause = FALSE;
SetWindowText(pause_button,"Pause");
}else{
pause = TRUE;
SetWindowText(pause_button,"Resume");
}
}else EnableWindow(pause_button,FALSE);
}else if(LOWORD(wParam) == 36){
MessageBox(
NULL,
"Snake by Andrew Carter\n"
"A 2008 Uranium-239 Production",
"Uranium-239",
MB_OK
);
}else if(LOWORD(wParam) == 40){
if(!redraw) redraw = TRUE;
}
break;
case WM_CTLCOLOREDIT:
SetTextColor((HDC)wParam, RGB(255,255,255));
SetBkColor((HDC)wParam, RGB(0,0,0));
return (LRESULT)GetSysColorBrush(COLOR_3DHILIGHT);
break;
case WM_CREATE:
redraw_win = CreateWindowEx(
0,
"Button",
"Redraw",
WS_CHILD | WS_VISIBLE,
15,
304,
65,
30,
hwnd,
(HMENU)40,
NULL,
NULL
);
EnableWindow(redraw_win,FALSE);
about_win = CreateWindowEx(
0,
"Button",
"About",
WS_CHILD | WS_VISIBLE,
84,
304,
65,
30,
hwnd,
(HMENU)36,
NULL,
NULL
);
start_game = CreateWindowEx(
0,
"Button",
"Start",
WS_CHILD | WS_VISIBLE,
154,
304,
65,
30,
hwnd,
(HMENU)34,
NULL,
NULL
);
pause_button = CreateWindowEx(
0,
"Button",
"Pause",
WS_CHILD | WS_VISIBLE,
224,
304,
65,
30,
hwnd,
(HMENU)37,
NULL,
NULL
);
EnableWindow(pause_button,FALSE);
score_win = CreateWindowEx(
0,
"Edit",
"0",
WS_CHILD | WS_VISIBLE | ES_CENTER,
90,
340,
200,
16,
hwnd,
NULL,
NULL,
NULL
);
SetWindowLong(score_win,GWL_USERDATA,(LONG)SetWindowLong(score_win,
GWL_WNDPROC,(LONG)BlockUserInput));
speed_bar = CreateWindowEx(
0,
TRACKBAR_CLASS,
"Speed bar",
WS_CHILD | WS_VISIBLE,
90,
365,
200,
25,
hwnd,
NULL,
NULL,
NULL
);
SendMessage(speed_bar,TBM_SETPOS,TRUE,80);
break;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
And Snake package attached.
My top score is just over 520 I think.