C++实现简易贪吃蛇(不会闪屏幕)

C++实现建议贪吃蛇(不会闪屏幕)

使用vs2013完成。记录踏上游戏开发的道路。

效果图

在这里插入图片描述

代码

// 2021.7.24.1贪吃蛇.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <list>
#include <numeric>  
#include <algorithm> 
#include <Windows.h>
#include <WinUser.h>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;

#define KEY_DOWN(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0)
#define MAX_SNAKE_LEN 20
#define MAP_MAXIMUM_HEIGHT 20
#define MAP_MAXIMUM_WIDTH 20
#define MAX_NUMBER_FRUIT 5


struct sSnakeBody
{
	void setPostion(int x, int y)
	{
		nSnakeBodyX = x;
		nSnakeBodyY = y;
	}
	void setPostion(sSnakeBody* temp)
	{
		nSnakeBodyX = temp->nSnakeBodyX;
		nSnakeBodyY = temp->nSnakeBodyY;
	}
	int nSnakeBodyX;
	int nSnakeBodyY;
};
typedef list<sSnakeBody> LISTSNAKEBODY;

struct sSnake
{
	sSnake()
	{
		nSnakeHeadX = 1;
		nSnakeHeadY = 1;
		nSnakeDirection = 1;
		speed = 5;
	}
	bool isExit(sSnakeBody temp)
	{
		if (nSnakeHeadX==temp.nSnakeBodyX&&nSnakeHeadY==temp.nSnakeBodyY)
		{
			return true;
		}
		return false;
	}
	bool isExit(int x, int y)
	{
		if (nSnakeHeadX == x&&nSnakeHeadY == y)
		{
			return true;
		}
		return false;
	}
	void reduction(sSnakeBody temp)
	{
		nSnakeHeadX = 2 * nSnakeHeadXBk - temp.nSnakeBodyX;
		nSnakeHeadY = 2 * nSnakeHeadYBk - temp.nSnakeBodyY;
	}

	int nSnakeHeadX;
	int nSnakeHeadY;
	int nSnakeHeadXBk;
	int nSnakeHeadYBk;
	int nSnakeDirection;//0表示上,1表示右,2表示下,3表示左,顺时针
	int speed;//指的是几个循环前进一次
	LISTSNAKEBODY snakeBodyList[MAX_SNAKE_LEN];
};

struct sFruit
{
	int FruitX;
	int FruitY;
	sFruit()
	{
		FruitX = -1;
		FruitY = -1;
	}
	sFruit(int x, int y)
	{
		FruitX = x;
		FruitY = y;
	}
	bool isExit(sSnake snake)
	{
		if (FruitX == snake.nSnakeHeadX && FruitY == snake.nSnakeHeadY)
			return true;
		else return false;
	}
};

vector<sFruit> gFruitVector;

sSnake gSnake;

//显示地图
void showArrMap(int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH])
{
	system("cls");
	for (int i = 0; i < MAP_MAXIMUM_HEIGHT; i++)
	{
		for (int j = 0; j < MAP_MAXIMUM_WIDTH; j++)
		{
			if (1 == arrMap[i][j] || gSnake.isExit(i,j))
			{
				cout << "■";
			}
			else if (arrMap[i][j] == 2)
			{
				cout << "●";
			}
			else
			{
				cout << "  ";
			}
		}
		if (4 == i)
		{
			cout << "\t得分:" << gSnake.snakeBodyList->size();
		}

		cout << endl;
	}
}

//将数据加载到地图上。返回值为加载后游戏是否失败
bool mapLoadData(int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH])
{

	//加载水果的数据
	for (unsigned int i = 0; i < gFruitVector.size(); i++)
	{
		arrMap[gFruitVector[i].FruitX][gFruitVector[i].FruitY] = 2;
	}


	//加载蛇的身体数据
	for (LISTSNAKEBODY::iterator iter = gSnake.snakeBodyList->begin(); iter != gSnake.snakeBodyList->end(); iter++)
	{
		arrMap[iter->nSnakeBodyX][iter->nSnakeBodyY] = 1;
	}


	// 吃到第一个水果的时候,一定不是游戏失败
	if (gSnake.snakeBodyList->size() == 1 && gSnake.isExit(gSnake.snakeBodyList->front()))
	{
		return false;
	}


	if (arrMap[gSnake.nSnakeHeadX][gSnake.nSnakeHeadY] == 1)
		return true;
	return false;
}

//更新蛇的数据
void updateSnake(int &nProgramCounter)
{
	if (nProgramCounter > gSnake.speed)
	{
		gSnake.nSnakeHeadXBk = gSnake.nSnakeHeadX;
		gSnake.nSnakeHeadYBk = gSnake.nSnakeHeadY;

		if (gSnake.nSnakeDirection == 0)
		{
			gSnake.nSnakeHeadX--;

		}
		else if (gSnake.nSnakeDirection == 1)
		{
			gSnake.nSnakeHeadY++;
		}
		else if (gSnake.nSnakeDirection == 2)
		{
			gSnake.nSnakeHeadX++;
		}
		else if (gSnake.nSnakeDirection == 3)
		{
			gSnake.nSnakeHeadY--;
		}
		if (gSnake.snakeBodyList->size() != 0)
		{
			if (gSnake.isExit(gSnake.snakeBodyList->front()))
			{
				gSnake.reduction(gSnake.snakeBodyList->front());
			}
		}

		//蛇的身体移动
		if (gSnake.snakeBodyList->size() != 0)
		{
			sSnakeBody snakeBody;
			snakeBody.setPostion(gSnake.nSnakeHeadXBk, gSnake.nSnakeHeadYBk);
			gSnake.snakeBodyList->push_front(snakeBody);
			gSnake.snakeBodyList->pop_back();
		}
		nProgramCounter = 0;
	}
}

