(上学期写的,确实很冗余的代码,菜鸟一枚还请大家包涵)
2个文件:snakeList.h和snake.cpp
首先是第一个:
#include <windows.h>
#pragma once
typedef struct tagNODE
{
POINT apt[4];
struct tagNODE * previous, *next;
}NODE;
typedef struct tagSNAKE
{
int length;
NODE *head, *tail;
}SNAKE;
其次:
/*********************************************************
Wy 05/21/2013
**********************************************************/
#include <windows.h>
#include <cstdlib>
#include <ctime>
#include "snakeList.h"
#define UNIT 30
#define ID_TIMER_SPEED 1
#define ID_TIMER_TIME 3
enum direction
{//记录蛇移动的方向
UP, DOWN, RIGHT, LEFT
}dire1,dire2;
//判断是否吃到食物,作为全局变量,是因为如果写过程函数中,则后面的函数中
//要用到eat,则需要给许多函数传入eat这个参数,太麻烦,所以设为全局变量。
bool eat1 = false;
//定义一个全局变量,当蛇遇到墙壁或者自身时,将其设置为true
bool game_over = false;
void square (HDC, POINT[]);
void border (HDC);
void drawSnake (HDC, SNAKE*);
bool isBorder (POINT[]);
bool isFood (POINT[], POINT[]);
bool isSelf (SNAKE*, SNAKE*, POINT[]);
void drawUp (SNAKE*, SNAKE*, POINT[]);
void drawDown (SNAKE*, SNAKE*, POINT[]);
void drawRight (SNAKE*, SNAKE*, POINT[]);
void drawLeft (SNAKE*, SNAKE*, POINT[]);
void runDef (SNAKE*, SNAKE*, direction*, POINT[]);
void creatFood (SNAKE*, SNAKE*, POINT[]);
void initializeSnake1(SNAKE*);
void initializeSnake2(SNAKE*);
void drawFood (HDC,POINT[]);
void clearSnake(SNAKE*);
void initializeGame (SNAKE*, SNAKE*);
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
//注册窗口类
static TCHAR szAppName[] = TEXT ("snake");
HWND hwnd;
MSG msg;
WNDCLASS wcls;
wcls.cbClsExtra = 0;
wcls.cbWndExtra = 0;
wcls.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wcls.hCursor = LoadCursor (NULL, IDC_ARROW);
wcls.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wcls.hInstance = hInstance;
wcls.lpfnWndProc = WndProc;
wcls.lpszClassName = szAppName;
wcls.lpszMenuName = NULL;
wcls.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClass (&wcls))
{
MessageBox (NULL, TEXT ("Program requires WinNT!"), szAppName, MB_ICONERROR);
}
//创建窗口
hwnd = CreateWindow (szAppName, TEXT("snake"),
WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT,
23*UNIT-13, 15*UNIT,
NULL, NULL, hInstance, NULL);
//显示和更新窗口
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 int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps;
static SNAKE snake1,snake2;//定义蛇结构体
static POINT food[4];//食物
static bool isKeyDown = false;//是否有方向键按下
static int time;
TCHAR szBuffer[1000];
switch (message)
{
case WM_SIZE:
cxClient = LOWORD (lParam);
cyClient = HIWORD (lParam);
return 0;
case WM_CREATE:
SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//设定游戏速度定时器
SetTimer (hwnd, ID_TIMER_TIME, 1000, NULL);//设定游戏时间定时器
initializeSnake1(&snake1);//初始化蛇1
initializeSnake2(&snake2);//初始化蛇2
dire2 = RIGHT;//初始化为向右移动
dire1 = RIGHT;//初始化为向右移动
creatFood(&snake1,&snake2,food);//创建食物
return 0;
case WM_TIMER:
switch (wParam)
{
case ID_TIMER_SPEED:
InvalidateRect (hwnd, NULL, TRUE);//如果设为FALSE,则蛇移动后会留下痕迹
return 0;
case ID_TIMER_TIME:
++time;
return 0;
default:
return 0;
}
case WM_CHAR:
{
switch (wParam)
{
case 'w':
if (dire2 != DOWN)//防止反向移动,以下类似
{
isKeyDown = true;
dire2 = UP; //将方向更新
drawUp(&snake2, &snake1, food);//更行蛇的结点坐标
}
return 0;
case 's':
if (dire2 != UP)
{
isKeyDown = true;
dire2 = DOWN;
drawDown(&snake2, &snake1, food);
}
return 0;
case 'd':
if (dire2 != LEFT)
{
isKeyDown = true;
dire2 = RIGHT;
drawRight(&snake2, &snake1, food);
}
return 0;
case 'a':
if (dire2 != RIGHT)
{
isKeyDown = true;
dire2 = LEFT;
drawLeft(&snake2, &snake1, food);
}
return 0;
}
return 0;
}
case WM_KEYDOWN://按键控制
{
switch (wParam)
{
case VK_UP:
if (dire1 != DOWN)//防止反向移动,以下类似
{
isKeyDown = true;
dire1 = UP; //将方向更新
drawUp(&snake1, &snake2, food);//更行蛇的结点坐标
}
return 0;
case VK_DOWN:
if (dire1 != UP)
{
isKeyDown = true;
dire1 = DOWN;
drawDown(&snake1, &snake2, food);
}
return 0;
case VK_RIGHT:
if (dire1 != LEFT)
{
isKeyDown = true;
dire1 = RIGHT;
drawRight(&snake1, &snake2, food);
}
return 0;
case VK_LEFT:
if (dire1 != RIGHT)
{
isKeyDown = true;
dire1 = LEFT;
drawLeft(&snake1, &snake2, food);
}
return 0;
case VK_SPACE:
KillTimer(hwnd,1);
if (IDNO == MessageBox(hwnd,TEXT("回到游戏?"),TEXT("暂停游戏"),MB_YESNO))
{
PostQuitMessage(0);
}
else
{
SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//恢复定时器
}
return 0;
case VK_ESCAPE:
KillTimer(hwnd,1);
if (IDYES == MessageBox(hwnd,TEXT("退出游戏?"),TEXT("退出游戏"),MB_YESNO))
{
PostQuitMessage(0);
}
else
{
SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//恢复定时器
}
return 0;
default:
return 0;
}
InvalidateRect (hwnd, NULL, TRUE);//使客户区无效
return 0;
}
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
border(hdc);//画边框
if (!isKeyDown)//判断是否有键按下
{
runDef(&snake1,&snake2,&dire1,food);//如果没有,则按默认方式,即原方向移动
runDef(&snake2,&snake2,&dire2,food);//如果没有,则按默认方式,即原方向移动
}
if (game_over)
{
KillTimer(hwnd,1);//暂停定时器
if (IDNO == MessageBox(hwnd,TEXT("Game Over! Try Again?"),TEXT("Snake!"),MB_YESNO))
{
PostQuitMessage(0);
}
else
{
initializeGame(&snake1,&snake2);
time = 0;
SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//恢复定时器
}
}
drawSnake (hdc, &snake1);//画蛇1
drawSnake (hdc, &snake2);//画蛇2
drawFood(hdc,food);//画食物
TextOut(hdc,10,12*UNIT+3,TEXT("玩家1控制:上W,下S,左A,右D 玩家2控制:上↑,下↓,左←,右→"),50);
TextOut(hdc,10,12*UNIT+25,TEXT("空格键:暂停游戏"),8);
TextOut(hdc,150,12*UNIT+25,TEXT("Esc键:退出游戏"),9);
TextOut(hdc,300,12*UNIT+25,szBuffer,wsprintf(szBuffer,TEXT("Player1 Score: %d"),snake1.length));
TextOut(hdc,450,12*UNIT+25,szBuffer,wsprintf(szBuffer,TEXT("Player2 Score: %d"),snake2.length));
TextOut(hdc,600,12*UNIT+25,szBuffer,wsprintf(szBuffer,TEXT("time: %d"),time));
EndPaint (hwnd, &ps);
isKeyDown = false;//将其恢复为false
return 0;
case WM_DESTROY:
KillTimer (hwnd, ID_TIMER_SPEED);
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
void square (HDC hdc, POINT apt[4])
{//paint a square based on 4 points
MoveToEx (hdc, apt[0].x, apt[0].y, NULL);
LineTo (hdc, apt[1].x, apt[1].y);
MoveToEx (hdc, apt[1].x, apt[1].y, NULL);
LineTo (hdc, apt[2].x, apt[2].y);
MoveToEx (hdc, apt[2].x, apt[2].y, NULL);
LineTo (hdc, apt[3].x, apt[3].y);
MoveToEx (hdc, apt[3].x, apt[3].y, NULL);
LineTo (hdc, apt[0].x, apt[0].y);
return;
}
void border (HDC hdc)
{//画出边框
POINT border[22][4];
for (int i=0; i!=22; ++i)
{//初始化上边框的每个方格的四个点坐标
border[i][0].x = i*UNIT;
border[i][0].y = 0;
border[i][1].x = (i+1)*UNIT;
border[i][1].y = 0;
border[i][2].x = (i+1)*UNIT;
border[i][2].y = UNIT;
border[i][3].x = i*UNIT;
border[i][3].y = UNIT;
}
for (int i=0; i!=22; ++i)
{//画出上边框
square (hdc, border[i]);
}
for (int i=0; i!=22; ++i)
{//初始化下边框每个方格的四个点坐标
border[i][0].x = i*UNIT;
border[i][0].y = 11*UNIT;
border[i][1].x = (i+1)*UNIT;
border[i][1].y = 11*UNIT;
border[i][2].x = (i+1)*UNIT;
border[i][2].y = 12*UNIT;
border[i][3].x = i*UNIT;
border[i][3].y = 12*UNIT;
}
for (int i=0; i!=22; ++i)
{//画出下边框
square (hdc, border[i]);
}
for (int i=0; i!=10; ++i)
{//初始化左边框每个方格的四个点坐标
border[i][0].x = 0;
border[i][0].y = (i+1)*UNIT;
border[i][1].x = UNIT;
border[i][1].y = (i+1)*UNIT;
border[i][2].x = UNIT;
border[i][2].y = (i+2)*UNIT;
border[i][3].x = 0;
border[i][3].y = (i+2)*UNIT;
}
for (int i=0; i!=22; ++i)
{//画出左边框
square (hdc, border[i]);
}
for (int i=0; i!=10; ++i)
{//初始化右边框每个方格的四个点坐标
border[i][0].x = 21*UNIT;
border[i][0].y = (i+1)*UNIT;
border[i][1].x = 22*UNIT;
border[i][1].y = (i+1)*UNIT;
border[i][2].x = 22*UNIT;
border[i][2].y = (i+2)*UNIT;
border[i][3].x = 21*UNIT;
border[i][3].y = (i+2)*UNIT;
}
for (int i=0; i!=22; ++i)
{//画出右边框
square (hdc, border[i]);
}
return;
}
void drawSnake (HDC hdc, SNAKE* s)
{
NODE* iter = s->head;
for (int i=0; i!=s->length; ++i)
{
square (hdc, iter->apt);
iter = iter->next;
}
iter = NULL;
free (iter);
return;
}
bool isBorder (POINT apt[4])
{
if (apt[0].x==0 || apt[0].x==21*UNIT
|| apt[0].y==0 || apt[0].y==11*UNIT)
return true;
else
return false;
}
bool isFood (POINT food[4], POINT apt[4])
{
if (apt[0].x == food[0].x && apt[0].y == food[0].y)
return true;
else
return false;
}
bool isSelf (SNAKE* s1, SNAKE* s2, POINT apt[4])
{
NODE* current = s1->head;
for (int i=0; i!=s1->length; ++i)
{
if (current->apt[0].x==apt[0].x && current->apt[0].y==apt[0].y)
return true;
current = current->next;
}
current = s2->head;
for (int i=0; i!=s2->length; ++i)
{
if (current->apt[0].x==apt[0].x && current->apt[0].y==apt[0].y)
return true;
current = current->next;
}
return false;
}
void drawUp (SNAKE* s1, SNAKE* s2, POINT food[4])
{
POINT temp[4];//蛇头上方的方格
temp[0].x = s1->head->apt[0].x;
temp[0].y = s1->head->apt[0].y - UNIT;
temp[1].x = s1->head->apt[1].x;
temp[1].y = s1->head->apt[1].y - UNIT;
temp[2] = s1->head->apt[1];
temp[3] = s1->head->apt[0];
if (isBorder(temp) || isSelf(s1, s2, temp))
{//判断是否为墙或者自身
game_over = true;
}
else if (isFood(food, temp))
{//如果是食物,则只添加头结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
eat1 = true;
s1->length++;
if (eat1)
creatFood(s1,s2,food);
eat1 = false;
}
else
{//为空。则添加头结点,删除尾结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
NODE* temp_tail;
temp_tail = s1->tail;
s1->tail = s1->tail->previous;
s1->tail->next = NULL;
free (temp_tail);
}
}
void drawDown (SNAKE* s1, SNAKE* s2, POINT food[4])
{
POINT temp[4];//蛇头下方的方格
temp[3].x = s1->head->apt[3].x;
temp[3].y = s1->head->apt[3].y + UNIT;
temp[2].x = s1->head->apt[2].x;
temp[2].y = s1->head->apt[2].y + UNIT;
temp[0] = s1->head->apt[3];
temp[1] = s1->head->apt[2];
if (isBorder(temp) || isSelf(s1,s2,temp))
{//判断是否为墙或者自身
game_over = true;
}
else if (isFood(food, temp))
{//如果是食物,则只添加头结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
eat1 = true;
s1->length++;
if (eat1)
creatFood(s1,s2,food);
eat1 = false;
}
else
{//为空。则添加头结点,删除尾结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
NODE* temp_tail;
temp_tail = s1->tail;
s1->tail = s1->tail->previous;
s1->tail->next = NULL;
free (temp_tail);
}
}
void drawRight (SNAKE* s1, SNAKE* s2, POINT food[4])
{
POINT temp[4];//蛇头右方的方格
temp[1].x = s1->head->apt[1].x + UNIT;
temp[1].y = s1->head->apt[1].y;
temp[2].x = s1->head->apt[2].x + UNIT;
temp[2].y = s1->head->apt[2].y;
temp[0] = s1->head->apt[1];
temp[3] = s1->head->apt[2];
if (isBorder(temp) || isSelf(s1, s2, temp))
{//判断是否为墙或者自身
game_over = true;
}
else if (isFood(food, temp))
{//如果是食物,则只添加头结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
eat1 = true;
s1->length++;
if (eat1)
creatFood(s1,s2,food);
eat1 = false;
}
else
{//为空。则添加头结点,删除尾结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
NODE* temp_tail;
temp_tail = s1->tail;
s1->tail = s1->tail->previous;
s1->tail->next = NULL;
free (temp_tail);
}
}
void drawLeft (SNAKE* s1, SNAKE* s2, POINT food[4])
{
POINT temp[4];//蛇头上方的方格
temp[0].x = s1->head->apt[0].x - UNIT;
temp[0].y = s1->head->apt[0].y;
temp[3].x = s1->head->apt[3].x - UNIT;
temp[3].y = s1->head->apt[3].y;
temp[2] = s1->head->apt[3];
temp[1] = s1->head->apt[0];
if (isBorder(temp) || isSelf(s1, s2, temp))
{//判断是否为墙或者自身
game_over = true;
}
else if (isFood(food, temp))
{//如果是食物,则只添加头结点
NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
eat1 = true;
s1->length++;
if (eat1)
creatFood(s1, s2, food);
eat1 = false;
}
else
{//为空。则添加头结点,删除尾结点
NODE *new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?
new_head->apt[0] = temp[0];
new_head->apt[1] = temp[1];
new_head->apt[2] = temp[2];
new_head->apt[3] = temp[3];
new_head->next = s1->head;
s1->head->previous = new_head;
s1->head = new_head;
NODE* temp_tail;
temp_tail = s1->tail;
s1->tail = s1->tail->previous;
s1->tail->next = NULL;
free (temp_tail);
}
}
void runDef (SNAKE* s1, SNAKE* s2, direction* d, POINT food[4])
{//默认移动方式,即按原方向移动
switch (*d)
{
case UP:
drawUp(s1,s2,food);break;
case DOWN:
drawDown(s1,s2,food);break;
case RIGHT:
drawRight(s1,s2,food);break;
case LEFT:
drawLeft(s1,s2,food);break;
default:
break;
}
}
void creatFood (SNAKE* snake1, SNAKE* snake2, POINT food[4])
{
do
{//防止食物出现在蛇身
srand((unsigned)time(NULL));//初始化时间种子
int seedx = rand()%20 + 1;//设置食物随即出现的x坐标
int seedy = rand()%10 + 1;//设置食物随即出现的y坐标
food[0].x = seedx*UNIT;
food[0].y = seedy*UNIT;
food[1].x = (seedx + 1)*UNIT;
food[1].y = seedy*UNIT;
food[2].x = (seedx + 1)*UNIT;
food[2].y = (seedy + 1)*UNIT;
food[3].x = seedx*UNIT;
food[3].y = (seedy + 1)*UNIT;
} while (isSelf(snake1,snake2,food));
}
void drawFood (HDC hdc,POINT food[4])
{
square(hdc,food);
}
void initializeSnake1(SNAKE* snake1)
{
NODE* one = (NODE*)malloc(sizeof(NODE));
NODE* two = (NODE*)malloc(sizeof(NODE));
NODE* three = (NODE*)malloc(sizeof(NODE));
//初始化蛇的三个节点链接
one->next = two;
two->next = three;
three->next = NULL;
three->previous = two;
two->previous = one;
one->previous = NULL;
//初始化蛇的三个节点坐标
one->apt[0].x = 6*UNIT;
one->apt[0].y = 3*UNIT;
one->apt[1].x = 7*UNIT;
one->apt[1].y = 3*UNIT;
one->apt[2].x = 7*UNIT;
one->apt[2].y = 4*UNIT;
one->apt[3].x = 6*UNIT;
one->apt[3].y = 4*UNIT;
two->apt[0].x = 5*UNIT;
two->apt[0].y = 3*UNIT;
two->apt[1].x = 6*UNIT;
two->apt[1].y = 3*UNIT;
two->apt[2].x = 6*UNIT;
two->apt[2].y = 4*UNIT;
two->apt[3].x = 5*UNIT;
two->apt[3].y = 4*UNIT;
three->apt[0].x = 4*UNIT;
three->apt[0].y = 3*UNIT;
three->apt[1].x = 5*UNIT;
three->apt[1].y = 3*UNIT;
three->apt[2].x = 5*UNIT;
three->apt[2].y = 4*UNIT;
three->apt[3].x = 4*UNIT;
three->apt[3].y = 4*UNIT;
//初始化蛇
snake1->length = 3;
snake1->head = one;
snake1->tail = three;
}
void initializeSnake2(SNAKE* snake2)
{
NODE* one = (NODE*)malloc(sizeof(NODE));
NODE* two = (NODE*)malloc(sizeof(NODE));
NODE* three = (NODE*)malloc(sizeof(NODE));
//初始化蛇的三个节点链接
one->next = two;
two->next = three;
three->next = NULL;
three->previous = two;
two->previous = one;
one->previous = NULL;
//初始化蛇的三个节点坐标
one->apt[0].x = 6*UNIT;
one->apt[0].y = 6*UNIT;
one->apt[1].x = 7*UNIT;
one->apt[1].y = 6*UNIT;
one->apt[2].x = 7*UNIT;
one->apt[2].y = 7*UNIT;
one->apt[3].x = 6*UNIT;
one->apt[3].y = 7*UNIT;
two->apt[0].x = 5*UNIT;
two->apt[0].y = 6*UNIT;
two->apt[1].x = 6*UNIT;
two->apt[1].y = 6*UNIT;
two->apt[2].x = 6*UNIT;
two->apt[2].y = 7*UNIT;
two->apt[3].x = 5*UNIT;
two->apt[3].y = 7*UNIT;
three->apt[0].x = 4*UNIT;
three->apt[0].y = 6*UNIT;
three->apt[1].x = 5*UNIT;
three->apt[1].y = 6*UNIT;
three->apt[2].x = 5*UNIT;
three->apt[2].y = 7*UNIT;
three->apt[3].x = 4*UNIT;
three->apt[3].y = 7*UNIT;
//初始化蛇
snake2->length = 3;
snake2->head = one;
snake2->tail = three;
}
void clearSnake(SNAKE* snake)
{//删除蛇所有结点
NODE* current = snake->head;
while (current)
{
NODE* temp = current;
current = current->next;
delete temp;
temp = NULL;
}
}
void initializeGame (SNAKE* snake1, SNAKE* snake2)
{//初始化游戏
clearSnake(snake1);//删除原来蛇1所有结点
clearSnake(snake2);//删除原来蛇2所有结点
initializeSnake1(snake1);//初始化蛇1
initializeSnake2(snake2);//初始化蛇2
game_over = false;//恢复游戏
dire1 = RIGHT;//初始化方向
dire2 = RIGHT;//初始化方向
}