C/C++项目——植物大战僵尸游戏

语言:C 使用工具:Visual Studio2019
使用技术:C语言、easyx图形库

一、游戏运行结果展示:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、开发过程

1、创建游戏开始界面

(1)包含头文件

#include<stdio.h>
#include<graphics.h>//easyx图形库的头文件,需要安装easyx图形库
#include "tools.h"//PNG优化文件
#include<time.h>
#include<math.h>

(2)主函数
调用游戏开始的函数

int main() {
   
	//游戏开始界面
	startUI();
	system("pause");
	return 0;
}

(3)启动菜单函数
1.使用initgraph(WIN_WIDTH, WIN_HEIGHT);创建游戏窗口。
2.使用loadimage进行加载不同状态下的背景图(暗、高亮)。
在这里插入图片描述在这里插入图片描述在这里插入图片描述
3.使用while(1) 循环以持续运行游戏并处理用户输入信息,创建ExMessage 类型变量,用于接收用户消息,其中PeekMessage 函数用于检查消息队列中是否有消息存在,而不会将消息从队列中移除。如果队列中有消息,PeekMessage 可以选择性地检索该消息的信息。
4.鼠标左键是点到开始冒险的位置时,//更改状态flag = 1。当鼠标左键松时且在开始冒险的位置时,退出,进入游戏主界面。
5.BeginBatchDraw() 和 EndBatchDraw() 用于实现双缓冲绘制,以减少屏幕闪烁并提高图形绘制的平滑性。在EasyX中,BeginBatchDraw() 函数用于开始这种双缓冲绘制模式,并创建一个后台缓冲区。这个函数通常会在一个绘制循环的开始处被调用,EndBatchDraw() 函数则用于结束双缓冲绘制模式,并将后台缓冲区的内容显示到屏幕上。这个函数应该在所有的绘制操作完成之后被调用。
注:双缓冲绘制是一种图形编程技术,它涉及到在内存中创建一个“后台”缓冲区,所有的绘制操作都在这个缓冲区中进行,而不是直接在屏幕上进行。一旦所有的绘制操作完成,这个后台缓冲区就会被“交换”到前台,从而一次性地在屏幕上显示所有的更新,这样用户就看不到中间的绘制过程,从而减少了闪烁。

#define WIN_WIDTH 900//窗口宽度
#define WIN_HEIGHT 600//窗口高度
//启动菜单
void startUI()
{
   
	//读取开始菜单的背景图
	IMAGE imgBg,imgMenu1, imgMenu2;
	loadimage(&imgBg, "./res/menu.png");
	loadimage(&imgMenu1, "./res/menu1.png");
	loadimage(&imgMenu2, "./res/menu2.png");
	int flag = 0;//记录冒险开始图片状态
	while (1)
	{
   
		BeginBatchDraw();//开始双缓存
		//显示背景图
		putimage(0, 0, &imgBg);
		putimagePNG(474, 75, flag ? &imgMenu2 : &imgMenu1);
		

		ExMessage msg;
		//获取消息
		if (peekmessage(&msg)) 
		{
   
			//判断鼠标左键是否点到开始冒险的位置
			if (msg.message == WM_LBUTTONDOWN && msg.x > 474 && msg.x < 474 + 300 &&msg.y>75&&msg.y<75+140)
			{
   
				//更改状态
				flag = 1;
			}
			//判断鼠标左键松开是否在开始冒险的位置
			else if (msg.message == WM_LBUTTONUP&&flag==1)
			{
   
				EndBatchDraw();
				break;
			}
		}
		EndBatchDraw();
	}
}

(4)运行截图
在这里插入图片描述

2、创建主场景

(1)创建全局变量
使用枚举方式创建植物类型,定义IMAGE类型的背景图片,工具栏图片、植物卡片图片

enum {
    WAN_DOU, XIANG_RI_KUI, ZHI_WU_XINAG };//定义植物种类

IMAGE imgBg;//表示背景图片
IMAGE imgBar;//表示工具栏图片
IMAGE imgCards[ZHI_WU_XINAG];//植物卡片

(2)初始化游戏背景
1.加载游戏背景图和工具栏图片、并使用memset初始化数组imgZhiWu。
在这里插入图片描述
在这里插入图片描述
2.加载所有植物图片,创建name数组,将每个植物图片的路径都用字符串保留并进行初始化加载。
在这里插入图片描述
2.加载每种植物的图片帧,并进行初始化加载。由于每个植物图片帧数不同,可以判断文件是否存在,进行分配内存。
在这里插入图片描述

//游戏初始化
void GameInit() 
{
   
	//加载游戏背景图片
	loadimage(&imgBg, "./res/bg.jpg");
	//加载游戏工具栏图片
	loadimage(&imgBar, "./res/bar5.png");
	//初始化植物卡片
	char name[64];
	for (int i = 0;i < ZHI_WU_XINAG;i++) 
	{
   
		//生成植物卡片的文件名
		sprintf_s(name, sizeof(name), "./res/Cards/card_%d.png", i + 1);
		loadimage(&imgCards[i], name);
	}
	curZhiWe = 0;
	sunshine = 50;//初始化阳光值
	//创建游戏窗口
	initgraph(WIN_WIDTH, WIN_HEIGHT,1);

}

(3)渲染游戏背景
创建更新窗口函数updateWindow()用于管理渲染图片作用

