C++项目实战:贪吃蛇

环境:Visual Studio 2022

语言:C++

数据结构:顺序表

完整代码:

#include <iostream>
#include <Windows.h>
#include <conio.h>

using namespace std;

#define H 27
#define W 60

const int dir[4][2] = {
	{-1, 0}, // 上
	{0, 1},  // 右
	{1, 0},  // 下
	{0, -1}  // 左
};

enum BlockType {
	EMPTY = 0,
	FOOD = 1,
};

struct Map {
	BlockType data[H][W];
	bool hasFood;
};

struct Pos {
	int x;
	int y;
};

struct Snack {
	Pos snack[H * W];
	int snackDir;
	int snackLength;
	int lastMoveTime;
	int moveFreqency;
};

void initSnack(Snack* snk) {
	snk->snackDir = 1;
	snk->snackLength = 3;
	snk->snack[0] = { W / 2, H / 2 };
	snk->snack[1] = { W / 2 - 1, H / 2 };
	snk->snack[0] = { W / 2 - 2, H / 2 };
	snk->lastMoveTime = 0;
	snk->moveFreqency = 500;
}

void hideCursor() {
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO curInfo = { 1, FALSE };
	SetConsoleCursorInfo(hOutput, &curInfo);
}

void initMap(Map* map) {
	for (int y = 0; y < H; ++y) {
		for (int x = 0; x < W; ++x) {
			map->data[y][x] = BlockType::EMPTY;
		}
	}
	map->hasFood = false;
}

void drawUnit(Pos p, const char unit[]) {
	COORD coord;
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	coord.X = p.x + 1;
	coord.Y = p.y + 1;
	SetConsoleCursorPosition(hOutput, coord);
	cout << unit;
}

void drawMap(Map* map) {
	system("cls");
	cout << "┏";
	for (int i = 0; i < W; ++i) {
		cout << "━";
	}
	cout << "┓" << endl;
	for (int y = 0; y < H; ++y) {
		cout << "┃";
		for (int x = 0; x < W; ++x) {
			if (map->data[y][x] == BlockType::EMPTY)
				cout << " ";
		}
		cout << "┃" << endl;
	}
	cout << "┗";
	for (int i = 0; i < W; ++i) {
		cout << "━";
	}
	cout << "┛" << endl;
}

void drawSnack(Snack* snk) {
	for (int i = 0; i < snk->snackLength; ++i) {
		drawUnit(snk->snack[i], "■");
	}
}

void moveSnack(Snack* snk) {
	for (int i = snk->snackLength - 1; i >= 1; --i) {
		snk->snack[i] = snk->snack[i - 1];
	}
	snk->snack[0].y += dir[snk->snackDir][0];
	snk->snack[0].x += dir[snk->snackDir][1];
}

bool checkOutOfBound(Pos p) {
	if (p.x <= 0 || p.x >= W) {
		return true;
	}
	if (p.y <= 0 || p.y >= H) {
		return true;
	}
	return false;
}

void checkEatFood(Snack* snk, Pos tail, Map* map) {
	Pos head = snk->snack[0];
	if (map->data[head.y][head.x] == BlockType::FOOD) {
		snk->snack[snk->snackLength++] = tail;
		map->data[head.y][head.x] = BlockType::EMPTY;
		map->hasFood = false;
		drawUnit(tail, "■");
	}
}

bool doMove(Snack* snk, Map* map) {
	Pos tail = snk->snack[snk->snackLength - 1];
	drawUnit(snk->snack[snk->snackLength - 1], " ");
	moveSnack(snk);
	if (checkOutOfBound(snk->snack[0])) {
		return false;
	}
	checkEatFood(snk, tail, map);
	drawUnit(snk->snack[0], "■");
	return true;
}

bool checkSnackMove(Snack* snk, Map* map) {
	int curTime = GetTickCount();
	if (curTime - snk->lastMoveTime > snk->moveFreqency) {
		if (false == doMove(snk, map))
			return false;
		snk->lastMoveTime = curTime;
	}
	return true;
}

void checkChangeDir(Snack* snk) {
	if (_kbhit()) {
		switch (_getch()) {
		case 'w':
			if (snk->snackDir != 2)
				snk->snackDir = 0;
			break;
		case 'd':
			if (snk->snackDir != 3)
				snk->snackDir = 1;
			break;
		case 's':
			if (snk->snackDir != 0)
				snk->snackDir = 2;
			break;
		case 'a':
			if (snk->snackDir != 1)
				snk->snackDir = 3;
			break;
		default:
			break;
		}
	}
}

void checkFoodGenerate(Snack* snk, Map* map) {
	if (map->hasFood == false) {
		while (1) {
			int x = rand() % W;
			int y = rand() % H;
			int i = 0;
			while (i < snk->snackLength) {
				if (x == snk->snack[i].x && y == snk->snack[i].y) {
					break;
				}
				i++;
			}
			if (i == snk->snackLength) {
				map->data[y][x] = BlockType::FOOD;
				map->hasFood = true;
				drawUnit({ x, y }, "●");
				return;
			}
		}
	}
}

void innitGame(Snack* snk, Map* map) {
	hideCursor();
	initMap(map);
	initSnack(snk);
	drawMap(map);
	drawSnack(snk);
}

int main() {
	Map map;
	Snack snk;
	innitGame(&snk, &map);
	while (1) {
		checkChangeDir(&snk);
		if (false == checkSnackMove(&snk, &map)) {
			break;
		}
		checkFoodGenerate(&snk, &map);
	}
	drawUnit({ W / 2 - 4, H / 2 }, "Game Over!");
	while(1) {}

	return 0;
}

运行截图:

 

  • 18
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值