C语言、c++实现超好玩植物大战僵尸(完整版附源码),C语言与C++实现超好玩植物大战僵尸游戏(附完整源码)

马肤
摘要:本文介绍了使用C语言和C++实现超好玩的植物大战僵尸游戏的完整版,并附上了源码。游戏具有完整的游戏机制和角色设定,玩家可以体验植物与僵尸之间的激烈战斗。通过本文,读者可以了解到如何使用C语言和C++进行游戏开发,并获取完整的游戏源码,以便进一步学习和探索。

实现这个游戏需要Easy_X

C语言、c++实现超好玩植物大战僵尸(完整版附源码),C语言与C++实现超好玩植物大战僵尸游戏(附完整源码) 第1张

main.cpp

//开发日志
//1导入素材
//2实现最开始的游戏场景
//3实现游戏顶部的工具栏
//4实现工具栏里面的游戏卡牌
#define WIN_WIDTH 900
#define WIN_HEIGHT 600
//定义植物类型
enum { WAN_DOU, XIANG_RI_KUI, ZHI_WU_COUNT };
#include
#include//easyx图形库的头文件
#include"tools.h"
#include"vector2.h"//向量引用
#include
#include
#include//导入音乐收集阳光的时候
//导入一个库
#include
#pragma comment(lib,"winmm.lib")
IMAGE imgBg;//全局变量表示背景图片
IMAGE imgBar;//工具栏
IMAGE imgCards[ZHI_WU_COUNT];
IMAGE* imgZhiwu[ZHI_WU_COUNT][20];
int curX, curY;//当前选中的植物,在拖动过程中的位置
int curZhiwu;//0没有选中。 1选中了第一种植物
 
struct zhiwu
{
	int type;//植物种类 0:表示没有植物 1:第一种植物
	int frameIndex;//序列帧的序号
 
	bool catched;//是否被僵尸捕获
	int deadTime;//死亡倒计时
 
	int x, y;
	int timer;
};
 
struct zhiwu map[3][9];
//定义一个阳光结构体
 
enum { SUNSHINE_DOWN, SUNSHINE_GROUND, SUNSHINE_COLLECT, SUNSHINE_RPODUCT };
 
 
struct sunshineBall
{
	int x, y;//阳光球飘落位置的坐标(x不变)
	int frameIndex;//当前图片显示帧的序号
	//阳光有一个落点设置
	int destY;//飘落位置的Y坐标
	bool used;//判断是否在使用
	//计时器
	int timer;
 
	float xoff;
	float yoff;
 
	float t;//贝塞尔曲线时间点0..1
	vector2 p1, p2, p3,p4;//分别对应起点终点控制点
	vector2 pCur;//当前时刻阳光球的位置
	float speed;
	int status;//阳光状态
};
 
struct sunshineBall balls[10];//设置10个阳光池
IMAGE imgSunshineBall[29];//加载阳光图片,一共29放入数组中
int sunshine;
 
struct zm
{
	int x, y;
	int row;
	int frameIndex;
	bool used;
	int speed;
	int blood;//僵尸血条
	bool dead;
	bool eating;//正在吃植物
};
struct zm zms[10];
IMAGE imgZM[22];
IMAGE imgZMDead[20];
IMAGE imgZMEat[21];
 
//子弹的数据类型
struct bullet
{
	int x, y;
	int row;
	bool used;
	int speed;
	bool blast;//定义豌豆射出的子弹是否发生爆炸
	int frameIndex;//帧序号
};
 
struct bullet bullets[30];
IMAGE imgBulletNormal;
IMAGE imgBallBlast[4];
 
