C++贪吃蛇游戏开发实践

news2024/12/29 10:43:13

C++贪吃蛇游戏开发实践

snake

对象分析

snakemove

我们首先需要确定一个像素点组成的地图(画布),要确定行数、列数和像素点大小。这个地图上将会有两个对象:蛇和食物。

蛇由头和身子组成,他们都有自己的位置,所以考虑使用位置点数组来存储。同时,还要存储蛇头方向和蛇身体节数。

而食物只要记录其位置即可。

地图上的内容就是蛇与食物,如果做图形界面,就是不断地在画布上绘制蛇与食物的过程。这里主要用到了绘制矩形与填充矩形的函数。

蛇的移动

蛇的移动就是对蛇身数组的操作,可以分类讨论。如果是蛇身,我们从蛇尾开始观察,会发现每一节的位置将是前一节的位置。即前一节的位置直接赋值给后一节即可,但要注意要从蛇尾开始操作。如果是蛇头,将取决于当前蛇的方向,但要注意不能掉头。

snakemove

蛇吃食物

蛇吃食物的判定是蛇头与食物位置是否重叠,如果吃到了要增长蛇身和重新投放食物。增长蛇身其实就是在蛇身数组的末尾再复制一份蛇尾。重新投放食物时要注意不能放在蛇身上。

eat

算法实现

图形界面

图形界面的代码在主函数里:

initgraph(WIDTH, HEIGHT);
while (true) {
    ...
}
closegraph();

整个绘制对象只用到了绘制矩形

  • setcolor(color);设置线颜色
  • setfillcolor(color);设置填充颜色
  • fillrect(x1, y1, x2, y2);绘制矩形需要左上角和右下角的点位置

方向枚举

enum Direction
{
	RIGHT = 39,
	LEFT = 37,
	DOWN = 40,
	UP = 38,
};

为了方便与键盘输入对应,将上下左右的键值进行枚举。

小蛇移动

结合上面的示意图理解小蛇移动的算法实现。

void snakeMove()
{
	// 更新蛇身
	for (int i = snake.num-1; i > 0; i--) {
		snake.body[i].x = snake.body[i-1].x;
		snake.body[i].y = snake.body[i-1].y;
	}
	// 更新蛇头
	switch (snake.dir) {
	case RIGHT:
		snake.body[0].x++;
		break;
	case LEFT:
		snake.body[0].x--;
		break;
	case DOWN:
		snake.body[0].y++;
		break;
	case UP:
		snake.body[0].y--;
		break;
	}
}

蛇吃食物

结合上面的示意图理解蛇吃食物的算法实现。

void eatFood()
{
	int x = snake.body[0].x;
	int y = snake.body[0].y;
	if (food.pos.x == x && food.pos.y == y) {
		// 食物重新投放
		bool flag;
		do {
			flag = false;
			food.pos.x = rand()%(M-2) + 1;
			food.pos.y = rand()%(N-2) + 1;
			for (int i = 0; i < snake.num; i++) {
				int x = snake.body[i].x, y = snake.body[i].y;
				if (x == food.pos.x && y == food.pos.y) {
					flag = true;
					break;
				}
			}
		} while (flag);
		// 蛇身增长
		snake.body[snake.num].x = snake.body[snake.num-1].x;
		snake.body[snake.num].y = snake.body[snake.num-1].y;
		snake.num++;
	}
}

代码实现

这里使用的是EGE库,需要提前安装。

#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
// 画布参数
const int N = 10;	// 行数
const int M = 10;	// 列数
const int L = 40;	// 像素点大小
const int T = 400;	// 间隔
// 方向枚举
enum Direction
{
	RIGHT = 39,
	LEFT = 37,
	DOWN = 40,
	UP = 38,
};
// 点结构体
struct Point
{
	int x, y;
	int X() {return x*L;}
	int Y() {return y*L;}
};
// 蛇结构体
struct Snake
{
	int num;
	Point body[N*M];
	Direction dir;
} snake;
// 食物结构体
struct Food
{
	Point pos;
} food;
// 功能函数
void initSnake();	// 初始化小蛇
void initFood();	// 初始化食物
void drawBoard();	// 绘制网格
void drawSnake();	// 绘制小蛇
void drawFood();	// 绘制食物
void drawAll();		// 全部绘制
void snakeMove();	// 小蛇移动
void eatFood();		// 吃到食物
bool snakeDie();	// 小蛇撞死
void keyDown();		// 按键处理

