C语言实现植物大战僵尸(完整版)

实现这个游戏需要Easy_X

这个在我前面一篇C++之番外篇爱心代码有程序教你怎么下载,大家可自行查看

然后就是需要植物大战僵尸的素材和音乐,需要的可以在评论区

首先是main.cpp

//开发日志
//1导入素材
//2实现最开始的游戏场景
//3实现游戏顶部的工具栏
//4实现工具栏里面的游戏卡牌
#define WIN_WIDTH 900
#define WIN_HEIGHT 600
//定义植物类型
enum { WAN_DOU, XIANG_RI_KUI, ZHI_WU_COUNT };
#include<stdio.h>
#include<graphics.h>//easyx图形库的头文件
#include"tools.h"
#include"vector2.h"//向量引用
#include<time.h>
#include<math.h>
#include<mmsystem.h>//导入音乐收集阳光的时候
//导入一个库
#include<Windows.h>
#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 < ZHI_WU_COUNT; i++)
	{
		//生成植物卡牌的文件名
		sprintf_s(name,sizeof(name),"res/Cards/card_%d.png",i+1);//加植物向枚举类型中加
		loadimage(&imgCards[i], name);

		for (int j = 0; j < 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;
			}
		}
	}
	curZhiwu = 0;
	sunshine = 50;

	memset(balls, 0, sizeof(balls));
	for (int i = 0; i < 29; i++)
	{
		sprintf_s(name, sizeof(name), "res/sunshine/%d.png",i+1);
		loadimage(&imgSunshineBall[i], name);
	}

	//配置随机种子,让阳光真正的随机
	srand((unsigned)time(NULL));

	//创建游戏的图形窗口
	initgraph(WIN_WIDTH, WIN_HEIGHT,1);

	//设置字体
	LOGFONT f;
	gettextstyle(&f);
	f.lfHeight = 30;
	f.lfWeight = 15;
	strcpy(f.lfFaceName, "Segoe UI Black");
	//抗锯齿
	f.lfQuality = ANTIALIASED_QUALITY;
	settextstyle(&f);
	setbkmode(TRANSPARENT);
	setcolor(BLACK);

	//初始化僵尸数据
	memset(zms, 0, sizeof(zms));
	int i = 0;
	for (i = 0; i < 22; i++)
	{
		sprintf_s(name,sizeof(name),"res/zm/%d.png",i+1);
		loadimage(&imgZM[i],name);
	}

	loadimage(&imgBulletNormal,"res/bullets/bullet_normal.png");
	memset(bullets,0,sizeof(bullets));

	//初始化豌豆子弹的帧图片数组
	loadimage(&imgBallBlast[3],"res/bullets/bullet_blast.png");
	for (int i = 0; i < 3; i++)
	{
		float k = (i + 1) * 0.2;
		loadimage(&imgBallBlast[i],"res/bullets/bullet_blast.png", 
			imgBallBlast[3].getwidth()*k, 
			imgBallBlast[3].getheight()*k,true);
	}

	for (int i = 0; i < 20; i++)
	{
		sprintf_s(name,sizeof(name),"res/zm.dead/%d.png",i+1);
		loadimage(&imgZMDead[i],name);
	}

	for (int i = 0; i < 21; i++)
	{
		sprintf_s(name,"res/zm_eat/%d.png",i+1);
		loadimage(&imgZMEat[i],name);
	}

}


void drawZM()
{
	int zmCount = sizeof(zms) / sizeof(zms[0]);
	for (int i = 0; i < zmCount; i++)
	{
		if (zms[i].used)
		{
			//IMAGE* img = &imgZM[zms[i].frameIndex];
			//IMAGE* img = (zms[i].dead) ? imgZMDead : imgZM;
			IMAGE* img = NULL;
			if (zms[i].dead)  img = imgZMDead;
			else if (zms[i].dead) img = imgZMEat;
			else img = imgZM;
			img += zms[i].frameIndex;


			putimagePNG(
				zms[i].x,
				zms[i].y-img->getheight(),
				img);
		}
	}
}
void drawSunshines()
{
	int ballMax = sizeof(balls) / sizeof(balls[0]);
	for (int i = 0; i < ballMax; i++)
	{
		if (balls[i].used || balls[i].xoff)
		{
			IMAGE* img = &imgSunshineBall[balls[i].frameIndex];
			//putimagePNG(balls[i].x, balls[i].y, img);
			putimagePNG(balls[i].pCur.x, balls[i].pCur.y, img);

		}
	}
}