//更新窗口
void updateWindow()
{
   
	BeginBatchDraw();//开始缓冲
	putimage(-112, 0, &imgBg);//显示背景图
	putimagePNG(250, 0, &imgBar);//显示PNG格式工具栏图
	//显示植物卡片
	drawCards();
	EndBatchDraw();//结束双缓冲
}

(4)渲染工具栏中的植物卡片

//绘制植物卡片
void drawCards()
{
   
	for (int i = 0;i < ZHI_WU_XINAG;i++)
	{
   
		int x = 338 + i * 65;
		int y = 6;
		putimage(x, y, &imgCards[i]);
	}
}

(5)运行截图
在这里插入图片描述

3、实现用户鼠标操作

(1)设置植物结构体
创建植物数据的结构体,当前成员type、frameIndex,创建struct zhiwu类型的一个二维数组map用于记录地图上的植物,GameInit()函数中初始化map数组。

int curX, curY;//当前选中的植物,移动过程中的位置
int curZhiWe;//0表示没有选中,1:表示选中第一种植物...
struct zhiwu {
   
	int type;//0:没有植物  1:第一种植物...
	int frameIndex;//序列帧数的序号
};
struct zhiwu map[3][9];//植物地图格子

void GameInit() 
{
   
memset(map, 0, sizeof(map));
}

(2)设置鼠标消息
1.鼠标按下:用于选择植物,WM_LBUTTONDOWN鼠标左键事件,先判断鼠标位置是否正确,是否在卡片上,更新curZhiwu记录鼠标选择植物卡片是哪种卡片。
2.鼠标移动:用于移动植物,WM_MOUSEMOVE鼠标移动事件,定义全局变量curX, curY,记录当前选中的植物,移动过程中的位置。
3.鼠标松开:用于植物种植,WM_LBUTTONUP 鼠标左键松开事件,当植物种下时,使用变量row,col记录当前的行和高;同时更新map数组中的数据。

//用户鼠标操作
void userClick() 
{
   
	//获取鼠标消息
	ExMessage msg;
	static int status = 0;
	//是否获得消息,获得返回true
	if (peekmessage(&msg)) 
	{
   
		//鼠标左键按下--选择植物
		if (msg.message == WM_LBUTTONDOWN)
		{
   
			//判断鼠标按键位置是否正确
			if (msg.x > 338 && msg.x < 338 + 65 * ZHI_WU_XINAG && msg.y < 96) 
			{
   
				int index = (msg.x - 338) / 65;
				status = 1;
				curZhiWe = index + 1;
			}
			//阳光收集操作
			else 
			{
   
				collectSunshine(&msg);
			}
		}
		//鼠标移动--移动植物
		else if (msg.message == WM_MOUSEMOVE &&status==1)
		{
   
			curX = msg.x;
			curY = msg.y;
		}
		//鼠标左键抬起--种植植物
		else if (msg.message == WM_LBUTTONUP && status == 1)
		{
   
			//在合理范围内
			if (msg.x > 256-112 && msg.y > 179 && msg.y < 489)
			{
   
				//记录鼠标位置
				int row = (msg.y - 179) / 102;//行
				int col = (msg.x - 256+112) / 81;//列
				//printf("%d %d\n", row, col);
				//种植植物
				if (map[row][col].type == 0)
				{
   
					map[row][col].type = curZhiWe;
					map[row][col].frameIndex = 0;
					map[row][col].shootTime = 0;
					map[row][col].x = 256-112 + col * 81;//记录植物x坐标
					map[row][col].y = 179 + row * 102 + 14;//记录植物y坐标
				}
			}
			status = 0;
			curZhiWe = 0;
		}
	}
}

4、渲染植物拖动和种植

(1)创建植物图片帧数组
创建全局二维数组imgZhiWu,用于存储指向图像数据的指针,同时在初始化GameInit() 函数中将数组初始化,
当图片帧存在时,进行申请内存
在这里插入图片描述

IMAGE *imgZhiWu[ZHI_WU_XINAG][20];//存放植物
//游戏初始化
void GameInit() 
{
   
	memset(imgZhiWu,0,sizeof(imgZhiWu));
	//初始化植物卡片
	char name[64];
	for (int i = 0;i < ZHI_WU_XINAG;i++) 
	{
   
		for (int j = 0;i < 20;j++)
		{
   
			sprintf_s(name, sizeof(name), "./res/zhiwu/%d/%d.png",i, j + 1);
			//判断文件是否存在
			if (fileExist(name)) {
   
				//申请内存
				imgZhiWu[i][j] = new IMAGE;
				loadimage(imgZhiWu[i][j], name);
			}
			else {
   
				break;
			}
		}
	}
}

(2)渲染拖到中的植物
在更新窗口updateWindow()函数中调用渲染植物函数,使用curX - img->getwidth() / 2,curY - img->getheight() / 2确保鼠标显示在植物的中心位置,否则在左上角。

//更新窗口
void updateWindow()
{
   
	//渲染植物
	drawZhiWu();
}

void drawZhiWu()
{
   
	//渲染移动中的植物
	if (curZhiWe > 0) {
   
		IMAGE* img = imgZhiWu[curZhiWe - 1][0];
		putimagePNG(curX - img->getwidth() / 2, curY - img->getheight() / 2, img);//实现背景透明,鼠标显示在植物中心
	}
}

(3)渲染种植中的植物
遍历map数组找到已经种植植物的位置,记录坐标,渲染图片帧。

//渲染植物
void drawZhiWu()
{
   
	//渲染种植中的植物
	for (int i = 0;i < 3;i++)
	{
   
		for (int j = 0;j < 9;j++)
		{
   
			if (map[i][j
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值