// -------------------主函数----------------------
int main()
{
	initgraph(M*L, N*L);
	begin:
	initSnake();
	initFood();
	while (true) {
		if (kbhit()) {	// 监听键盘按键
			keyDown();
		}
		snakeMove();
		if (snakeDie()) {
			MessageBox(getHWnd(),"Game Over!","rePlay",MB_OK);
			goto begin;
		}
		eatFood();
		drawAll();
		Sleep(T);
	}
	closegraph();
	return 0;
}

void initSnake()
{
	snake.num = 3;
	snake.dir = RIGHT;
	snake.body[2].x = 1;
	snake.body[2].y = 1;
	snake.body[1].x = 2;
	snake.body[1].y = 1;
	snake.body[0].x = 3;
	snake.body[0].y = 1;
}

void initFood()
{
	bool flag;
	do {
		flag = false;
		food.pos.x = rand()%(M-2) + 1;
		food.pos.y = rand()%(N-2) + 1;
		// 如果食物在蛇身上则重新投放
		for (int i = 0; i < snake.num; i++) {
			int x = snake.body[i].x, y = snake.body[i].y;
			if (x == food.pos.x && y == food.pos.y) {
				flag = true;
				break;
			}
		}
	} while (flag);
}

void drawBoard()
{
	for (int i = 0; i < M; i++) {
		for (int j = 0; j < N; j++) {
			setcolor(BLUE);
			setfillcolor(BLACK);
			fillrect(i*L, j*L, i*L+L, j*L+L);
		}
	}
	for (int i = 0; i < N; i++) {
		setcolor(BLUE);
		setfillcolor(EGERGB(0, 0, 139));
		fillrect(0, i*L, L, i*L+L);
		fillrect((M-1)*L, i*L, M*L, i*L+L);
	}
	for (int i = 0; i < M; i++) {
		setcolor(BLUE);
		setfillcolor(EGERGB(0, 0, 139));
		fillrect(i*L, 0, i*L+L, L);
		fillrect(i*L, (N-1)*L, i*L+L, N*L);
	}
}

void drawSnake()
{
	for (int i = 0; i < snake.num; i++) {
		setcolor(BLUE);
		setfillcolor(EGERGB(0,100,0));
		fillrect(snake.body[i].X(),snake.body[i].Y(),snake.body[i].X()+L,snake.body[i].Y()+L);
	}
}

void drawFood()
{
	setcolor(BLUE);
	setfillcolor(RED);
	fillrect(food.pos.X(),food.pos.Y(),food.pos.X()+L,food.pos.Y()+L);
}

void drawAll()
{
	drawBoard();
	drawFood();
	drawSnake();
}

void snakeMove()
{
	// 更新蛇身
	for (int i = snake.num-1; i > 0; i--) {
		snake.body[i].x = snake.body[i-1].x;
		snake.body[i].y = snake.body[i-1].y;
	}
	// 更新蛇头
	switch (snake.dir) {
	case RIGHT:
		snake.body[0].x++;
		break;
	case LEFT:
		snake.body[0].x--;
		break;
	case DOWN:
		snake.body[0].y++;
		break;
	case UP:
		snake.body[0].y--;
		break;
	}
}

void eatFood()
{
	int x = snake.body[0].x;
	int y = snake.body[0].y;
	if (food.pos.x == x && food.pos.y == y) {
		// 食物重新投放
		bool flag;
		do {
			flag = false;
			food.pos.x = rand()%(M-2) + 1;
			food.pos.y = rand()%(N-2) + 1;
			for (int i = 0; i < snake.num; i++) {
				int x = snake.body[i].x, y = snake.body[i].y;
				if (x == food.pos.x && y == food.pos.y) {
					flag = true;
					break;
				}
			}
		} while (flag);
		// 蛇身增长
		snake.body[snake.num].x = snake.body[snake.num-1].x;
		snake.body[snake.num].y = snake.body[snake.num-1].y;
		snake.num++;
	}
}

bool snakeDie()
{
	int x = snake.body[0].x;
	int y = snake.body[0].y;
	// 超出边框
	if (x >= (M-1) || y >= (N-1) || x <= 0 || y <= 0) {
		return true;
	}
	// 迟到自身
	for (int i = 1; i < snake.num; i++) {
		if (x == snake.body[i].x && y == snake.body[i].y) {
			return true;
		}
	}
	return false;
}