//绑定键盘事件
void bindKeyboardEvents()
{
	if (KEY_DOWN(VK_UP))
	{
		gSnake.nSnakeDirection = 0;
	}
	else if (KEY_DOWN(VK_RIGHT))
	{
		gSnake.nSnakeDirection = 1;
	}
	else if (KEY_DOWN(VK_DOWN))
	{
		gSnake.nSnakeDirection = 2;
	}
	else if (KEY_DOWN(VK_LEFT))
	{
		gSnake.nSnakeDirection = 3;
	}

	if (KEY_DOWN(VK_SHIFT))
	{
		gSnake.speed = 2;
	}
	else
	{
		gSnake.speed = 5;
	}
}

//随机生成 N 个水果,
void randomlyGeneratedFruit(int N, int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH])
{
	int maxi = MAP_MAXIMUM_HEIGHT;
	int maxj = MAP_MAXIMUM_WIDTH;
	int AllCnt = 0;

	vector<int> randMap;

	for (int i = 0; i < maxi; i++)
	{
		for (int j = 0; j < maxj; j++)
		{
			if (0 == arrMap[i][j])
			{
				randMap.push_back(i*maxj + j);
				AllCnt++;
			}
		}
	}

	if (AllCnt < N)
	{
		N = AllCnt;
	}
	for (int i = 0; i < N; i++)
	{
		int temp = (rand() % AllCnt--);
		randMap.erase(randMap.begin() + temp);
		sFruit fruitTemp = sFruit(temp / maxi + 1, temp % (maxi - 2) + 1);
		gFruitVector.push_back(fruitTemp);
	}
}

//初始化地图
void initArrMap(int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH])
{
	for (int i = 0; i < MAP_MAXIMUM_HEIGHT; i++)
	{
		for (int j = 0; j < MAP_MAXIMUM_WIDTH; j++)
		{
			if (i == 0 || j == 0 || i == MAP_MAXIMUM_HEIGHT - 1 || j == MAP_MAXIMUM_WIDTH - 1)
				arrMap[i][j] = 1;
			else
				arrMap[i][j] = 0;
		}
	}
}

//初始化水果数据
void initFruit(int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH])
{
	randomlyGeneratedFruit(MAX_NUMBER_FRUIT, arrMap);
}


//蛇头吃到水果事件
void eatFruitEvent(int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH])
{
	for (unsigned int i = 0; i < gFruitVector.size(); i++)
	{
		if (gFruitVector[i].isExit(gSnake))
		{
			sSnakeBody snakeBodyTemp;
			if (gSnake.snakeBodyList->size() == 0)
			{
				snakeBodyTemp.setPostion(gSnake.nSnakeHeadX, gSnake.nSnakeHeadY);
			}
			else
			{
				snakeBodyTemp.setPostion(&gSnake.snakeBodyList->back());
			}
			gSnake.snakeBodyList->push_back(snakeBodyTemp);
			gFruitVector.erase(gFruitVector.begin() + i);
			randomlyGeneratedFruit(1, arrMap);
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{

	HANDLE hOutput;
	COORD coord = { 0, 0 };
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	//创建新的缓冲区
	HANDLE hOutBuf = CreateConsoleScreenBuffer(
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		CONSOLE_TEXTMODE_BUFFER,
		NULL
		);

	//设置新的缓冲区为活动显示缓冲
	SetConsoleActiveScreenBuffer(hOutBuf);

	//隐藏两个缓冲区的光标
	CONSOLE_CURSOR_INFO cci;
	cci.bVisible = 0;
	cci.dwSize = 1;
	SetConsoleCursorInfo(hOutput, &cci);
	SetConsoleCursorInfo(hOutBuf, &cci);

	//双缓冲处理显示
	DWORD bytes = 0;
	char data[3200];

	//地图,需要将数据映射到地图上,再去渲染地图。
	int arrMap[MAP_MAXIMUM_HEIGHT][MAP_MAXIMUM_WIDTH];
	srand(time(NULL));

	//计数器。
	int nProgramCounter = 0;

	//初始化各个数据
	initArrMap(arrMap);
	initFruit(arrMap);

	while (true)
	{
		nProgramCounter++;
		initArrMap(arrMap);
		bindKeyboardEvents();
		updateSnake(nProgramCounter);
		eatFruitEvent(arrMap);
		bool bIsWin = mapLoadData(arrMap);
		showArrMap(arrMap);
		if (bIsWin)
		{
			cout << endl << "游戏失败!!!";
			ReadConsoleOutputCharacterA(hOutput, data, 3200, coord, &bytes);
			WriteConsoleOutputCharacterA(hOutBuf, data, 3200, coord, &bytes);
			break;
		}

		ReadConsoleOutputCharacterA(hOutput, data, 3200, coord, &bytes);
		WriteConsoleOutputCharacterA(hOutBuf, data, 3200, coord, &bytes);
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值