|
|
#include<iostream>
|
|
|
using namespace std;
|
|
|
#include<easyx.h> //包含图形库头文件
|
|
|
#include<stdlib.h>
|
|
|
#include<time.h>
|
|
|
|
|
|
#define WIDTH 1040 //定义场景大小
|
|
|
#define HEIGHT 640
|
|
|
#define SIZE 20 //定义食物以及蛇的大小 一个格子的大小
|
|
|
#define UP 1 //定义蛇的朝向
|
|
|
#define DOWN -1
|
|
|
#define LEFT 2
|
|
|
#define RIGHT -2
|
|
|
#define MAX 2000 //蛇的最大长度
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
{
|
|
|
int x;
|
|
|
int y;
|
|
|
}SnakeNode;
|
|
|
|
|
|
SnakeNode temp[MAX]; //用另外一个数组来存储蛇原来的位置
|
|
|
int speed = 150; //蛇的速度
|
|
|
|
|
|
//创建蛇的类
|
|
|
class Snake
|
|
|
{
|
|
|
friend class Food;
|
|
|
public:
|
|
|
Snake(); //初始化
|
|
|
void Move(); //移动
|
|
|
void Draw(); //绘制蛇
|
|
|
bool Eat(Food food); //吃食物
|
|
|
bool Defeat(); //失败判定
|
|
|
private:
|
|
|
int dirt; //朝向
|
|
|
int length; //长度
|
|
|
SnakeNode node[MAX]; //蛇的坐标
|
|
|
};
|
|
|
|
|
|
//创建食物的类
|
|
|
class Food
|
|
|
{
|
|
|
friend class Snake;
|
|
|
public:
|
|
|
Food(Snake snake); //食物初始化
|
|
|
void Draw(); //绘制食物
|
|
|
private:
|
|
|
int x, y; //坐标
|
|
|
};
|
|
|
|
|
|
//蛇的初始化
|
|
|
Snake::Snake()
|
|
|
{
|
|
|
dirt = RIGHT;
|
|
|
length = 3;
|
|
|
//下标是0的位置为蛇的头部
|
|
|
for (int i = 0; i < length; i++)
|
|
|
{
|
|
|
node[i].x = 60 - ((i + 1) * SIZE);//坐标带上20
|
|
|
node[i].y = 0;
|
|
|
} //固定刚开始蛇的位置
|
|
|
//蛇一开始从屏幕的左上角出现
|
|
|
}
|
|
|
|
|
|
//移动
|
|
|
void Snake::Move()
|
|
|
{
|
|
|
for (int i = 0; i < length; i++) //将原来的蛇结点拷贝一份
|
|
|
{
|
|
|
temp[i].x = node[i].x;
|
|
|
temp[i].y = node[i].y;
|
|
|
}
|
|
|
int status = 0; //用来判断是否点击了转向按键
|
|
|
if (dirt == RIGHT) //四个方向,讨论现在的方向,分别判断是否转向,不能反向。
|
|
|
{
|
|
|
//判断是否转向
|
|
|
if (GetAsyncKeyState('W') && status == 0) //捕捉键盘输入为w,easyx 判断转向
|
|
|
{
|
|
|
dirt = UP; //去了if(dirt==up)的else
|
|
|
status = 1;
|
|
|
}
|
|
|
else if (GetAsyncKeyState('S') && status == 0)
|
|
|
{
|
|
|
dirt = DOWN;
|
|
|
status = 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
node[0].x = node[0].x + SIZE;
|
|
|
}
|
|
|
}
|
|
|
if (dirt == DOWN)
|
|
|
{
|
|
|
//判断是否转向
|
|
|
if (GetAsyncKeyState('A') && status == 0)
|
|
|
{
|
|
|
dirt = LEFT;
|
|
|
status = 1;
|
|
|
}
|
|
|
else if (GetAsyncKeyState('D') && status == 0)
|
|
|
{
|
|
|
node[0].x = node[0].x + SIZE;
|
|
|
dirt = RIGHT;
|
|
|
status = 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
node[0].y = node[0].y + SIZE;
|
|
|
}
|
|
|
}
|
|
|
if (dirt == LEFT)
|
|
|
{
|
|
|
//判断是否转向
|
|
|
if (GetAsyncKeyState('W') && status == 0)
|
|
|
{
|
|
|
dirt = UP;
|
|
|
status = 1;
|
|
|
}
|
|
|
else if (GetAsyncKeyState('S') && status == 0)
|
|
|
{
|
|
|
node[0].y = node[0].y + SIZE;
|
|
|
dirt = DOWN;
|
|
|
status = 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
node[0].x -= SIZE;
|
|
|
}
|
|
|
}
|
|
|
if (dirt == UP)
|
|
|
{
|
|
|
//判断是否转向
|
|
|
if (GetAsyncKeyState('A') && status == 0)
|
|
|
{
|
|
|
node[0].x = node[0].x - SIZE;
|
|
|
dirt = LEFT;
|
|
|
status = 1;
|
|
|
}
|
|
|
else if (GetAsyncKeyState('D') && status == 0)
|
|
|
{
|
|
|
node[0].x = node[0].x + SIZE;
|
|
|
dirt = RIGHT;
|
|
|
status = 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
node[0].y = node[0].y - SIZE;
|
|
|
//改变坐标
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//移动
|
|
|
for (int i = 1; i < length; i++)
|
|
|
{
|
|
|
node[i].x = temp[i - 1].x;
|
|
|
node[i].y = temp[i - 1].y;
|
|
|
}
|
|
|
Sleep(speed); //休眠这么长时间,停顿一下
|
|
|
}
|
|
|
|
|
|
//绘制蛇
|
|
|
void Snake::Draw()
|
|
|
{
|
|
|
cleardevice(); //清空原先的绘图
|
|
|
srand((unsigned)time(NULL)); //设置颜色随机数(setfillcolor)时用
|
|
|
for (int i = 0; i < length; i++)
|
|
|
{
|
|
|
setfillcolor(RGB(rand() % 256, rand() % 256, rand() % 256)); //五颜六色的蛇
|
|
|
fillrectangle(node[i].x, node[i].y, node[i].x + SIZE, node[i].y + SIZE);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//吃食物
|
|
|
bool Snake::Eat(Food food)
|
|
|
{
|
|
|
if (food.x == node[0].x && food.y == node[0].y) //头有没有碰到食物
|
|
|
{
|
|
|
if (node[length - 1].x - node[length - 2].x == 0 && node[length - 1].y - node[length - 2].y == -20)
|
|
|
{
|
|
|
//判断蛇尾巴的方向(数组最后两个点的位置关系),新点加在尾巴后面
|
|
|
length++;
|
|
|
node[length - 1].x = node[length - 2].x;
|
|
|
node[length - 1].y = node[length - 2].y - SIZE;
|
|
|
}
|
|
|
else if (node[length - 1].x - node[length - 2].x == 0 && node[length - 1].y - node[length - 2].y == 20)
|
|
|
{
|
|
|
length++;
|
|
|
node[length - 1].x = node[length - 2].x;
|
|
|
node[length - 1].y = node[length - 2].y + SIZE;
|
|
|
}
|
|
|
else if (node[length - 1].x - node[length - 2].x == 20 && node[length - 1].y - node[length - 2].y == 0)
|
|
|
{
|
|
|
length++;
|
|
|
node[length - 1].x = node[length - 2].x + SIZE;
|
|
|
node[length - 1].y = node[length - 2].y;
|
|
|
}
|
|
|
else if (node[length - 1].x - node[length - 2].x == -20 && node[length - 1].y - node[length - 2].y == 0)
|
|
|
{
|
|
|
length++;
|
|
|
node[length - 1].x = node[length - 2].x - SIZE;
|
|
|
node[length - 1].y = node[length - 2].y;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
//失败判定
|
|
|
bool Snake::Defeat()
|
|
|
{
|
|
|
//碰到边界
|
|
|
if (node[0].x < 0 || node[0].x >= WIDTH || node[0].y < 0 || node[0].y >= HEIGHT)
|
|
|
return true;
|
|
|
|
|
|
//碰到自己的身体
|
|
|
for (int i = 1; i < length; i++)
|
|
|
{
|
|
|
if (node[0].x == node[i].x && node[0].y == node[i].y)
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
//食物的初始化
|
|
|
Food::Food(Snake snake)
|
|
|
{
|
|
|
table:
|
|
|
srand((unsigned)time(NULL)); //设计随机种子,产生随机数
|
|
|
x = (rand() % (WIDTH / SIZE)) * SIZE;
|
|
|
y = (rand() % (HEIGHT / SIZE)) * SIZE;
|
|
|
|
|
|
for (int i = 0; i < snake.length; i++)
|
|
|
{
|
|
|
if (snake.node[i].x == x && snake.node[i].y == y)
|
|
|
goto table; //如果食物在蛇身上,则重新初始化
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//绘制食物
|
|
|
void Food::Draw()
|
|
|
{
|
|
|
setfillcolor(GREEN); //食物是绿色
|
|
|
fillrectangle(x, y, x + SIZE, y + SIZE); //绘制食物为矩形,四个顶点坐标。
|
|
|
}
|
|
|
|
|
|
int main()
|
|
|
{
|
|
|
initgraph(WIDTH, HEIGHT);
|
|
|
Snake snake;
|
|
|
|
|
|
table:
|
|
|
Food food(snake);
|
|
|
while (1)
|
|
|
{
|
|
|
BeginBatchDraw();
|
|
|
FlushBatchDraw(); //双缓冲,防止屏幕一闪一闪的
|
|
|
snake.Draw();
|
|
|
food.Draw();
|
|
|
FlushBatchDraw(); //双缓冲,防止屏幕一闪一闪的
|
|
|
EndBatchDraw();
|
|
|
/*双缓冲,防止屏幕一闪一闪的*/
|
|
|
if (snake.Eat(food))
|
|
|
{
|
|
|
goto table; //如果吃到食物,就再设置一个食物
|
|
|
}
|
|
|
if (snake.Defeat())
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
snake.Move();
|
|
|
}
|
|
|
|
|
|
HWND window = GetHWnd(); //弹窗,提示游戏失败
|
|
|
SetWindowText(window, L"提示"); //修改窗口标题,设置成提示
|
|
|
MessageBox(window, L"游戏失败", L"提示", MB_OKCANCEL);
|
|
|
//提示失败信息 MB_OKCANCEL:下面有两个按键,确定或取消
|
|
|
|
|
|
return 0;
|
|
|
} |