bool fileExist(const char* name)
{
	FILE* fp = fopen(name, "r");//r表示文件的读取
	if (fp == NULL)
	{
		return false;
	}
	else
	{
		fclose(fp);
		return true;
	}
}
 
 
void gameInit()
{
	//加载游戏背景图片
	//把字符集修改成多字符字符集
	loadimage(&imgBg,"res/bg.jpg");
	loadimage(&imgBar,"res/bar5.png");
 
	memset(imgZhiwu, 0, sizeof(imgZhiwu));
	//初始化植物卡牌
	memset(map, 0, sizeof(map));
	char name[64];
	for (int i = 0; i getheight(),
				img);
		}
	}
}
void drawSunshines()
{
	int ballMax = sizeof(balls) / sizeof(balls[0]);
	for (int i = 0; i  0)
			{
				//int x = 256 + j * 81;
				//int y = 179 + i*102+14;
				int Zhiwutype = map[i][j].type - 1;
				int index = map[i][j].frameIndex;
				//putimagePNG(x, y, imgZhiwu[Zhiwutype][index]);
				putimagePNG(map[i][j].x, map[i][j].y,imgZhiwu[Zhiwutype][index]);
			}
		}
	}
	//渲染拖动过程中的植物
	if (curZhiwu)
	{
		IMAGE* img = imgZhiwu[curZhiwu - 1][0];
		putimagePNG(curX - img->getwidth()/2, curY - img->getheight()/2, img);
	}
 
 
	drawSunshines();//绘制阳光
 
 
	char scoreText[8];
	sprintf_s(scoreText, sizeof(scoreText),"%d",sunshine);
	outtextxy(276,67,scoreText);//输出阳光分数
 
	drawZM();//渲染僵尸
 
 
	//渲染阳光
	int bulletMax = sizeof(bullets) / sizeof(bullets[0]);
	for (int i = 0; i x > x && msg->xy>y && msg->y  338 && msg.x  256 && msg.y > 179 && msg.y = fre )
	{
		fre = 200 + rand() % 200;
		count = 0;//满了计数器清0
		//从阳光池中去一个可以使用的
		int ballMax = sizeof(balls) / sizeof(balls[0]);
		int i = 0;
		for (i = 0; i = ballMax) return;//阳光池满了
		balls[i].used = true;
		balls[i].frameIndex = 0;
		//balls[i].x = 260 + rand() % (900 - 260);
		//balls[i].y = 60;
		//balls[i].destY = 200 + (rand() % 4) * 90;
		balls[i].timer = 0;
		//balls[i].xoff = 0;
		//balls[i].yoff = 0;
		balls[i].status = SUNSHINE_DOWN;
		balls[i].p1 = vector2(260 + rand() % (900 - 260), 60);
		balls[i].p4 = vector2(balls[i].p1.x, 200 + (rand() % 4) * 90);
		int off = 2;
		float distance = balls[i].p4.y - balls[i].p1.y;
		balls[i].speed = 1.0 / (distance / off);
	}
 
	//向日葵生产阳光
	int ballMax = sizeof(balls) / sizeof(balls[0]);
	for (int i = 0; i  200)
			{
				map[i][j].timer = 0;
 
				int k = 0;
				for (k = 0; k = ballMax) return;
 
				balls[k].used = true;
				balls[k].p1 = vector2(map[i][j].x, map[i][j].y);
				int w = (100 + rand() % 50) * (rand() % 2 ? 1 : -1);
				balls[k].p4 = vector2(map[i][j].x+w, 
					map[i][j].y+imgZhiwu[XIANG_RI_KUI][0]->getheight()-
					imgSunshineBall[0].getheight());
				balls[k].p2 = vector2(balls[k].p1.x+w*0.3,balls[k].p1.y-100);
				balls[k].p3 = vector2(balls[k].p1.x + w * 0.7, balls[k].p1.y + 100);
				balls[k].status = SUNSHINE_RPODUCT;
				balls[k].speed = 0.05;
				balls[k].t = 0;
			}
		}
	}
 
}
 
 
void updateSunshine()//更新阳光
{
	int ballMax = sizeof(balls) / sizeof(balls[0]);
	for (int i = 0; i status = SUNSHINE_GROUND;
				sun->timer = 0;
			}
			else if (balls[i].status == SUNSHINE_GROUND)
			{
				balls[i].timer++;
				if (balls[i].timer > 100)
				{
					balls[i].used = false;
					balls[i].timer = 0;
				}
			}
			else if (balls[i].status == SUNSHINE_COLLECT)
			{
				struct sunshineBall* sun = &balls[i];
				sun->t+=sun->speed;
				sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
				if (sun->t > 1)
				{
					sun->used = false;
					sunshine += 25;
				}
			}
			else if (balls[i].status == SUNSHINE_RPODUCT)
			{
				struct sunshineBall* sun = &balls[i];
				sun->t += sun->speed;
				sun->pCur = calcBezierPoint(sun->t, sun->p1, sun->p2, sun->p3, sun->p4);
				if (sun->t > 1)
				{
					sun->status = SUNSHINE_GROUND;
					sun->timer = 0;
				}
			}
 
 
			balls[i].frameIndex=(balls[i].frameIndex+1)%29;
			if (balls[i].timer == 0)
			{
				balls[i].y += 2;
			}
			if (balls[i].y >= balls[i].destY)
			{
				//balls[i].used = false;
				balls[i].timer++;
				if (balls[i].timer > 100)
				{
					balls[i].used = false;
				}
			}
		
		}
	}
}
 
 
void creatZM()
{
	static int zmFre = 500;
	static int count = 0;
	count++;
	if (count > zmFre)
	{
		count = 0;
		zmFre = rand() % 200 + 300;
	}
	int i=0;
	int zmMax=sizeof(zms)/sizeof(zms[0]);
	for (i = 0; i  2)
	{
		count = 0;
		//更新僵尸的位置
		for (int i = 0; i  4)
	{
		count2 = 0;
		for (int i = 0; i = 20)
					{
						zms[i].used = false;
					}
				}
				else if (zms[i].eating)
				{
					zms[i].frameIndex= (zms[i].frameIndex + 1) % 21;
				}
				else
				{
					zms[i].frameIndex = (zms[i].frameIndex + 1) % 22;
				}
			}
		}
	}
}
 
 
void shoot()
{
	int lines[3] = { 0 };
	int zmCount = sizeof(zms) / sizeof(zms[0]);
	int bulletMax = sizeof(bullets) / sizeof(bullets[0]);
	int dangerX = WIN_WIDTH - imgZM[0].getwidth();
	for (int i = 0; i  20)
				{
					count = 0;
					int k = 0;
					for (k = 0; k getwidth() - 10;
						bullets[k].y = zwY+5;
					}
				}
			}
		}
	}
}
 
