江南才子 发表于 2021-6-27 12:43:10

MFC实现贪吃蛇

贪吃蛇游戏的实现
一、前期准备
类的定义
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();//初始化位置
friendSnake;
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像素
};
  开发工具 VS2019
二、实现思路
1、建立一个单文档文件


2、完成对类的声明和实现
  点类的实现
Point::Point(int x, int y)
{
this->x &#61; x;
this->y &#61; y;
}
int Point::getPointx() {
returnx;
}
int Point::getPointy() {
return y;
}
bool Point::changex(int a)
{
x &#61; a;
return true;
}
bool Point::changey(int b)
{
y &#61; b;
return true;
}
bool Point::cmp(Point& a) {
if (a.x &#61;&#61; x && a.y &#61;&#61; y)
return true;
return false;
}
  食物类的实现
Food::Food()
{
srand(time(NULL));
int a &#61; rand() % 320 &#43; 100;
a -&#61; a % 10;
int b &#61; rand() % 320 &#43; 100;
b -&#61; 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() &#43; 10, x.getPointy() &#43; 10), &brush);
brush.DeleteObject();
}
Point Food::init()
{
srand(time(NULL));//设置种子
//生成40-420之间的随机数
int a &#61; rand() % 380 &#43; 40;
a -&#61; a % 10;
int b &#61; rand() % 380 &#43; 40;
b -&#61; 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()&#43;10, head.getPointy()&#43;10), &brush);
brush.DeleteObject();
brush.CreateSolidBrush(RGB(255, 0, 0));
for (int i &#61; length - 1; i >&#61; 0; i--) {
dc->FillRect(CRect(body.getPointx(), body.getPointy(), body.getPointx() &#43; 10, body.getPointy() &#43; 10), &brush);
}
brush.DeleteObject();
}
bool Snake::isHit() {
if (head.getPointx() <&#61; 30 || head.getPointx() >&#61; 420)
return true;
if (head.getPointy() <&#61; 30 || head.getPointy() >&#61; 420)
return true;
return false;
}
bool Snake::move(Food &food)
{
int i &#61; length;
if (isEat())
{
return false;
}
if (isHit())
{
return false;
}
if (eatFood(food.x.getPointx(), food.x.getPointy())) {
Point n &#61; food.init();
if (n.cmp(head))
n &#61; food.init();
while (1) {
i &#61; length;
for (i--; i >&#61; 0; i--) {
if (body.cmp((n))) {
n &#61; food.init();
break;
}
}
if (i < 0)
break;
}
Point t(body.getPointx(), body.getPointy());
body.push_back(t);
length&#43;&#43;;
return true;
}
i &#61; length;
switch (direct)
{
case 1: {
for (i--; i >&#61; 1; i--)
{
body.changex(body.getPointx());
body.changey(body.getPointy());
}
body.changex(head.getPointx());
body.changey(head.getPointy());
head.changey(head.getPointy() - 10);
break;
}
case 2: {
for (i--; i >&#61; 1; i--)
{
body.changex(body.getPointx());
body.changey(body.getPointy());
}
body.changex(head.getPointx());
body.changey(head.getPointy());
head.changex(head.getPointx() &#43; 10);
break;
}
case 3: {
for (i--; i >&#61; 1; i--)
{
body.changex(body.getPointx());
body.changey(body.getPointy());
}
body.changex(head.getPointx());
body.changey(head.getPointy());
head.changey(head.getPointy() &#43; 10);
break;
}
case 4: {
for (i--; i >&#61; 1; i--)
{
body.changex(body.getPointx());
body.changey(body.getPointy());
}
body.changex(head.getPointx());
body.changey(head.getPointy());
head.changex(head.getPointx() - 10);
break;
}
}
return true;
}
bool Snake::isEat()
{
int x &#61; head.getPointx();
int y &#61; head.getPointy();
int i &#61; length;
if (i > 3) {
for (i-- ; i >&#61; 0; i--)
{
if (head.getPointx() &#61;&#61; body.getPointx() && head.getPointy() &#61;&#61; body.getPointy())
return true;
}
}

return false;
}
bool Snake::eatFood(int x, int y)
{
if (head.getPointx() &#61;&#61; x && head.getPointy() &#61;&#61; y)
return true;
return false;
}
void Snake::changeD(int a)
{
direct &#61; a;
}
3、对贪吃蛇、食物、界面的绘制
  建立类向导

对ondraw()虚函数进行编写


  在绘制过程中还需要使用双缓存技术&#xff0c;可以自行了解一下。
4、初始化游戏
  我对初始化游戏有两种方法
方法一&#xff1a; 在OnInitialUpdate()函数内用SetTimer(1, 1000, NULL);

方法二 &#xff1a;在菜单内加入开始游戏

实现&#xff1a;
在资源管理器内双击TCsnake.rc


对菜单进行编辑

可以写入自己想要的&#xff0c;然后添加事件处理程序

类列表选择CTCSnakeView&#xff0c;消息类型COMMAND&#xff0c;函数名自定义

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

5、实现蛇的移动效果
  通过OnTimer()、SetTimer()、Invalidate()和KillTimer()的配合实现
6、通过按键改变蛇的移动方向
  首先添加一个OnKeyDown()函数

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







以上就是我实现贪吃蛇的基础步骤&#xff0c;初学MFC&#xff0c;很多地方没有考虑周全。内容很多只是粗略介绍实现过程&#xff0c;具体的实现过程还需要查看源码&#xff0c;用到的一些虚函数和消息的详解大家应该可以自行查到。作品仅作记录
  下面附上源码
源码地址&#xff1a; https://gitee.com/gg_8_0/the-greedy-snake-of-mfc.git
                                                            
页: [1]
查看完整版本: MFC实现贪吃蛇