零基础用c++实现诺基亚上的贪吃蛇,我惊呼爷青回!

爱上编程 专栏收录该内容
1 篇文章 0 订阅

今天是六一儿童节,奖励了自己一瓶旺仔牛奶,觉得还是意犹未尽,作为六岁零170个月的小孩子,我翻出了大一写的贪吃蛇小游戏,玩起来虽然粗糙,但是惊呼“爷青回”啊,让我回到了小板砖一样诺基亚上的贪吃蛇时代。

在这里插入图片描述

六一儿童节,建议大家收藏找回童年嗷,哈哈哈,喜欢作者的希望一键三连点个关注。在文章最后附有完整代码。

本文实现的是一个基于控制台的贪吃蛇小游戏,当时还不会界面这些操作,但是就是因为这样才有童年那味!

界面展示

初始界面中有一些游戏提示信息,还有贪吃蛇和食物的初始位置,以及四周的边框。
#标识我们的贪吃小蛇,*表示食物,●表示边框。
在这里插入图片描述
游戏结束图:
在这里插入图片描述

设计思路

设计一个蛇的类,如图所示:
在这里插入图片描述

绘制边框等操作

具体实现可看下面源码

class snake;
void Init_Console();//控制台初始化
void gotoPos(SHORT x = 0, SHORT y = 0);//光标坐标控制
void Init_Map();//画边框
void KeyConctrl(snake &, int);//键盘控制函数
void is_gameover();//结束提示
void Prompt_info(int, int);//提示信息
void dis_date(int, int, double, int);//得分信息

如何表现位置

蛇身和食物的位置都是使用的COORD结构。

COORD是WindowsAPI中定义的一种结构,表示一个字符在控制台屏幕上的坐标。

typedef struct _COORD {
SHORT X; // horizontal coordinate   
SHORT Y; // vertical coordinate   } COORD;

如何表现蛇身

使用“#”表示蛇身,每吃一个食物就变长一个“#”。

如何表现食物

使用“*”表现食物,每吃掉一个食物,下一个食物就会随机出现在地图里。

如何移动

用"#"表示贪吃蛇,每次移动从蛇头开始,所以蛇不能反向移动,也就是不能倒车。每次输入方向键后,蛇头就会朝着方向移动,然后蛇身在该点也改变自身的方向。
方向分为停止、左、右、上、下。

enum direction { go_stop = 0, go_left, go_right, go_up, go_down }dir;

每一次移动,都要进行碰撞检测,检测是否发生了碰撞。

//    //移动
	bool move()
	{
		switch (this->dir)
		{
		case go_stop:
			break;
		case go_left:
			in_Pos.X -= 2;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		case go_right:
			in_Pos.X += 2;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		case go_up:
			in_Pos.Y--;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		case go_down:
			in_Pos.Y++;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		}
		return false;
	}
};

检验碰撞

检验膨胀边框比较简单,就是测试蛇头的坐标有没有超过边框的范围。

//撞蛇 撞边检测
	bool check_snk(COORD snk_Pos)
	{
		//边界检测
		if (snk_Pos.Y <= 1 || (snk_Pos.Y >= 23) || (snk_Pos.X <= 1) || snk_Pos.X >= 45)
		{
			return true;
		}
		for (int i = clear_bit; i <= print_bit; i++)
		{
			if (_Pos[i].X == snk_Pos.X && _Pos[i].Y == snk_Pos.Y) return true;
		}
		return false;
	}

速度升级

每当贪吃蛇吃掉五个食物,得到500分之后,速度就会+1,速度最高设置为5。

void up_speed()
	{
		if (this->speed < 5)(this->speed)++;

	}

源代码

#include <iomanip>
#include <windows.h>
#include <iostream>
#include <conio.h>
using namespace std;

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//全局句柄
class snake;
void Init_Console();//控制台初始化
void gotoPos(SHORT x = 0, SHORT y = 0);//光标坐标控制
void Init_Map();//画边框
void KeyConctrl(snake &, int);//键盘控制函数
void is_gameover();//结束提示
void Prompt_info(int, int);//提示信息
void dis_date(int, int, double, int);//得分信息

bool gameOver = false;
bool withdraw = false;