void updataBullets()
{
	int countMax = sizeof(bullets) / sizeof(bullets[0]);
	for (int i = 0; i  WIN_WIDTH)
			{
				bullets[i].used = false;
			}
 
			//子弹的碰撞爆炸
			if (bullets[i].blast)
			{
				bullets[i].frameIndex++;
				if (bullets[i].frameIndex >= 4)
				{
					bullets[i].used = false;
				}
			}
		}
	}
}
 
void checkBullet2Zm()
{
	int bCount = sizeof(bullets) / sizeof(bullets[0]);
	int zCount = sizeof(zms) / sizeof(zms[0]);
	for (int i = 0; i  x1 && x  100)
					{
						map[row][k].deadTime = 0; 
						map[row][k].type = 0;
						zms[i].eating = false;
						zms[i].frameIndex = 0; 
						zms[i].speed = 1;
					}
				}
				else
				{
					map[row][k].catched = true;
					map[row][k].deadTime = 0;
					zms[i].eating = true;
					zms[i].speed = 0;
					zms[i].frameIndex = 0;
 
				}
			}
		}
	}
}
 
void collisionCheck()
{
	checkBullet2Zm();
	checkZm2Zhiwu();
}
void updateGame()
{
	
	for (int i = 0; i  0)
			{
				map[i][j].frameIndex++;
				int Zhiwutype = map[i][j].type - 1;
				int index = map[i][j].frameIndex;
				if (imgZhiwu[Zhiwutype][index] == NULL)
				{
					map[i][j].frameIndex = 0;
				}
			}
		}
	}
	creatSunshine();//创建阳光
	updateSunshine();//更新阳光状态
 
	creatZM();//创建僵尸
	updataZM();//更新僵尸的状态
 
	shoot();//发射豌豆子弹
	updataBullets();//更新豌豆子弹
 
	collisionCheck();//实现豌豆子弹和僵尸的碰撞
}
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);//如果flag=0,那么加载第二个菜单,
		//就是鼠标点击冒险模式后冒险模式的图标会暗淡下来
		
		ExMessage msg;
		if (peekmessage(&msg))//如果有消息响应
		{
			if (msg.message == WM_LBUTTONDOWN&&msg.x>474&&msg.x75&&msg.y
				flag = 1;
				//鼠标松开
				//EndBatchDraw();//渲染一下
			}
			else if (msg.message == WM_LBUTTONUP&&flag)//鼠标抬起
			{
				return;
			}
		}
		EndBatchDraw();
	}
	
}
int main(void)
{
	gameInit();//进入游戏的程序函数
	startUI();//菜单函数
	int timer = 0;
	bool flag = true;
	while (1)
	{
		userClick();
		timer += getDelay();
		if (timer  20)
		{
			flag = true;
			timer = 0;
		}
		if (flag)
		{
			flag = false;
			updateWindow();
			updateGame();
		}
	}
	system("pause");
	return 0;
}

tools.cpp

#include "tools.h"
 