void keyDown()
{
	char userKey = 0;
	userKey = getch();
	switch (userKey) {
	case LEFT:
		if (snake.dir != RIGHT) {
			snake.dir = LEFT;
		}
		break;
	case RIGHT:
		if (snake.dir != LEFT) {
			snake.dir = RIGHT;
		}
		break;
	case UP:
		if (snake.dir != DOWN) {
			snake.dir = UP;
		}
		break;
	case DOWN:
		if (snake.dir != UP) {
			snake.dir = DOWN;
		}
	}
}
  • snake

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/115444.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

移动端测试必备技能: adb命令和抓包

移动端测试 是指对移动应用进行的测试&#xff0c;即实体的特性满足需求的程度&#xff0c;进行测试前需要搭建测试环境。 1 移动端自动化环境搭建 1.1 java安装 java JDK 安装jdk-8u181-windows-x64.exe 配置环境变量&#xff1a; JAVA_HOME&#xff1a;D:\developer to…

基于C#+SqlServer开发(WinForm)学生宿舍管理系统【100010056】

学生宿舍管理系统 一、前言 学生宿合是学生们最为熟悉的领域&#xff0c;假定学校有若干栋宿会楼&#xff0c;每栋宿合楼有若干层&#xff0c;每层有若干个寝室&#xff0c;每个寝室可住若干个学生。以往的手工操作已经不能适应现在办公的需要.为了摆脱繁琐的劳动,提高工作效…

HTML XHTML HTML5区别

文章目录HTML & XHTML & HTML5区别HTMLXHTMLHTML5区别HTML & XHTML & HTML5区别 HTML HTML&#xff0c;全称“HyperText Mark-up Language&#xff08;超文本标记语言&#xff09;”&#xff0c;它是构成网页文档的主要语言。我们常说的HTML&#xff0c;指的…

金融服务机构提高移动应用程序安全性的 3 种方式

金融移动应用程序的使用正在迅速加速&#xff0c; 2020 年用户会话数量增长了 49% 。VMware报告称&#xff0c;金融应用程序的网络攻击在同年也增长了 118%。 Intertrust的另一份报告显示&#xff0c;77% 的金融服务应用程序至少包含一个可能导致数据泄露的安全漏洞。最近发现…

【Three.js入门】纹理加载进度、环境贴图、经纬线映射贴图与高动态范围成像HDR

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

VMwareLinux详细安装步骤

一、VmWare虚拟机的安装 目录 一、VmWare虚拟机的安装 1、安装虚拟机 二、在虚拟机上安装CentOS 1、创建新虚拟机 2、选择典型→ 下一步 3、选择稍后安装操作系统 4、选择操作系统和版本 5、输入虚拟机名称和安装路径 6、设置磁盘大小 7、选择CentOS安装镜像文件 8、…

射线检测中的像质计

像质计&#xff0c;透度计 Image Quality Indicators&#xff0c;Penetrameters 分类&#xff1a;线型像质计、阶梯孔型像质计、平板孔型像质计、双丝型像质计。 前三种像质计的作用&#xff1a;测定检测图像的厚度&#xff08;密度&#xff09;对比度&#xff1b; 后一种像质…

数论专题(1)数论函数,整数分块

从今天起,我们将要开始数论的学习,是不是感觉很难?难的话就听我讲吧,讲了后就不难了(bushi) 数论函数定义 (数论函数) 数论函数的定义:在全体正整数&#xff08;或者整数&#xff09;上定义的函数称作数论函数。 积性的定义&#xff1a;若 gcd(a,b)1,则f(ab)f(a)f(b)。举个栗…

适合制造业的ERP系统有哪些? 制造业的ERP对企业有什么作用?

在当前的激烈的市场竞争下&#xff0c;制造企业如果想要长期稳定地发展&#xff0c;除了需要把外部因素做好把控&#xff0c;还需要提升企业自身的管理水平&#xff0c;来提高自己的竞争力&#xff0c;而信息化是企业发展的必经之路。 适合制造业的ERP系统在企业管理中起到了至…

《Science》教你如何写好一篇博士毕业论文!