class snake
{
private:
	bool flash;
	int speed, length, print_bit, clear_bit;
	COORD in_Pos, bit_Pos;
	COORD _Pos[255];
	enum direction { go_stop = 0, go_left, go_right, go_up, go_down }dir;
public:
	snake(SHORT x = 9, SHORT y = 5)
	{
		clear_bit = print_bit = length = speed = 0;
		in_Pos.X = x; in_Pos.Y = y; bit_Pos.X = 11; bit_Pos.Y = 8;
		flash = true;
		dir = go_stop;
		_Pos[0].X = in_Pos.X;
		_Pos[0].Y = in_Pos.Y;
	}
	~snake() {}
	void up_speed()
	{
		if (this->speed < 5)(this->speed)++;


	}
	double get_speed()
	{
		return this->speed;
	}
	int get_length()
	{
		return this->length;
	}
	//
	void dir_control(char _dir)
	{
		switch (_dir)
		{
		case 's': this->dir = go_stop;
			break;
		case 'l': if (this->dir != go_right)this->dir = go_left;
			break;
		case 'r': if (this->dir != go_left)this->dir = go_right;
			break;
		case 'u': if (this->dir != go_down)this->dir = go_up;
			break;
		case 'd': if (this->dir != go_up)this->dir = go_down;
			break;

		}
	}

	//光标位置
	void setPos(COORD pos)
	{
		SetConsoleCursorPosition(hOut, pos);
	}

	//碰撞检测
	void check_bit()
	{
		if (in_Pos.X == bit_Pos.X && in_Pos.Y == bit_Pos.Y)
		{
			length++;
			if ((length % 5 == 0))
			{
				if (this->speed < 5)this->speed++;
			}
			if (length == 254)
			{
				cout << "游戏通关!";
			}
			do
			{
				srand(time(NULL));
				bit_Pos.X = 3 + (rand() % 20) * 2;
				bit_Pos.Y = 2 + rand() % 20;
			} while (check_snk(bit_Pos));
		}
		else
		{
			cle();
			clear_bit++;
		}
	}
	//撞蛇 撞边检测
	bool check_snk(COORD snk_Pos)
	{
		//边界检测
		if (snk_Pos.Y <= 1 || (snk_Pos.Y >= 23) || (snk_Pos.X <= 1) || snk_Pos.X >= 45)
		{
			return true;
		}
		for (int i = clear_bit; i <= print_bit; i++)
		{
			if (_Pos[i].X == snk_Pos.X && _Pos[i].Y == snk_Pos.Y) return true;
		}
		return false;
	}

	//显示
	void dis()
	{
		if (!flash)
		{
			setPos(bit_Pos);
			SetConsoleTextAttribute(hOut, 0x0e);
			cout << " ";
			flash = true;
		}
		else
		{
			setPos(bit_Pos);
			SetConsoleTextAttribute(hOut, 0x0e);
			cout << "*";
			flash = false;
		}
		setPos(in_Pos);
		SetConsoleTextAttribute(hOut, 0x09);
		cout << "#";

	}
	void cle()
	{

		setPos(_Pos[clear_bit]);
		SetConsoleTextAttribute(hOut, 0x05);
		cout << " ";
	}

	void save_date()
	{

		if (print_bit == 254)
		{
			for (int i = 0; i <= length; i++)
			{
				_Pos[i].X = _Pos[clear_bit + i].X;
				_Pos[i].Y = _Pos[clear_bit + i].Y;
			}
			clear_bit = 0;
			print_bit = length;
		}
		print_bit++;
		_Pos[print_bit].X = in_Pos.X;
		_Pos[print_bit].Y = in_Pos.Y;

	}

	//    //移动
	bool move()
	{
		switch (this->dir)
		{
		case go_stop:
			break;
		case go_left:
			in_Pos.X -= 2;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		case go_right:
			in_Pos.X += 2;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		case go_up:
			in_Pos.Y--;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		case go_down:
			in_Pos.Y++;
			if (check_snk(in_Pos))
			{
				return true;
			}
			dis();
			save_date();
			check_bit();
			break;
		}
		return false;
	}
};

int main()
{
	do
	{
		Init_Console();
		Init_Map();
		Prompt_info(3, 3);
		snake s(27, 11);
		clock_t t_in, t_out;
		t_in = clock();
		s.dis();
		//
		while (!gameOver)
		{
			if (_kbhit())
			{
				KeyConctrl(s, _getch());
			}

			t_out = clock();
			dis_date(3, 5, s.get_speed(), s.get_length());
			if (t_out - t_in > ((0.25 - (s.get_speed() / 25)) * CLOCKS_PER_SEC))
			{
				t_in = t_out;
				gameOver = s.move();
				if (gameOver)
				{
					is_gameover();
				}
			}
			Sleep(10);
		}
		//
		while (gameOver)
		{
			if (_kbhit())
			{
				switch (_getch())
				{
				case 'y':
				case 'Y':
					gameOver = false;
					system("cls");
					break;
				case 'n':
				case 'N':
					gameOver = false;
					withdraw = true;
					break;
				}
			}
			Sleep(10);
		}
	} while (!withdraw);
	gotoPos(15, 13);
	return 0;
}