void updateWindow()
{
	BeginBatchDraw();//开始缓冲
	putimage(0, 0, &imgBg);
	//putimage(250, 0, &imgBar);
	putimagePNG(250, 0, &imgBar);
	for (int i = 0; i < ZHI_WU_COUNT; i++)
	{
		int x = 338 + i * 65;
		int y = 6;
		putimage(x, y, &imgCards[i]);
	}
	

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			if (map[i][j].type > 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 < bulletMax; i++)
	{
		if (bullets[i].used)
		{
			if (bullets[i].blast)
			{
				IMAGE* img = &imgBallBlast[bullets[i].frameIndex];
				putimagePNG(bullets[i].x, bullets[i].y, img);
			}
			else
			{
				putimagePNG(bullets[i].x, bullets[i].y, &imgBulletNormal);

			}
		}
	}



	EndBatchDraw();//结束双缓冲
}

void collectSunshine(ExMessage* msg)
{
	int count = sizeof(balls) / sizeof(balls[0]);
	int w = imgSunshineBall[0].getwidth();
	int h = imgSunshineBall[0].getheight();
	for (int i = 0; i < count; i++)
	{
		if (balls[i].used)
		{
			/*int x = balls[i].x;
			int y = balls[i].y;*/
			int x = balls[i].pCur.x;
			int y = balls[i].pCur.y;

			if (msg->x > x && msg->x<x + w && msg->y>y && msg->y < y + h)
			{
			    balls[i].used = false;
				balls[i].status = SUNSHINE_COLLECT;
			    sunshine += 25;
			    mciSendString("play res/sunshine.mp3",0,0,0);//加载音乐文件

				//设置阳光球的偏移量
				balls[i].p1 = balls[i].pCur;
				balls[i].p4 = vector2(262, 0);
				balls[i].t = 0;
				float distance = dis(balls[i].p1 - balls[i].p4);
				float off = 8.0;
				balls[i].speed = 1.0/(distance/off);
			}

		}
	}
}


void userClick()
{
	ExMessage msg;//参数是消息类型
	static int status = 0;
	//如果消息有值则保存在peekmessage函数中,即为真
	if (peekmessage(&msg))
	{
		if (msg.message == WM_LBUTTONDOWN)//WM_LBUTTONDOWN左键按下去的意思
		{
			if (msg.x > 338 && msg.x < 338 + 65*ZHI_WU_COUNT && msg.y < 96)//定义坐标判断点击的是否为植物
			{
				int index = (msg.x - 338) / 65;
				status = 1;
				curZhiwu = index + 1;
			}
			else
			{
				collectSunshine(&msg);
			}
		}
		else if (msg.message == WM_MOUSEMOVE&&status==1)//WM_MOUSEMOVE鼠标移动
		{
			//记录当前位置
			curX = msg.x;
			curY = msg.y;
		}
		//鼠标抬动植物就种下去
		else if (msg.message == WM_LBUTTONUP)
		{
			if (msg.x > 256 && msg.y > 179 && msg.y < 489)
			{
				int row = (msg.y - 179) / 102;
				int col = (msg.x - 256) / 81;

				if (map[row][col].type == 0)
				{
					map[row][col].type = curZhiwu;
					map[row][col].frameIndex = 0;

					//int x = 256 + j * 81;
				    //int y = 179 + i*102+14;
					map[row][col].x = 256 + col * 81;
					map[row][col].y = 179 + row * 102+14;
				}
			}
				curZhiwu = 0;
				status = 0;
			
		}
	}
}


