• C++基于EasyX制作贪吃蛇游戏(二)第一版代码与程序


    本文首发于我的个人博客www.colourso.top,欢迎来访。

    原文链接:http://www.colourso.top/c-snake-pro1/

    原文写于2019-06-21,本次重新整理。

    上一篇博客写了贪吃蛇第一版的文档,这一篇博客就把第一版本的贪吃蛇代码展示一下,附带源码与可执行文件的下载。

    开发环境

    原博客环境:

    工具: VS2013

    依赖: EasyX Library for C++ (Ver:20180727(beta)

    整理时环境:

    工具:VS2017

    依赖:EasyX Library for C++ (Ver:20200520(beta))

    VS2017属性页设置

    注意字符集为Unicode字符集

    新版源代码

    #include <graphics.h>
    #include <conio.h>
    #include <stdlib.h>
    #include <time.h>
    
    //蛇头方向预定义
    #define UP 1	//↑
    #define RIGHT 2 //→
    #define DOWN 3  //↓
    #define LEFT 4  //←
    
    /*-------------结构体定义---------------*/
    
    typedef struct Node //蛇的节点
    {
    	int x;			   //横左边
    	int y;			   //纵坐标
    	struct Node *next; //指向下一个节点的指针
    	struct Node *pre;  //指向前一个节点的指针
    } *LinkNode;
    
    struct Snake //蛇的结构体
    {
    	LinkNode head; //指向头节点的指针
    	LinkNode tail; //指向尾节点的指针
    	int direction; //蛇头方向
    	int num;	   //节点数目
    };
    
    struct Food //食物结构体
    {
    	int x;		//横坐标
    	int y;		//纵坐标
    	bool exist; //是否存在,1表示存在
    };
    
    /*-------------全局变量---------------*/
    
    int g_score = 0; //获得分数
    Snake snake;	 //游戏中的蛇本体
    Food food;		 //食物
    
    /*-------------函数声明---------------*/
    
    void init();	 //初始化
    void drawgame(); //绘制界面
    void gameplay(); //开始游戏
    void close();	//释放资源
    
    void drawfood(Food food);		  //绘制食物
    void drawsnake(Snake snake);	  //绘制蛇
    void drawsnakenode(Node node);	//绘制蛇的结点
    void clearsnakenode(Node node);   //清除蛇的结点
    void snakebodymove(Snake &snake); //蛇身体结点向前复制
    bool collidesnake(Snake snake);   //碰撞自身检测
    void drawscore();				  //绘制分数
    void clearscore();				  //清除分数
    
    /*-------------程序入口---------------*/
    
    int main()
    {
    	init();
    	drawgame();
    	gameplay();
    	close();
    	return 0;
    }
    
    /*-------------函数实现---------------*/
    
    //初始化
    void init()
    {
    	initgraph(640, 480);   //初始化窗口
    	//setorigin(0, 480);	 //设置坐标原点
    	//setaspectratio(1, -1); //使y轴向上为正
    
    	//蛇与食物初始化
    	//食物初始坐标为(310,230)
    	food.x = 310;
    	food.y = 230;
    	food.exist = true;
    
    	//蛇初始长度为3,蛇头坐标为(210,230)
    
    	//在堆上开辟空间,防止此函数的生命周期结束后结点全部被释放掉
    	LinkNode nodes2 = (LinkNode)malloc(sizeof(Node));
    	nodes2->x = 170;
    	nodes2->y = 230;
    	nodes2->next = nullptr;
    	LinkNode nodes1 = (LinkNode)malloc(sizeof(Node));
    	nodes1->x = 190;
    	nodes1->y = 230;
    	nodes1->next = nodes2;
    	LinkNode nodes0 = (LinkNode)malloc(sizeof(Node));
    	nodes0->x = 210;
    	nodes0->y = 230;
    	nodes0->next = nodes1;
    	nodes2->pre = nodes1;
    	nodes1->pre = nodes0;
    	nodes0->pre = nullptr;
    	snake.head = nodes0;
    	snake.tail = nodes2;
    	snake.direction = RIGHT;
    	snake.num = 3;
    
    	//初始分数
    	g_score = (snake.num - 3) * 10;
    }
    
    //绘制界面
    void drawgame()
    {
    	//画宽度为2的棕色实线,分割区域
    	setlinecolor(BROWN);
    	setlinestyle(PS_SOLID, 2);
    	line(482, 0, 482, 480);
    
    	//绘制食物
    	drawfood(food);
    
    	//绘制蛇
    	drawsnake(snake);
    
    	//绘制分数
    	drawscore();
    }
    
    //开始游戏
    void gameplay()
    {
    	Node ends; //末尾结点
    	while (1)
    	{
    		ends.x = snake.tail->x;
    		ends.y = snake.tail->y;
    
    		if (!food.exist)
    		{
    			int x;
    			int y;
    			while (1)
    			{
    				srand(time(0));
    				x = (rand() % 24) * 20 + 10;
    				y = (rand() % 24) * 20 + 10;
    
    				//食物位置检测算法
    				LinkNode linknode = snake.head;
    				bool cont = true;
    				while (linknode != snake.tail->next)
    				{
    					if (linknode->x == x && linknode->y == y)
    					{
    						cont = false;
    						break;
    					}
    					linknode = linknode->next;
    				}
    				if (cont)
    				{
    					break;
    				}
    			}
    
    			food.x = x;
    			food.y = y;
    			food.exist = true;
    			drawfood(food);
    		}
    
    		//按键
    		if (_kbhit())
    		{
    			char key = _getch();
    			switch (key)
    			{
    			case 72: //↑
    				if (snake.direction != UP && snake.direction != DOWN)
    					snake.direction = UP;
    				break;
    			case 80: //↓
    				if (snake.direction != UP && snake.direction != DOWN)
    					snake.direction = DOWN;
    				break;
    			case 75: //←
    				if (snake.direction != LEFT && snake.direction != RIGHT)
    					snake.direction = LEFT;
    				break;
    			case 77: //→
    				if (snake.direction != LEFT && snake.direction != RIGHT)
    					snake.direction = RIGHT;
    				break;
    			}
    		}
            
            //消除走过的尾部结点
    		clearsnakenode(ends);
            
    		//前进
    		switch (snake.direction)
    		{
    		case UP:
    		{
    			//头部y-20,x不变
    			snakebodymove(snake);
    			snake.head->y -= 20;
    			drawsnakenode(*(snake.head));
    			break;
    		}
    		case RIGHT:
    		{
    			//头部x+20,y不变
    			snakebodymove(snake);
    			snake.head->x += 20;
    			drawsnakenode(*(snake.head));
    			break;
    		}
    		case DOWN:
    		{
    			//头部y+20,x不变
    			snakebodymove(snake);
    			snake.head->y += 20;
    			drawsnakenode(*(snake.head));
    			break;
    		}
    		case LEFT:
    		{
    			//头部x-20,y不变
    			snakebodymove(snake);
    			snake.head->x -= 20;
    			drawsnakenode(*(snake.head));
    			break;
    		}
    		}
    
    		//蛇吃食物
    		if (snake.head->x == food.x && snake.head->y == food.y && food.exist)
    		{
    			food.exist = false;
    			//isClear = false;
    
    			//分数变化
    			g_score += 10;
    
    			//在末尾增加新的结点,维护双向链表的关系
    			LinkNode nodes = (LinkNode)malloc(sizeof(Node));
    			nodes->x = ends.x;
    			nodes->y = ends.y;
    			nodes->next = snake.tail->next;
    			nodes->pre = snake.tail;
    			snake.tail->next = nodes;
    			snake.tail = nodes;
    			++snake.num;
    
    			drawsnakenode(ends);
    
    			clearscore();
    			drawscore();
    		}
    
    		//碰撞判断
    		bool collidewall = snake.head->x < 10 || snake.head->x > 470 || snake.head->y < 10 || snake.head->y > 470;
    		if (collidewall || collidesnake(snake))
    		{
    			cleardevice();
    			TCHAR s[] = _T("game over");
    			settextstyle(48, 0, _T("黑体"));
    			outtextxy(230, 280, s);
    			break;
    		}
    		Sleep(150);
    	}
    }
    
    //释放资源
    void close()
    {
    	_getch();
    	closegraph();
    }
    
    //绘制食物
    void drawfood(Food food)
    {
    	//红色,全填充,无边框的圆
    	setfillcolor(RED);
    	setfillstyle(BS_SOLID);
    	solidcircle(food.x, food.y, 8);
    }
    
    //绘制蛇的结点
    void drawsnakenode(Node node)
    {
    	//绿色,全填充,无边框的正方形
    	setfillcolor(GREEN);
    	setfillstyle(BS_SOLID);
    	solidrectangle(node.x - 9, node.y + 9, node.x + 9, node.y - 9);
    }
    
    //清除蛇的结点
    void clearsnakenode(Node node)
    {
    	//黑色,全填充,无边框的正方形
    	setfillcolor(BLACK);
    	setfillstyle(BS_SOLID);
    	solidrectangle(node.x - 9, node.y + 9, node.x + 9, node.y - 9);
    }
    
    //绘制蛇
    void drawsnake(Snake snake)
    {
    	LinkNode linknode = snake.head;
    	while (linknode != snake.tail->next)
    	{
    		drawsnakenode(*linknode);
    		linknode = linknode->next;
    	}
    }
    
    //蛇身体结点向前复制
    void snakebodymove(Snake &snake)
    {
    	LinkNode linknode = snake.tail;
    	while (linknode != snake.head)
    	{
    		linknode->x = linknode->pre->x;
    		linknode->y = linknode->pre->y;
    
    		linknode = linknode->pre;
    	}
    }
    
    //碰撞自身检测
    bool collidesnake(Snake snake)
    {
    	if (snake.num <= 3)
    		return false;
    	LinkNode node = snake.head->next;
    	while (node != snake.tail->next)
    	{
    		if (node->x == snake.head->x && node->y == snake.head->y)
    			return true;
    		node = node->next;
    	}
    	return false;
    }
    
    //绘制分数
    void drawscore()
    {
    	TCHAR s[] = _T("获得分数:");
    	settextstyle(16, 0, _T("黑体"));
    	outtextxy(485, 300, s);
    
    	TCHAR t[5];
    	_stprintf_s(t, _T("%d"), g_score); // 高版本 VC 推荐使用 _stprintf_s 函数
    	outtextxy(560, 300, t);
    }
    
    //清除分数
    void clearscore()
    {
    	//黑色,全填充,无边框的正方形
    	setfillcolor(BLACK);
    	setfillstyle(BS_SOLID);
    	solidrectangle(485, 480, 640, 300);
    }
    

    程序展示

    以下是B站视频

    上面视频不能播放请移步:https://www.bilibili.com/video/BV1bA411Y7L9/

    程序下载

    原先:百度网盘链接:https://pan.baidu.com/s/1O3EqtcAeciukwt2uixC7RQ
    提取码:tm95

    新第一版:链接:https://pan.baidu.com/s/1hNfVsYZp-I6dH2875FR7iw
    提取码:a4b2

    Github地址:https://github.com/Colourso/Simple-CPP-project-by-Colourso/

    其他

    关于上述程序之中的一些问题,比如使用vs生成的文件结构、字符集设置的问题,还有_T()是什么意思?
    请查看这篇博客:VS开发C++的一些问题——VS项目工程文件、Debug与Relase模式、字符集问题以及_T()宏

  • 相关阅读:
    zz java java.nio.ByteBuffer flip
    看到的应用mina做的一个实例
    命令行工具SVN
    ByteBuffer 理解
    Linux命令行下常用svn命令
    三元操作符对null 的处理
    获取最后一个字符串
    C#分割字符串
    学习Silverlight 书籍
    oralce 进行多表同步
  • 原文地址:https://www.cnblogs.com/colourso/p/12984011.html
Copyright © 2020-2023  润新知