//控制台初始化
void Init_Console()
{
	SetConsoleTitleA("Console_贪吃蛇");
	COORD dSiz = { 80, 25 };
	SetConsoleScreenBufferSize(hOut, dSiz);//设置窗口缓冲区大小
	CONSOLE_CURSOR_INFO _guan_biao = { 1, FALSE };//设置光标大小,隐藏光标
	SetConsoleCursorInfo(hOut, &_guan_biao);
	system("color 0f");//设置画布颜色

}
//光标位置
void gotoPos(SHORT x, SHORT y)
{
	COORD pos = { x, y };
	SetConsoleCursorPosition(hOut, pos);
}
//画边框
void Init_Map()
{
	//SetConsoleTextAttribute(hOut, 0xF0); //设置前景色,背景色
	system("cls");
	//左边框
	for (int i = 0; i < 23; i++)
	{
		cout << endl << " ●";
	}
	//上边框
	gotoPos(3, 1);
	for (int i = 0; i < 21; i++)
	{
		cout << "●";
	}
	//下边框
	gotoPos(3, 23);
	for (int i = 0; i < 21; i++)
	{
		cout << "●";
	}
	//右边框
	for (SHORT i = 1; i <= 23; i++)
	{
		gotoPos(45, i);
		cout << "●";
	}
}
//键盘控制函数
void KeyConctrl(snake &_snk, int _key)
{
	switch (_key)
	{
	case ' ':
		_snk.dir_control('s');
		break;
	case 'w':
	case 'W':
	case 72: _snk.dir_control('u');
		break;
	case 'a':
	case 'A':
	case 75: _snk.dir_control('l');
		break;
	case 'd':
	case 'D':
	case 77: _snk.dir_control('r');
		break;
	case 's':
	case 'S':
	case 80: _snk.dir_control('d');
		break;
	case '+': _snk.up_speed();
		break;
	default: break;
	}
}
//结束提示
void is_gameover()
{

	gotoPos(17, 11);
	SetConsoleTextAttribute(hOut, 0xec);
	cout << "game over!";
	gotoPos(15, 12);
	cout << "Y重新开始/N退出";
	SetConsoleTextAttribute(hOut, 0x0f);

}
//提示信息
void Prompt_info(int _x, int _y)
{

	SetConsoleTextAttribute(hOut, 0xB);
	gotoPos(_x + 47, _y + 0);
	cout << "■游戏说明:";
	gotoPos(_x + 51, _y + 2);
	cout << "A.每得500分移速自动加1";
	gotoPos(_x + 51, _y + 3);
	cout << "B.可手动加速,最高移速5";
	gotoPos(_x + 47, _y + 5);
	cout << "■操作说明:";
	gotoPos(_x + 51, _y + 7);
	cout << "□向左移动:← A";
	gotoPos(_x + 51, _y + 8);
	cout << "□向右移动:→ D";
	gotoPos(_x + 51, _y + 9);
	cout << "□向下移动:↓ S";
	gotoPos(_x + 51, _y + 10);
	cout << "□向上移动:↑ W";
	gotoPos(_x + 51, _y + 11);
	cout << "□控制加速:+";
	gotoPos(_x + 51, _y + 12);
	cout << "□暂停游戏:空格";
	gotoPos(_x + 51, _y + 13);
	cout << "□开始游戏:任意方向键";
	gotoPos(_x + 47, 22);
	cout << "■By: Codebowl 就是靓仔我啦";
}
//速度积分显示
void dis_date(int _x, int _y, double Sped, int Score)
{
	SetConsoleTextAttribute(hOut, 0xB);
	gotoPos(_x + 47, _y + 13);
	cout << setw(2) << "◆ 移动速度: ";
	SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
	cout << Sped;
	gotoPos(_x + 47, _y + 14);
	SetConsoleTextAttribute(hOut, 0xB);
	cout << "◆ 当前积分: ";
	SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
	cout << setw(2) << Score * 100;
}

编程这些小游戏,会让你在不知不觉中爱上编程,特别适合初学者研究和实现。

这里是最强学妹工具人Codebowl。
一个面试C++开发,却误入大厂数据开发的靓仔。
希望大家一键三联,给个关注嗷

  • 37
    点赞
  • 50
    评论
  • 3
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值