某天晚上閒着無聊就寫了個貪喫蛇鏈表,然後第二天就開始就主程序了,很快就寫完了,所以大家如果有好的思路,不妨也動動手嘛。好記性不如爛筆頭嘛。貪喫蛇的思路挺簡單的,就是用一個鏈表來保存蛇的路線,不過這個鏈表是經過特殊構造的,主要思路就是把客戶區分成若干個小方格子,然後鏈表會保存x和y座標,這個算是最重要的了,其它的都挺簡單的,在這裏就不贅述了。
打開vc6,然後新建一個win32空項目就可以了。
這個是運行截圖
這個是snake_list.h
#ifndef SNAKE_LIST_H
#define SNAKE_LIST_H
#define CLIENT_WIDTH 600
#define CLIENT_HEIGHT 600
#define ARRAY_COUNT 1600
#define ARRAY_WIDTH 40
#define ARRAY_HEIGHT 40
#define SANKE_UNIT 15
#define SNAKE_NUM 5
//定製版貪喫蛇鏈表
typedef struct Snake_List{
int x;//x座標
int y;//y座標
struct Snake_List* next;
}snake_list;
extern void init_snake(snake_list** head, char* snake_array);//初始化蛇
extern int add_head_hit(const int* x, const int* y, snake_list** head, char* snake_array);//撞上蛇
extern int add_head_no_hit(const int* x, const int* y, snake_list** head, char* snake_array);//沒撞上蛇
extern void destory(snake_list* head);//清空蛇
extern void get_head_info(snake_list* head, int *x, int *y);//獲取蛇頭
#endif
這個是snake_list.c
#include "snake_list.h"
#include <stdio.h>
#include <stdlib.h>
static snake_list* snake_tail;//蛇僞尾巴
static void set_snake_tail(snake_list* head);//設置新的蛇僞尾巴
void init_snake(snake_list** head, char* snake_array)
{
snake_list *p, *q;
int i, max_num;
max_num = 18 + SNAKE_NUM;
for (i = 18; i < max_num; i++) {//默認蛇長5個單位 座標從20*ARRAY_WIDTH 13開始
p = (snake_list* )malloc(sizeof(snake_list));
if (i == 18) {
*head = p;
} else {
q->next = p;
if (i == max_num - 2) {
snake_tail = p;//設置僞尾巴
}
}
p->x = 30;
p->y = i;
snake_array[p->x*ARRAY_WIDTH+p->y] = 1;//更改蛇數組的位
q = p;
}
p->next = NULL;
}
//x, y是撞擊的位置座標,撞擊後頭部改變,尾巴不變
int add_head_hit(const int* x, const int* y, snake_list** head, char* snake_array)
{
snake_list *p, *q;
p = (snake_list*)malloc(sizeof(snake_list));
q = *head;
*head = p;
(*head)->x = *x;
(*head)->y = *y;
(*head)->next = q;
snake_array[*x*ARRAY_WIDTH+*y] = 1;
return 1;
}
//x, y是前進的位置座標,前進後頭部改變,尾巴改變
int add_head_no_hit(const int* x, const int* y, snake_list** head, char* snake_array)
{
snake_list *p, *q;
p = (snake_list*)malloc(sizeof(snake_list));
q = *head;
*head = p;
(*head)->x = *x;
(*head)->y = *y;
(*head)->next = q;
snake_array[*x*ARRAY_WIDTH+*y] = 1;
p = snake_tail;//設置新的尾巴
q = p->next;
p->next = NULL;
snake_array[q->x*ARRAY_WIDTH+q->y] = 0;
free(q);
set_snake_tail(*head);
return 1;
}
void destory(snake_list* head)
{
snake_list *p, *q;
p = head;
while (p) {
q = p->next;
free (p);
p = q;
}
}
void get_head_info(snake_list* head, int *x, int *y)
{
*x = head->x;
*y = head->y;
}
static void set_snake_tail(snake_list* head)
{
snake_list* temp;
temp = head;
while (temp->next->next) {//找到到第二個位置
temp = temp->next;
}
snake_tail = temp;
}
這個是resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by resource.rc
//
#define IDB_BITMAP1 101
#define IDI_ICON1 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
這個是snake.c
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include "snake_list.h"
#include "resource.h"
#define bool int
#define true 1
#define false 0
#define TIMERID 201314
static HINSTANCE ghInstance;
static UINT gDirection;
static RECT gClientRect;
static POINT gSnakeFood;//食物
static bool gStop;//是否暫停
static snake_list* gSnakeHead;//蛇頭
static bool gGameStart;//遊戲是否開始
static char gSnakeArray[ARRAY_HEIGHT*ARRAY_WIDTH];//保存蛇
的路徑
void Init(HWND hwnd);//初始化一些變量
void HandleMove(HWND hwnd, UINT keyCode);//處理上下左右鍵消息
void HandleQuit(HWND hwnd);//處理用戶是否退出
void DrawSnake(HWND hwnd);//繪製蛇的身體
void GenerateFood();//隨機產生食物
void AutoForward(HWND hwnd);//自動前進
LRESULT CALLBACK WinProc(HWND hwnd,UINT uMsg,WPARAM wpara,LPARAM lpara);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nShowCmd )
{
WNDCLASS wndclass;
MSG msg;
HWND hwnd;
RECT windowRect, clientRect;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wndclass.hCursor = LoadCursor(hInstance, IDC_UPARROW);//光標屬性
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE
(IDI_ICON1));//圖標
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WinProc;
wndclass.lpszClassName = "snake";
wndclass.lpszMenuName = NULL;//無菜單
wndclass.style = CS_HREDRAW | CS_VREDRAW;//窗口風格
ghInstance = hInstance;
//註冊窗口
RegisterClass(&wndclass);
//創建窗口
hwnd = CreateWindow("snake", "Snake-by-inconsolablev",
WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX, 0, 0,
CLIENT_WIDTH, CLIENT_HEIGHT, NULL, NULL, ghInstance,
NULL);
//調整客戶區的大小
GetWindowRect(hwnd,&windowRect);
GetClientRect(hwnd,&clientRect);
windowRect.right += CLIENT_WIDTH - clientRect.right +
clientRect.left;
windowRect.bottom += CLIENT_HEIGHT - clientRect.bottom +
clientRect.top;
MoveWindow(hwnd, (GetSystemMetrics(SM_CXSCREEN) -
windowRect.right + windowRect.left) / 2, windowRect.top,
windowRect.right - windowRect.left, windowRect.bottom -
windowRect.top, true);
Init(hwnd);
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinProc(HWND hwnd,UINT uMsg,WPARAM wpara,LPARAM lpara)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (wpara == VK_SPACE && gGameStart == false) {
gGameStart = true;
GenerateFood();
SetTimer(hwnd, TIMERID, 150, NULL);
} else if (wpara == VK_RETURN && gGameStart == true)
{//Enter 暫停
KillTimer(hwnd, TIMERID);
gStop = true;
InvalidateRect(hwnd, &gClientRect, false);
} else if (wpara == VK_SPACE && gStop == true) {
//繼續遊戲
gStop = false;
SetTimer(hwnd, TIMERID, 150, NULL);
} else if (gGameStart == true && gStop == false) {
HandleMove(hwnd, wpara);
}
break;
case WM_TIMER:
HandleMove(hwnd, gDirection);
break;
case WM_PAINT:
DrawSnake(hwnd);
break;
case WM_CLOSE:
if (IDYES == MessageBox(hwnd,"是否真的結
束?","snake",MB_YESNO))
{
KillTimer(hwnd, TIMERID);
DestroyWindow(hwnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wpara,lpara);
}
return (LRESULT)NULL;
}
void Init(HWND hwnd)
{
gGameStart = false;
gStop = false;
gDirection = VK_LEFT;//默認左邊
memset(gSnakeArray, 0, ARRAY_HEIGHT*ARRAY_WIDTH);
GetClientRect(hwnd, &gClientRect);
init_snake(&gSnakeHead, gSnakeArray);
}
void HandleQuit(HWND hwnd)
{
KillTimer(hwnd, TIMERID);
destory(gSnakeHead);
Init(hwnd);
InvalidateRect(hwnd, &gClientRect, false);
}
void HandleMove(HWND hwnd, UINT keyCode)
{
static POINT basePoint;
char temp;
get_head_info(gSnakeHead, &basePoint.x, &basePoint.y);
switch (keyCode){
case VK_UP:
if (basePoint.x != 0) {//沒到達最頂端就可以繼續
basePoint.x--;
temp = gSnakeArray
[basePoint.x*ARRAY_WIDTH+basePoint.y];
if (temp == 0) {
//無障礙物
gDirection = VK_UP;
add_head_no_hit(&basePoint.x,
&basePoint.y, &gSnakeHead, gSnakeArray);
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 2) {
//碰到食物 喫掉
gDirection = VK_UP;
add_head_hit(&basePoint.x, &basePoint.y,
&gSnakeHead, gSnakeArray);
GenerateFood();
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 1) {
if (gDirection != VK_DOWN) {//蛇繞成一團
而不是後退
HandleQuit(hwnd);
}
}
} else {
HandleQuit(hwnd);
}
break;
case VK_DOWN:
if (basePoint.x != ARRAY_HEIGHT - 1) {//沒到達最下端就可
以繼續
basePoint.x++;
temp = gSnakeArray
[basePoint.x*ARRAY_WIDTH+basePoint.y];
if (temp == 0) {
//無障礙物
gDirection = VK_DOWN;
add_head_no_hit(&basePoint.x,
&basePoint.y, &gSnakeHead, gSnakeArray);
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 2) {
//碰到食物 喫掉
gDirection = VK_DOWN;
add_head_hit(&basePoint.x, &basePoint.y,
&gSnakeHead, gSnakeArray);
GenerateFood();
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 1) {
if (gDirection != VK_UP) {//蛇繞成一團 而
不是後退
HandleQuit(hwnd);
}
}
} else {
HandleQuit(hwnd);
}
break;
case VK_LEFT:
if (basePoint.y != 0) {//沒到達最左端就可以繼續
basePoint.y--;
temp = gSnakeArray
[basePoint.x*ARRAY_WIDTH+basePoint.y];
if (temp == 0) {
//無障礙物
gDirection = VK_LEFT;
add_head_no_hit(&basePoint.x,
&basePoint.y, &gSnakeHead, gSnakeArray);
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 2) {
//碰到食物 喫掉
gDirection = VK_LEFT;
add_head_hit(&basePoint.x, &basePoint.y,
&gSnakeHead, gSnakeArray);
GenerateFood();
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 1) {
if (gDirection != VK_RIGHT) {//蛇繞成一團
而不是後退
HandleQuit(hwnd);
}
}
} else {
HandleQuit(hwnd);
}
break;
case VK_RIGHT:
if (basePoint.y != ARRAY_WIDTH - 1) {//沒到達最右端就可以
繼續
basePoint.y++;
temp = gSnakeArray
[basePoint.x*ARRAY_WIDTH+basePoint.y];
if (temp == 0) {
//無障礙物
gDirection = VK_RIGHT;
add_head_no_hit(&basePoint.x,
&basePoint.y, &gSnakeHead, gSnakeArray);
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 2) {
//碰到食物 喫掉
gDirection = VK_RIGHT;
add_head_hit(&basePoint.x, &basePoint.y,
&gSnakeHead, gSnakeArray);
GenerateFood();
InvalidateRect(hwnd, &gClientRect,
false);
} else if (temp == 1) {
if (gDirection != VK_LEFT) {//蛇繞成一團
而不是後退
HandleQuit(hwnd);
}
}
} else {
HandleQuit(hwnd);
}
break;
default:
break;
}
}
void GenerateFood()
{
int i = 0, j = 0;
static short int temp[ARRAY_COUNT];
for (i = 0; i < ARRAY_COUNT; i++) {
if (gSnakeArray[i] == 0) {
temp[j++] = i;//保存是0的位置
}
}
//然後在這些元素是0裏面取一個就行了
srand((unsigned)time(NULL));
j = rand() % j; //隨機獲取一個是0的元素
gSnakeFood.x = temp[j] / ARRAY_WIDTH;
gSnakeFood.y = temp[j] % ARRAY_WIDTH;
gSnakeArray[gSnakeFood.x*ARRAY_WIDTH+gSnakeFood.y] = 2;//食物標記
}
void DrawSnake(HWND hwnd)
{
static HDC hMemDC, hDC;
static HBRUSH hBrush, hOldBrush;
static HBITMAP hBitmap, hOldBitmap;
static HFONT hFont, hOldFont;
static LOGFONT logFont;
POINT tempPoint;
snake_list* temp;
PAINTSTRUCT ps;
static RECT fontRect;
char str[25];
temp = gSnakeHead;
hDC = BeginPaint(hwnd, &ps);
hMemDC = CreateCompatibleDC(hDC);
hBitmap = (HBITMAP)LoadBitmap(ghInstance, MAKEINTRESOURCE
(IDB_BITMAP1));
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//保存舊的位
圖
hBrush = CreateSolidBrush(RGB(87, 66, 189));
hOldBrush = (HBRUSH)SelectObject(hMemDC, hBrush);//保存舊的畫刷
SetBkMode(hMemDC, TRANSPARENT);
while (temp) {//遍歷整個蛇 繪製蛇身
tempPoint.x = temp->y*SANKE_UNIT;//notify this place
tempPoint.y = temp->x*SANKE_UNIT;
Rectangle(hMemDC, tempPoint.x, tempPoint.y,
tempPoint.x+SANKE_UNIT, tempPoint.y+SANKE_UNIT);
temp = temp->next;
}
if (gGameStart == false) {//遊戲未開始 寫提示
sprintf(str, "Press Space To Start!");
SetTextColor(hMemDC, RGB(255, 0, 0));
ZeroMemory(&logFont, sizeof(LOGFONT));
logFont.lfCharSet = ANSI_CHARSET;
logFont.lfHeight = 30; //設置字體的大小
logFont.lfWidth = 15;
logFont.lfWeight = 10;
hFont = CreateFontIndirect(&logFont);
fontRect.left = 150;
fontRect.right = fontRect.left+400;
fontRect.top = 100;
fontRect.bottom = 400;
hOldFont = (HFONT)SelectObject(hMemDC,hFont);//保存舊的的
字體
DrawText(hMemDC, str, strlen(str), &fontRect, DT_BOTTOM);
} else {
if (gStop == true) {
//暫停遊戲
sprintf(str, "Press Space to Continue!");
SetTextColor(hMemDC, RGB(255, 0, 0));
hFont = CreateFontIndirect(&logFont);
hOldFont = (HFONT)SelectObject(hMemDC,hFont);//保
存舊的的字體
DrawText(hMemDC, str, strlen(str), &fontRect,
DT_BOTTOM);
} else {
//繼續遊戲
sprintf(str, "Press Enter to Stop!");
SetTextColor(hMemDC, RGB(255, 0, 0));
hFont = CreateFontIndirect(&logFont);
hOldFont = (HFONT)SelectObject(hMemDC,hFont);//保
存舊的的字體
DrawText(hMemDC, str, strlen(str), &fontRect,
DT_BOTTOM);
}//繪製食物
DeleteObject(hBrush);
hBrush = CreateSolidBrush(RGB(55, 208, 47));
hOldBrush = (HBRUSH)SelectObject(hMemDC, hBrush);
tempPoint.x = gSnakeFood.y*SANKE_UNIT;//notify this place
tempPoint.y = gSnakeFood.x*SANKE_UNIT;
Rectangle(hMemDC, tempPoint.x, tempPoint.y,
tempPoint.x+SANKE_UNIT, tempPoint.y+SANKE_UNIT);
}
BitBlt(hDC, 0, 0, gClientRect.right - gClientRect.left,
gClientRect.bottom - gClientRect.top, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldFont);//選回舊的
SelectObject(hMemDC, hOldBitmap);
SelectObject(hMemDC, hOldBrush);
EndPaint(hwnd,&ps);
DeleteDC(hMemDC);//釋放資源
DeleteDC(hDC);
DeleteObject(hBitmap);
DeleteObject(hFont);
DeleteObject(hBrush);
}
就寫到這裏把,明天還得早起呢。