// 载入PNG图并去透明部分
void _putimagePNG(int  picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
	DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
	DWORD* draw = GetImageBuffer();
	DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
	int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
	int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
	int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带
	int graphHeight = getheight();     //获取绘图区的高度,EASYX自带
	int dstX = 0;    //在显存里像素的角标
 
	// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
	for (int iy = 0; iy > 24); //0xAArrggbb;AA是透明度
			int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
			int sg = ((src[srcX] & 0xff00) >> 8);   //G
			int sb = src[srcX] & 0xff;              //B
			if (ix >= 0 && ix = 0 && iy 
				dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
				int dr = ((dst[dstX] & 0xff0000)  16);
				int dg = ((dst[dstX] & 0xff00) >> 8);
				int db = dst[dstX] & 0xff;
				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) 
 
	IMAGE imgTmp, imgTmp2, imgTmp3;
	int winWidth = getwidth();
	int winHeight = getheight();
	if (y getheight() > winHeight) {
		SetWorkingImage(picture);
		getimage(&imgTmp, x, y, picture->getwidth(), winHeight - y);
		SetWorkingImage();
		picture = &imgTmp;
	}
 
	if (x getwidth() + x, picture->getheight());
		SetWorkingImage();
		x = 0;
		picture = &imgTmp2;
	}
 
	if (x > winWidth - picture->getwidth()) {
		SetWorkingImage(picture);
		getimage(&imgTmp3, 0, 0, winWidth - x, picture->getheight());
		SetWorkingImage();
		picture = &imgTmp3;
	}
 
 
	_putimagePNG(x, y, picture);
}
 
int getDelay() {
	static unsigned long long lastTime = 0;
	unsigned long long currentTime = GetTickCount();
	if (lastTime == 0) {
		lastTime = currentTime;
		return 0;
	}
	else {
		int ret = currentTime - lastTime;
		lastTime = currentTime;
		return ret;
	}
}

vector2.cpp

//头文件要求
#include 
 
struct vector2
{
	vector2(int _x = 0, int _y = 0) :x(x), y(y){}
	vector2(int* data):x(data[0]),y(data[1]){}
	long long x, y;
};
 
//加法
vector2 operator +(vector2 x, vector2 y) { 
	return vector2(x.x + y.x, x.y + y.y ); 
}
 
//减法
vector2 operator -(vector2 x, vector2 y) {
	return vector2(x.x - y.x, x.y - y.y);
}
 
// 乘法
vector2 operator *(vector2 x, vector2 y) {
	return vector2(x.x * y.x - x.y * y.y, x.y * y.x + x.x * y.y);
}
 
// 乘法
vector2 operator *(vector2 y, float x) {
	return vector2(x*y.x, x*y.y);
}
 
vector2 operator *(float x, vector2 y) {
	return vector2(x * y.x, x * y.y);
}
 
//叉积
long long cross(vector2 x, vector2 y) { return x.y * y.x - x.x * y.y; }
 
//数量积 点积
long long dot(vector2 x, vector2 y) { return x.x * y.x + x.y * y.y; }
 
//四舍五入除法
long long dv(long long a, long long b) {//注意重名!!! 
	return b  

tools.h

#pragma once
#include 
 
void putimagePNG(int  picture_x, int picture_y, IMAGE* picture);
int getDelay();

vector2.h

#pragma once
 
//头文件要求
#include 
 
struct vector2 {
	vector2(int _x=0, int _y=0) :x(_x), y(_y) {}
	vector2(int* data) :x(data[0]), y(data[1]){}
	long long x, y;
};
 
//加法
vector2 operator +(vector2 x, vector2 y);
 
//减法
vector2 operator -(vector2 x, vector2 y);
 
// 乘法
vector2 operator *(vector2 x, vector2 y);
vector2 operator *(vector2, float);
vector2 operator *(float, vector2);
 
//叉积
long long cross(vector2 x, vector2 y);
 
//数量积 点积
long long dot(vector2 x, vector2 y);
 
//四舍五入除法
long long dv(long long a, long long b);
 
 
//模长平方
long long len(vector2 x);
 
//模长
long long dis(vector2 x);
 
//向量除法
vector2 operator /(vector2 x, vector2 y);
 
//向量膜
vector2 operator %(vector2 x, vector2 y);
 
//向量GCD 
vector2 gcd(vector2 x, vector2 y);
 
vector2 calcBezierPoint(float t, vector2 p0, vector2 p1, vector2 p2, vector2 p3);
效果图C语言、c++实现超好玩植物大战僵尸(完整版附源码),C语言与C++实现超好玩植物大战僵尸游戏(附完整源码) 第2张C语言、c++实现超好玩植物大战僵尸(完整版附源码),C语言与C++实现超好玩植物大战僵尸游戏(附完整源码) 第3张

0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码