void creatSunshine()
{
	static int count = 0;
	static int fre = 400;
	count++;
	if (count >= fre )
	{
		fre = 200 + rand() % 200;
		count = 0;//满了计数器清0
		//从阳光池中去一个可以使用的
		int ballMax = sizeof(balls) / sizeof(balls[0]);
		int i = 0;
		for (i = 0; i < ballMax && balls[i].used; i++);
		if (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 < 3; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			if (map[i][j].type == XIANG_RI_KUI + 1)
			{
				map[i][j].timer++;
			}
			if (map[i][j].timer > 200)
			{
				map[i][j].timer = 0;

				int k = 0;
				for (k = 0; k < ballMax && balls[k].used; k++);
				if (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 < ballMax; i++)
	{
		if (balls[i].used)
		{


			balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
			if (balls[i].status = SUNSHINE_DOWN)
			{
				struct sunshineBall* sun = &balls[i];
				sun->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 < zmMax && zms[i].used; i++);
	if (i < zmMax)
	{
		memset(&zms[i],0,sizeof(zms[i]));
		zms[i].used = true;
		zms[i].x = WIN_WIDTH;
		zms[i].row = rand() % 3;
		zms[i].y = 172 + (1 + zms[i].row) * 100;
		zms[i].speed = 1;
		zms[i].blood = 100;
		zms[i].dead = false;
	}
}


void updataZM()
{
	int zmMax = sizeof(zms) / sizeof(zms[0]);

	static int count = 0;
	count++;
	if (count > 2)
	{
		count = 0;
		//更新僵尸的位置
		for (int i = 0; i < zmMax; i++)
		{

			if (zms[i].used)
			{
				zms[i].x -= zms[i].speed;
				if (zms[i].x < 170)
				{
					printf("GAME OVER\n");
					MessageBox(NULL, "over", "over", 0);//待优化
					exit(0);
				}
			}
		}
	}
	

	static int count2 = 0;
	count2++;
	if (count2 > 4)
	{
		count2 = 0;
		for (int i = 0; i < zmMax; i++)
		{
			if (zms[i].used)
			{
				if (zms[i].dead)
				{
					zms[i].frameIndex++;
					if (zms[i].frameIndex >= 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 < zmCount; i++)
	{
		if (zms[i].used && zms[i].x < dangerX)
		{
			lines[zms[i].row] = 1;
		}
	}
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			if (map[i][j].type == WAN_DOU + 1&&lines[i])
			{
				static int count = 0;
				count++;
				if (count > 20)
				{
					count = 0;
					int k = 0;
					for (k = 0; k < bulletMax && bullets[k].used; k++);
					if (k < bulletMax)
					{
						bullets[k].used = true;
						bullets[k].row = i;
						bullets[k].speed = 6;

						bullets[k].blast = false;
						bullets[k].frameIndex = 0;

						int zwX = 256 + j * 81;
						int zwY = 179 + i * 102 + 14;
						bullets[k].x = zwX + imgZhiwu[map[i][j].type - 1][0]->getwidth() - 10;
						bullets[k].y = zwY+5;
					}
				}
			}
		}
	}
}

void updataBullets()
{
	int countMax = sizeof(bullets) / sizeof(bullets[0]);
	for (int i = 0; i < countMax; i++)
	{
		if (bullets[i].used)
		{
			bullets[i].x += bullets[i].speed;
			if (bullets[i].x > 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 < bCount; i++)
	{
		if (bullets[i].used == false || bullets[i].blast)
		{
			continue;
		}
		for (int k = 0; k < zCount; k++)
		{
			//if (zms[i].used == false) continue;
			if (zms[k].used == false)  continue;
			int x1 = zms[k].x + 80;
			int x2 = zms[k].x + 110;
			int x = bullets[i].x;
			if (zms[k].dead == false && bullets[i].row == zms[k].row && x > x1 && x < x2)
			{
				zms[k].blood -= 20;
				bullets[i].blast = true;
				bullets[i].speed = 0;

				if (zms[k].blood <= 0)
				{
					zms[k].dead = true;
					zms[k].speed = 0;
					zms[k].frameIndex = 0;
				}


				break;
			}
		}
	}
}

void checkZm2Zhiwu()
{

	int zCount = sizeof(zms) / sizeof(zms[0]);
	for (int i = 0; i < zCount; i++)
	{
		if (zms[i].dead) continue;
		int row = zms[i].row;
		for (int k = 0; k < 9; k++)
		{
			if (map[row][k].type == 0)
			{
				continue;
			}
			int ZhiWuX = 256 + k * 81;
			int x1 = ZhiWuX + 10;
			int x2 = ZhiWuX + 60;
			int x3 = zms[i].x + 80;
			if (x3 > x1 && x3 < x2)
			{
				if (map[row][k].catched)
				{
					map[row][k].deadTime++;
					if (map[row][k].deadTime > 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 < 3; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			if (map[i][j].type > 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.x<474+300
				&&msg.y>75&&msg.y<75+140)//按下鼠标
				//判断按下的位置对不对
			{
				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 < picture_height; iy++)
	{
		for (int ix = 0; ix < picture_width; ix++)
		{
			int srcX = ix + iy * picture_width; //在显存里像素的角标
			int sa = ((src[srcX] & 0xff000000) >> 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 <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
			{
				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) << 16)
					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)
					| (sb * sa / 255 + db * (255 - sa) / 255);
			}
		}
	}
}

// 适用于 y <0 以及x<0的任何情况
void putimagePNG(int x, int y, IMAGE* picture) {

	IMAGE imgTmp, imgTmp2, imgTmp3;
	int winWidth = getwidth();
	int winHeight = getheight();
	if (y < 0) {
		SetWorkingImage(picture);
		getimage(&imgTmp, 0, -y,
			picture->getwidth(), picture->getheight() + y);
		SetWorkingImage();
		y = 0;
		picture = &imgTmp;
	}
	else if (y >= getheight() || x >= getwidth()) {
		return;
	}
	else if (y + picture->getheight() > winHeight) {
		SetWorkingImage(picture);
		getimage(&imgTmp, x, y, picture->getwidth(), winHeight - y);
		SetWorkingImage();
		picture = &imgTmp;
	}

	if (x < 0) {
		SetWorkingImage(picture);
		getimage(&imgTmp2, -x, 0, picture->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;
	}
}

然后最后就是头文件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 < picture_height; iy++)
	{
		for (int ix = 0; ix < picture_width; ix++)
		{
			int srcX = ix + iy * picture_width; //在显存里像素的角标
			int sa = ((src[srcX] & 0xff000000) >> 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 <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
			{
				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) << 16)
					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)
					| (sb * sa / 255 + db * (255 - sa) / 255);
			}
		}
	}
}

// 适用于 y <0 以及x<0的任何情况
void putimagePNG(int x, int y, IMAGE* picture) {

	IMAGE imgTmp, imgTmp2, imgTmp3;
	int winWidth = getwidth();
	int winHeight = getheight();
	if (y < 0) {
		SetWorkingImage(picture);
		getimage(&imgTmp, 0, -y,
			picture->getwidth(), picture->getheight() + y);
		SetWorkingImage();
		y = 0;
		picture = &imgTmp;
	}
	else if (y >= getheight() || x >= getwidth()) {
		return;
	}
	else if (y + picture->getheight() > winHeight) {
		SetWorkingImage(picture);
		getimage(&imgTmp, x, y, picture->getwidth(), winHeight - y);
		SetWorkingImage();
		picture = &imgTmp;
	}

	if (x < 0) {
		SetWorkingImage(picture);
		getimage(&imgTmp2, -x, 0, picture->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 <cmath>

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 < 0 ? dv(-a, -b)
		: (a < 0 ? -dv(-a, b)
			: (a + b / 2) / b);
}

//模长平方
long long len(vector2 x) { return x.x * x.x + x.y * x.y; }

//模长
long long dis(vector2 x) { return sqrt(x.x * x.x + x.y * x.y); }

//向量除法
vector2 operator /(vector2 x, vector2 y) {
	long long l = len(y);
	return vector2(dv(dot(x, y), l), dv(cross(x, y), l));
}

//向量膜
vector2 operator %(vector2 x, vector2 y) { return x - ((x / y) * y); }

//向量GCD 
vector2 gcd(vector2 x, vector2 y) { return len(y) ? gcd(y, x % y) : x; }


vector2 calcBezierPoint(float t, vector2 p0, vector2 p1, vector2 p2, vector2 p3) {
	float u = 1 - t;
	float tt = t * t;
	float uu = u * u;
	float uuu = uu * u;
	float ttt = tt * t;

	vector2 p = uuu * p0;
	p = p + 3 * uu * t * p1;
	p = p + 3 * u * tt * p2;
	p = p + ttt * p3;

	return p;
}

最后头文件tools.h

#pragma once
#include <graphics.h>

void putimagePNG(int  picture_x, int picture_y, IMAGE* picture);
int getDelay();

vector2.h

#pragma once

//头文件要求
#include <cmath>

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);

这里给大家演示一下画面

相关推荐
binishuaio5 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE7 分钟前
【Java SE】StringBuffer
java·开发语言
就是有点傻11 分钟前
WPF中的依赖属性
开发语言·wpf
洋24020 分钟前
C语言常用标准库函数
c语言·开发语言
进击的六角龙21 分钟前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel
wrx繁星点点22 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
王哈哈^_^25 分钟前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城27 分钟前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
NoneCoder40 分钟前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发
苏三有春40 分钟前
PyQt5实战——UTF-8编码器功能的实现(六)
开发语言·qt