华哥和高鑫告诉我。要多写一下博客。记录下自己的学习问题及感想。这样就能更好的向大家学习交流。自己也能从中找到更大的学习乐趣和广泛的知识。
昨天。醒哥说我学了那么久自己也可以试一下先写些简单的小程序练习一下。这样就能从实践中学习和发现一些从课本上找不到的问题。以便向大家请教。是的,自己在一个自闭的角落是学习。真的进步很慢。所以。我会以后自己多写博客。多问问题。希望大家能多多的指教。谢谢大家。
昨天就先试写了一个贪吃蛇。因为自己早在两个星期前就看过高鑫的源码。所以对于它的思路也非常清楚了。但还是从写的过程中发现了很多细节的问题。先附上代码
//贪吃蛇
#include <windows.h>
#include <stdlib.h>
#include <time.h>
int NUM=5;
#define ID_TIMER 1
int i ,BTN = 4 ;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
struct Snake
{
int left;
int top;
int right;
int button;
}s[500];
struct food
{
int x;
int y;
}f;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Retro Snaker " ) ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ( "This program requires Windows NT!" ),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ( "Retro Snaker __Crazw"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HDC hdcScreen;
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
static int cxClient,cyClient;
// int i ,BTN = 3 ; // wsm不能在这定义?????????????????????????
switch (message)
{
case WM_CREATE:
SetTimer (hwnd, ID_TIMER, 200, NULL) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam); //cxclient 和 cyclient GetClientRect 区别有吗?????????
s[0].left = 100;
s[0].top = 100;
s[0].right = 120;
s[0].button = 120;
for(i = 1;i < NUM ;i++)
{
s[i].left = s[i - 1].left + 20;
s[i].top = s[0].top ;
s[i].right = s[i - 1].right+ 20;
s[i].button = s[0].button;
}
srand(time(0));
f.x = (rand() % cxClient) / 20 * 20 ; //确保能与蛇头相容;从高鑫那才想到这一点。
f.y = (rand() % cyClient) / 20 * 20;
//InvalidateRect(hwnd,NULL,true);
return 0;
case WM_TIMER:
//响应按键
if(BTN == 1)
{
for(i = 0;i < NUM - 1;i++)
{
s[i].left = s[i + 1].left;
s[i].top = s[i + 1].top;
s[i].right = s[i + 1].right;
s[i].button = s[i + 1].button;
}
s[NUM - 1].top -= 20;
s[NUM - 1].button -= 20;
}
else if(BTN == 2)
{
for(i = 0;i < NUM - 1;i++)
{
s[i].left = s[i + 1].left;
s[i].top = s[i + 1].top;
s[i].right = s[i + 1].right;
s[i].button = s[i + 1].button;
}
s[NUM - 1].top += 20;
s[NUM - 1].button += 20;
}
else if(BTN == 3)
{
for(i = 0;i < NUM - 1;i++)
{
s[i].left = s[i + 1].left;
s[i].top = s[i + 1].top;
s[i].right = s[i + 1].right;
s[i].button = s[i + 1].button;
}
s[NUM - 1].right -= 20;
s[NUM - 1].left -= 20;
}
else if(BTN == 4)
{
for(i = 0;i < NUM - 1;i++)
{
s[i].left = s[i + 1].left;
s[i].top = s[i + 1].top;
s[i].right = s[i + 1].right;
s[i].button = s[i + 1].button;
}
s[NUM - 1].right += 20;
s[NUM - 1].left += 20;
}
//怎么死
if(s[NUM - 1].right > cxClient || s[NUM - 1].left < 0 || s[NUM - 1].top < 0 ||s[NUM - 1].button > cyClient +20) //触边死
{
KillTimer(hwnd,ID_TIMER);
MessageBox(hwnd,TEXT("Sorry,You lost!"),TEXT("Result"),MB_OK|MB_ICONERROR);
exit(0);
}
for(i = 0;i < NUM - 1;i ++)
{
if(s[NUM - 1].left ==s[i].left&&s[NUM - 1].right == s[i].right && s[NUM - 1].top == s[i].top && s[NUM - 1].button == s[i].button)
{
KillTimer(hwnd,ID_TIMER);
MessageBox(hwnd,TEXT("Sorry,You lost!"),TEXT("Result"),MB_OK|MB_ICONERROR);
exit(0);
}
}
//增长
switch(BTN)
{
case 1:
if(s[NUM - 1].top == f.y + 20 && s[NUM - 1].left == f.x)
{
NUM ++;
s[NUM - 1].top = f.y;
s[NUM - 1].left = f.x;
s[NUM - 1].right = f.x + 20;
s[NUM - 1].button = f.y + 20;
f.x = (rand() % cxClient) / 20 * 20 ;
f.y = (rand() % cyClient) / 20 * 20;
break ;
}
case 2:
if(s[NUM - 1].top == f.y && s[NUM - 1].left == f.x)
{
NUM ++;
s[NUM - 1].top = f.y;
s[NUM - 1].left = f.x;
s[NUM - 1].right = f.x + 20;
s[NUM - 1].button = f.y + 20;
f.x = (rand() % cxClient) / 20 * 20 ;
f.y = (rand() % cyClient) / 20 * 20;
break ;
}
case 3:
if(s[NUM - 1].top == f.y && s[NUM - 1].left == f.x)
{
NUM ++;
s[NUM - 1].top = f.y;
s[NUM - 1].left = f.x;
s[NUM - 1].right = f.x + 20;
s[NUM - 1].button = f.y + 20;
f.x = (rand() % cxClient) / 20 * 20 ;
f.y = (rand() % cyClient) / 20 * 20;
break ;
}
case 4:
if(s[NUM - 1].top == f.y && s[NUM - 1].left == f.x)
{
NUM ++;
s[NUM - 1].top = f.y;
s[NUM - 1].left = f.x;
s[NUM - 1].right = f.x + 20;
s[NUM - 1].button = f.y + 20;
f.x = (rand() % cxClient) / 20 * 20 ;
f.y = (rand() % cyClient) / 20 * 20;
break ;
}
default:
break;
}
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_UP:
BTN = 1;
break;
case VK_DOWN:
BTN = 2;
break;
case VK_LEFT:
BTN = 3;
break;
case VK_RIGHT:
BTN = 4;
break;
}
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
for(i = 0;i < NUM - 1;i++)
{
Rectangle(hdc,s[i].left,s[i].top,s[i].right,s[i].button);
}
SelectObject(hdc,(HBRUSH)GetStockObject(GRAY_BRUSH));
Rectangle(hdc,s[NUM - 1].left,s[NUM - 1].top,s[NUM - 1].right,s[NUM - 1].button);
Ellipse(hdc,f.x,f.y,f.x + 20,f.y + 20);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
KillTimer(hwnd,ID_TIMER);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
大致实现了贪吃蛇的基本功能。但是还有很多可以改进的地方。所以。希望大家能给于指点和意见。万分感谢。
补充:在处理碰框死亡时。高鑫说可以改进。在创建窗口时可以初始化窗口的大小和位置。做好全局安排蛇和食物的大小和位置。
又学习了一点。