博士生涯的完美结束少不了一篇优秀的毕业论文。但是说起来容易&#xff0c;写起来有时让人痛不欲生。不仅内容多&#xff0c;还需要用严谨的逻辑把章节联系起来&#xff0c;常常耗时耗力。而且博士论文要的不仅仅是学术工作的质量&#xff0c;如何将这些工作合理、完整地呈现也…

基于Java实现(PC)大学班级事务管理系统【100010059】

大学班级事务管理系统 要求 本次设计要求利用 Java 实现 C/S 模式的大学班级内日常事务管理系统&#xff08;PC 版&#xff0c;应用于校内网有线网络访问&#xff0c;暂不开发移动端&#xff09;&#xff0c;不得依赖现有的建模框架&#xff0c;使用 swings 技术完成如下基本…

IP地址分类及范围详解

IP地址分为公网IP地址&#xff08;合法IP地址&#xff09;和私有IP地址 公网IP地址主要应用于Internet上的主机访问&#xff0c;而私有IP地址应用于局域网中计算机的相互通信。 IP地址的表示形式&#xff1a;分为二进制表示和点分十进制表示。现在使用的IP地址长度均为32位/4个…

阿里云oss访问图片出现跨域问题

需要服务器端支持&#xff0c;开一下cdn Access-Control-Allow-Origin字段是服务端添加了才有的&#xff0c;前端加了crossOrigin"anonymous"是想跨域获取这张图片&#xff0c;好用在canvas.toDataURL()上&#xff0c;但是服务端不一定同意&#xff0c;服务端添加了…

开始摸索学习go,具体内容和过程就慢慢补充吧。

计划学习路线 文章目录计划学习路线书籍开源项目资料网站课程书籍 《go语言核心编程》 -腾讯作者 《go语言编程之旅》 -5个项目 --对go语言能做的内容做了整体介绍吧&#xff0c;对细节还不够细化&#xff0c;对独立编写代码帮助有限 第二章 swaage 有版本冲突&#xff0c;等…

37.卷积神经网络(LeNet)的代码实现(在colab上)

ps&#xff1a;在教材上直接打开colab&#xff0c;运行原来的代码!pip install githttps://github.com/d2l-ai/d2l-zhrelease # installing d2l是会报错的&#xff0c;改成这句代码&#xff0c;可以正确运行&#xff1a;!pip install d2l0.14.&#xff0c;直接制定了d2l的版本 …

利用Bat打开exe程序并传入值

目录 一、分清楚exe接收值的方式 1、打开exe时提示输入1、2、3... 2、知道exe形参&#xff08;程序主函数中定义的argv[]&#xff09; 二、call和start的区别 一、分清楚exe接收值的方式 1、打开exe时提示输入1、2、3... 如图&#xff1a; 这种是程序运行时接收用户输入…

SuperMap GIS 三维硬件设置优化

目录一、简介二、查看硬件显卡三、显卡设置1、NVIDA显卡设置2、AMD显卡设置一、简介 我们都知道为了体验更好的大型3D游戏&#xff0c;那么好的显卡是必不可少的。但是有了好的显卡当配置不对时&#xff0c;此时体验感也会大打折扣。同样的道理&#xff0c;在SuperMap中也需要…

Redis原理篇—通信协议

Redis原理篇—通信协议 笔记整理自 b站_黑马程序员Redis入门到实战教程 RESP协议 Redis 是一个 CS 架构的软件&#xff0c;通信一般分两步&#xff08;不包括 pipeline 和 PubSub&#xff09;&#xff1a; 客户端&#xff08;client&#xff09;向服务端&#xff08;server&a…

VMC证书是什么?获取认证标志证书步骤是怎样的?

VMC证书是什么&#xff1f; VMC证书(全称&#xff1a;Verified Mark Certificate)&#xff0c;也称认证标志证书&#xff0c;是由权威CA机构颁发&#xff0c;用于验证商标所有权的数字证书。 VMC 通过提供验证机制与 BIMI 协同工作&#xff0c;BIMI标准可以在电子邮件中的“发…

OSCS开源安全周报第23期:Foxit PDF Reader/Editor 任意代码执行漏洞

本周安全态势综述 OSCS 社区共收录安全漏洞10个&#xff0c;其中公开漏洞值得关注的是 Apache Airflow Hive Provider <5.0.0 存在操作系统命令注入漏洞&#xff08;CVE-2022-46421&#xff09;vm2 < 3.9.10 存在任意代码执行漏洞&#xff08;CVE-2022-25893&#xff0…