贪吃蛇c++实现 实训认识小游戏

大一假期几天的实训认识课,用 C++ 做了两个小游戏,一个是推箱子,一个是贪吃蛇,让我对编程实现二维游戏有了点基础认识,下面是贪吃蛇游戏的一点简要认识。
运行环境:vs2012
用到结构体,枚举enum, if条件语句等
首先,我们要用到地图Map当然指的是游戏地图,我们使用0,1来构造,1为墙(障碍物),0为可通过空间,大小随心,如图:
蛇地图

当然,0,1也用于后面的墙的图案定义以及蛇的撞墙判定,这里方块墙(也可以其它图案)我们使用搜狗输入法里的符号大全:
在这里插入图片描述
enum用来定义几个选项,如游戏菜单界面,游戏控制区,游戏输赢判定,enum枚举c++学习过程中大家都学过,例如:
enum enumType {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
枚举量Monday、Tuesday等的值默认分别为0-6,我们可以显式的设置枚举量的值:
enum enumType {Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6, Sunday=7};但指定的值必须是整数。
还有结构体struct:结构体可以将原本意义属于一个整体的数据组合在一起。

唯一有一个新知识:按键控制
在这里插入图片描述
函数GetAsyncKeyState确定在调用它时某个按键处于弹起还是按下的,以及此按键是否在上一次调用GetAsyncKeyState之后(“又”)按下过(重复也算按下)。
这句话的完整意思是:预定义了一个KEYDOWN参数为vk_code 他的定义的含义是判断一个键是否被按下(GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0如果按下了就是1,没有按下就是0
然后其它地方用的时候直接用KEYDOWN(vk_code)判断这个键是否按下,相反弹起来是1按下是0。

清屏函数:system(“cls”);执行c++的一些比较大的程序时,可能会需要执行很多功能,但一次一次功能执行过后,会留下以前的字符占据着屏幕,看起来特别乱,也影响接下来的功能调用,这个函数可以在每执行完一次功能,选择回到一开始的初始界面。
作用是清除程序先前显示的内容,但不会清除先前调用程序功能而实现的对内存的改变.而由于是清除先前显示的内容,所以对此函数的写入位置要考虑一下,避免连初始界面也给清空了。
若想调用此函数,在程序代码的头文件上,要加上#include <stdlib.h> 才可以使用。

我们把它放在循环中,最合适不过,不断把循环出的界面清屏,利用视觉暂留,造成动画效果。

延时函数:Sleep(1);//延时函数,减慢蛇的速度,便于控制,我的代码只有一关,所以直接自己随意改时间,觉得若是好多关卡,可以写一个函数,每关改变括号内的数值,改变游戏难度。
要加上头文件 #include<time.h>

最后就是不知为何,笔记本运行会出现好多莫名其妙的点闪啊闪,在学校机房运行却没有。

运行部分截图如下:
菜单界面
在这里插入图片描述
游戏开始界面:
在这里插入图片描述
游戏中界面:这张截图考手速

在这里插入图片描述
撞墙之后:
在这里插入图片描述
食物必须随机出现,所以使用随机函数生成食物坐标,蛇头控制,蛇的移动是核心,还有蛇的长度增加,蛇移动时身体要跟着蛇头,所以我们总是要备份前一个点的位置,将其赋给后一点,实现蛇的移动,还有用判断语句实现吃完食物蛇的长度加一。

接下来附上代码(含注释):

// GREED Snake.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include<time.h>//蛇走的太快,利用此头文件的函数让他慢下来

using namespace std;

#define KEY_DOWN(vk_code) GetAsyncKeyState(vk_code)&0x8000?1:0

int g_arrMap1[15][20]={
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};
enum
{
	E_MENU_START,
	E_MENU_SETTING,
	E_MENU_EXIT
};
enum
{
	E_GAME_MENU,
	E_GAME_MAP,
	E_GAME_WIN,
	E_GAME_LOSE
};
enum
{
	E_DIR_NONE,
	E_DIR_DOWN,
	E_DIR_UP,
	E_DIR_LEFT,
	E_DIR_RIGHT
};

struct SData
{
	SData()
	{
		nRow = 0;
		nCol = 0;
		nRowBk = 0;
		nColBk = 0;
	}
	SData(int nInRow,int nInCol)
	{
		nRow = nInRow;
		nCol = nInCol;
		nRowBk = nInRow;
		nColBk = nInCol;
	}
	void backUp()//备份函数
	{
		nRowBk = nRow;
		nColBk = nCol;
	}
	void restore()//坐标释放函数
	{
		nRow = nRowBk;
		nCol = nColBk;
	}
	int nRow;
	int nCol;
	int nRowBk;
	int nColBk;

};

int _tmain(int argc, _TCHAR* argv[])
{   Sleep(1);//延时函数,减慢蛇的速度
	int nMenuState =  E_MENU_START;//菜单状态
	int nGameState =  E_GAME_MENU;//游戏状态
	//定义蛇:
	SData arrSnake[15]={};
	//蛇头坐标初始化
	arrSnake[0] = SData(2,2);
	//蛇长度初始化
	int nlength = 1;
	int foodnumber=1;
	//定义蛇头的移动方向,
	int  nDir = E_DIR_NONE;
	//食物坐标
	SData sFood = SData( rand()%13+1, rand()%18+1) ;  //食物随机出现
	while(true)
	{
	system("cls");
		if(E_GAME_MENU == nGameState)
		{
			if(KEY_DOWN(VK_RETURN))//菜单数据更新按下enter键进入游戏地图
			{
				if(E_MENU_START == nMenuState)/*按下enter键时要判断当前箭头是否指示在游戏开始的位置
			    判断nMenuState的值是否是0,是则切换,不是则不管*/
				{nGameState = E_GAME_MAP;}
				else if(E_MENU_EXIT==nMenuState)//退出程序运行框
			     {
			     exit(0);
			     }
			}
			
		    if(KEY_DOWN(VK_UP))
			{
				nMenuState--;
			    if(nMenuState<E_MENU_START)
				  {
					nMenuState = E_MENU_EXIT;
				  }
			}
			else if(KEY_DOWN(VK_DOWN))
			{
				nMenuState++;
				if(nMenuState > E_MENU_EXIT)
				{
					nMenuState = E_MENU_START;
				}
			}
				//菜单渲染
			if(E_MENU_START == nMenuState)
			{
				cout <<"->游戏开始"<< endl;
				cout <<"  游戏设置"<< endl;
				cout <<"  游戏结束"<< endl;
			}
			else if(E_MENU_SETTING == nMenuState)
			{
				cout <<"  游戏开始"<< endl;
				cout <<"->游戏设置"<< endl;
				cout <<"  游戏结束"<< endl;
			}
			else if(E_MENU_EXIT == nMenuState)
			{
				cout <<"  游戏开始"<< endl;
				cout <<"  游戏设置"<< endl;
				cout <<"->游戏结束"<< endl;
			}
		}
		//切地图	
		else if(nGameState == E_GAME_MAP)
		{
			if(KEY_DOWN(VK_ESCAPE))//按下esc键返回菜单
			{
				nGameState = E_GAME_MENU;
			}

			//蛇头的坐标的备份
			arrSnake[0].nRowBk = arrSnake[0].nRow;
			arrSnake[0].nColBk = arrSnake[0].nCol;


			//控制蛇头的自动
			if(KEY_DOWN(VK_UP))
			{
				nDir = E_DIR_UP;
			}
			if(KEY_DOWN(VK_DOWN))
			{
				nDir = E_DIR_DOWN;
			}
			if(KEY_DOWN(VK_LEFT))
			{
				nDir = E_DIR_LEFT;
			}
			if(KEY_DOWN(VK_RIGHT))
			{
				nDir = E_DIR_RIGHT;
			}
			if(nDir == E_DIR_UP)
			{
				arrSnake[0].nRow--;
			}
		
			if(nDir == E_DIR_DOWN)
			{
				arrSnake[0].nRow++;
			}
		
			if(nDir == E_DIR_LEFT)
			{
				arrSnake[0].nCol--;
			}
			
			if(nDir == E_DIR_RIGHT)
			{
				arrSnake[0].nCol++;
			}
			//吃食物
			if(arrSnake[0].nRow == sFood.nRow && arrSnake[0].nCol == sFood.nCol)
			{
				nlength++;
				sFood = SData(rand()%13+1 ,rand()%18+1);
				//foodnumber++;
			}
			//身体跟随蛇头
			for(int i = 1;i < nlength;i++)
				{
					//备份当前这一节坐标
					arrSnake[i].backUp();
						//arrSnake[i].nRowBk = arrSnake[i].nRow;
						//arrSnake[i].nColBk = arrSnake[i].nCol;
					//把这一节的坐标给下一节
						arrSnake[i].nRow = arrSnake[i-1].nRowBk;
						arrSnake[i].nCol = arrSnake[i-1].nColBk;
					
					//在这一节坐标中输出
						
			  }
			//游戏胜负的判断
			//撞墙则失败
			if(1 == g_arrMap1[arrSnake[0].nRow][arrSnake[0].nCol] )
			{
				nGameState = E_GAME_LOSE;
			}
			for(int i=1;i<15;i++)
			{
				if(arrSnake[0].nRow == arrSnake[1].nRow && arrSnake[0].nCol == arrSnake[1].nCol)
				{
					nGameState = E_GAME_LOSE;
					break;
				}
			}
			
			

			//地图渲染
			for(int i=0;i<15;i++)
			{
				for(int j=0;j<20;j++)
				{
					bool bDrawSnake = false;
					for(int m=0; m<15; m++)
					{
						if(i == arrSnake[m].nRow && j == arrSnake[m].nCol)
						{
							bDrawSnake = true;
							break;
						}
					}
					if(1 == g_arrMap1[i][j])
					{
						cout<<"■";
					}
					else if(bDrawSnake)
					{
						cout<<"□";
					}
					else if(i == sFood.nRow && j == sFood.nCol) //输出食物的位置
					{
						cout<<"●";
					}
					else
					{
						cout<<"  ";
					}
				}
				cout<<endl;
			}
		}
		else if ( nGameState == E_GAME_LOSE )
			{
				if(KEY_DOWN(VK_ESCAPE))
				{
					nGameState = E_GAME_MENU;   //按向下键 返回游戏菜单
				}
				cout<<"    很遗憾,你输了这场游戏!"<<endl;
				cout<<"按Esc键退至菜单并进行新游戏吧!";
			}
		
	}
	return 0;
}
 
 



假期实训认识之贪吃蛇。其实一开始不会蛇头自动走时,是仿照推箱子写的手动贪吃蛇,牵着蛇鼻子走,哈哈。

发布了6 篇原创文章 · 获赞 11 · 访问量 456

猜你喜欢

转载自blog.csdn.net/qq_44114055/article/details/103913053