贪吃蛇游戏的实现 一、前期准备

类的定义

1、位置(点)类的定义

class Point
{
public:
	Point(int x = 0, int y = 0);
	int getPointx();  //获得X轴位置
	int getPointy();  //获得Y轴位置
	bool changex(int a);  //改变X轴位置
	bool changey(int b);  //改变Y轴位置
	bool cmp(Point &a);  //比较
private:
	int x, y;  //X、Y轴
};

2、食物类的定义

class Food
{
public:
	Food();
	void draw(CDC* dc);   //画食物
	Point init();	//初始化位置
	friend  Snake;  
private:
	Point x;
};

3、蛇类的定义

class Snake
{
public:
	friend class CTCSnakeView;
	Snake(Point head, int d = 2, int len = 1);
	~Snake() {

	}
	void drawSnake(CDC *dc);  //画蛇
	bool eatFood(int x, int y); //吃食物
	bool move(Food &food); //游走
	void changeD(int);  //改变方向
	bool isHit();
	int getD() {
		return direct;
	}        // 获取方向
	Point getH() {
		return head;
	}        //获取头位置
private:
	Point head;  //蛇头位置
	int direct;  //前进方向
	vector<Point> body; // 蛇身位置
	int length; //蛇长
	bool isEat();  //判断是否吃到自己
	//蛇身宽度为10像素
};
二、实现思路

1、建立一个单文档文件

MFC实现贪吃蛇_mfc

MFC实现贪吃蛇_mfc_02

2、完成对类的声明和实现

点类的实现

Point::Point(int x, int y)
{
	this->x = x;
	this->y = y;
}
int Point::getPointx() {
	return  x;
}
int Point::getPointy() {
	return y;
}
bool Point::changex(int a)
{
	x = a;
	return true;
}
bool Point::changey(int b)
{
	y = b;
	return true;
}
bool Point::cmp(Point& a) {
	if (a.x == x && a.y == y)
		return true;
	return false;
}

食物类的实现

Food::Food()
{
	srand(time(NULL));
	int a = rand() % 320 + 100;
	a -= a % 10;
	int b = rand() % 320 + 100;
	b -= b % 10;
	x.changex(a);
	x.changey(b);
}
void Food::draw(CDC* dc)
{
	CBrush brush;
	brush.CreateSolidBrush(RGB(0, 0, 255));
	dc->FillRect(CRect(x.getPointx(), x.getPointy(), x.getPointx() + 10, x.getPointy() + 10), &brush);
	brush.DeleteObject();
}
Point Food::init()
{
	srand(time(NULL));  //设置种子
	//生成40-420之间的随机数
	int a = rand() % 380 + 40;
	a -= a % 10;
	int b = rand() % 380 + 40;
	b -= b % 10;
	x.changex(a);
	x.changey(b);
	return x;
}

贪吃蛇类的定义

Snake::Snake(Point head, int d, int len):head(60, 60), direct(d), length(len)
{
	body.push_back(Point(50, 60));
}
void Snake::drawSnake(CDC * dc)
{
	CBrush brush;
	brush.CreateSolidBrush(RGB(0, 255, 0));
	dc->FillRect(CRect(head.getPointx(), head.getPointy(), head.getPointx()+10, head.getPointy()+10), &brush);
	brush.DeleteObject();
	brush.CreateSolidBrush(RGB(255, 0, 0));
	for (int i = length - 1; i >= 0; i--) {
		dc->FillRect(CRect(body[i].getPointx(), body[i].getPointy(), body[i].getPointx() + 10, body[i].getPointy() + 10), &brush);
	}
	brush.DeleteObject();
}
bool Snake::isHit() {
	if (head.getPointx() <= 30 || head.getPointx() >= 420)
		return true;
	if (head.getPointy() <= 30 || head.getPointy() >= 420)
		return true;
	return false;
}
bool Snake::move(Food &food)
{
	int i = length;
	if (isEat())
	{
		return false;
	}
	if (isHit())
	{
		return false;
	}
	if (eatFood(food.x.getPointx(), food.x.getPointy())) {
		Point n = food.init();
		if (n.cmp(head)) 
			n = food.init();
		while (1) {
			i = length;
			for (i--; i >= 0; i--) {
				if (body[i].cmp((n))) {
					n = food.init();
					break;
				}
			}	
			if (i < 0)
				break;
		}
		Point t(body[length - 1].getPointx(), body[length - 1].getPointy());
		body.push_back(t);
		length++;
		return true;
	}
	i = length;
	switch (direct)
	{
		case 1: {
			for (i--; i >= 1; i--)
			{
				body[i].changex(body[i - 1].getPointx());
				body[i].changey(body[i - 1].getPointy());
			}
			body[0].changex(head.getPointx());
			body[0].changey(head.getPointy());
			head.changey(head.getPointy() - 10);
			break;
		}
		case 2: {
			for (i--; i >= 1; i--)
			{
					body[i].changex(body[i - 1].getPointx());
					body[i].changey(body[i - 1].getPointy());			
			}
			body[0].changex(head.getPointx());
			body[0].changey(head.getPointy());
			head.changex(head.getPointx() + 10);
			break;
		}
		case 3: {
			for (i--; i >= 1; i--)
			{
					body[i].changex(body[i - 1].getPointx());
					body[i].changey(body[i - 1].getPointy());
			}
			body[0].changex(head.getPointx());
			body[0].changey(head.getPointy());
			head.changey(head.getPointy() + 10);
			break;
		}
		case 4: {
			for (i--; i >= 1; i--)
			{
				body[i].changex(body[i - 1].getPointx());
				body[i].changey(body[i - 1].getPointy());
			}
			body[0].changex(head.getPointx());
			body[0].changey(head.getPointy());
			head.changex(head.getPointx() - 10);
			break;
		}
	}
	return true;
}
bool Snake::isEat()
{
	int x = head.getPointx();
	int y = head.getPointy();
	int i = length;
	if (i > 3) {
	for (i-- ; i >= 0; i--)
		{
			if (head.getPointx() == body[i].getPointx() && head.getPointy() == body[i].getPointy())
				return true;
		}
	}
	
	return false;
}
bool Snake::eatFood(int x, int y)
{
	if (head.getPointx() == x && head.getPointy() == y)
		return true;
	return false;
}
void Snake::changeD(int a)
{
	direct = a;
}

3、对贪吃蛇、食物、界面的绘制

建立类向导

MFC实现贪吃蛇_mfc_03

对ondraw()虚函数进行编写

MFC实现贪吃蛇_mfc_04

MFC实现贪吃蛇_mfc_05

在绘制过程中还需要使用双缓存技术,可以自行了解一下。

4、初始化游戏

我对初始化游戏有两种方法
方法一: 在OnInitialUpdate()函数内用SetTimer(1, 1000, NULL);

MFC实现贪吃蛇_mfc_06

方法二 :在菜单内加入开始游戏

MFC实现贪吃蛇_mfc_07

实现:
在资源管理器内双击TCsnake.rc

MFC实现贪吃蛇_mfc_08

MFC实现贪吃蛇_mfc_09

对菜单进行编辑

MFC实现贪吃蛇_mfc_10

可以写入自己想要的,然后添加事件处理程序

MFC实现贪吃蛇_mfc_11

类列表选择CTCSnakeView,消息类型COMMAND,函数名自定义

MFC实现贪吃蛇_mfc_12

在生成的函数内用settimer()达到开始游戏的效果

MFC实现贪吃蛇_mfc_13

5、实现蛇的移动效果

通过OnTimer()、SetTimer()、Invalidate()和KillTimer()的配合实现

6、通过按键改变蛇的移动方向

首先添加一个OnKeyDown()函数

MFC实现贪吃蛇_mfc_14

再在函数内判断按下的键所对应的方向,最后进行一个改变方向的操作。