大一期末C/C++基于EasyX图形库的期末课设

忙完了大一课设,就赶忙来写一篇博客,希望能对你们有用.

文章目录

  • 忙完了大一课设,就赶忙来写一篇博客,希望能对你们有用.
  • 项目灵感:
  • 游戏玩法:
  • 难点:
    • 1.圣诞老人的睁眼闭眼
    • 2.人物的移动
    • 3.判断袜子与人物相撞
    • 4.鼠标操作
    • 4.游戏音乐加载
    • 5. 我的头文件
    • 6. 透明背景贴图的工具(不用做掩码图啦!!!!!!)
    • 7.其他判断游戏失败成功,袜子的移动,等等杂七杂八的就不一一解释了,直接给你们放我的代码
    • 8.这个是我的图片素材
    • 有什么问题,后续会补充,评论区问.

先来大致了解一下我的游戏

下图是游戏主界面的样子


点击开始游戏
就会显示我的游戏说明,然后按任意键开始游戏

进入游戏的样子

游戏失败,游戏胜利的界面
大一期末C/C++基于EasyX图形库的期末课设_第1张图片

大一期末C/C++基于EasyX图形库的期末课设_第2张图片

项目灵感:

玩法类似于三二一木头人,其实当时想做一个鱿鱼游戏,但是那个游戏3D的更好,所以我不会…,写课设的那一天刚好是圣诞节,就应景用圣诞老人写了这个游戏,素材是真的难找

游戏玩法:

用方向键控制哆啦A梦移动,然后那个圣诞老人的眼睛会一睁一闭,当他看到你移动时就会发射一个圣诞袜来攻击你,你既要躲避还要碰到圣诞老人,然后你就获胜了.

难点:

1.圣诞老人的睁眼闭眼

这个我当时想用多线程去写一个随机函数来控制他睁眼闭眼,但是发现游戏会一闪一闪的,加了双缓冲也没有用,所以最后就用了ps把素材搞成了一列帧序列图,让他自己一张一张切,这个样不会闪,但是就不能随机睁眼闭眼了(就很烦!!!)为了赶时间,也想不出其他办法,与没有大神来告诉我.

2.人物的移动

这个其实也不难,就弄明白EasyX里面函数的原理就自己能写出来了

void KeyCont() {//键盘控制人物移动函数
	int time = 60,v=13;//v就相当于人物的速度
	if (GetAsyncKeyState(VK_UP) & 0X8000) {
		pl.img_x++;
		pl.img_y = 456;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}
		pl.y-=v;//这个就是人物的y坐标减一,就相当于他往上走了一个v
		Sleep(time);//控制切图片的频率,不加的话太快了
	}
	if (GetAsyncKeyState(VK_DOWN) & 0X8000) {
		pl.img_x++;
		pl.img_y = 0;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}
		pl.y+=v;
		Sleep(time);
	}
	if (GetAsyncKeyState(VK_RIGHT) & 0X8000) {
		pl.img_x++;
		pl.img_y = 304;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}

		pl.x+=v;
		Sleep(time);
	}
	if (GetAsyncKeyState(VK_LEFT) & 0X8000) {
		pl.img_x++;
		pl.img_y = 152;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}
		pl.x-=v;
		Sleep(time);
	}
	if(1){
		Man.img_x++;
		if (Man.img_x >= 11) {
			Man.img_x = 0;
		}
		Sleep(time);
		time -= 1;
	}
}

3.判断袜子与人物相撞

这个就用他俩之间的位置关系来判断
用一个简单的if函数

if (pl.x > bull[i].r_x && pl.x<bull[i].r_x + 60
			&& pl.y>bull[i].r_y && pl.y < bull[i].r_y + 60
			|| pl.x + 85>bull[i].r_x && pl.x + 85 < bull[i].r_x + 60
			&&pl.y+150 > bull[i].r_y && pl.y+150 < bull[i].r_y + 60
			|| pl.x + 85 > bull[i].r_x && pl.x + 85 < bull[i].r_x + 60
			&& pl.y + 75 > bull[i].r_y && pl.y + 75 < bull[i].r_y + 60)

4.鼠标操作

这个就封装一个函数来判断鼠标光标的位置,和左键右键,我只写了左键的

void Mouse() {
	ExMessage msg;
	if (peekmessage(&msg, EM_MOUSE))
	{
		if (msg.x >= 515 && msg.x <= 515 + 172 && msg.y >= 700 && msg.y <= 700 + 64) {
			drawImg(515, 680, &开始游戏图标01);
		}
		else {
			drawImg(515, 680, &开始游戏图标);
		}
		switch (msg.message) {
		
		case WM_LBUTTONDOWN:
			if (msg.x >= 1150 && msg.x <= 1300 && msg.y >= 10 && msg.y <= 130) {
				点击bgm();
				mciSendString(_T("stop shengdan01.mp3"), NULL, 0, NULL);
				mciSendString(_T("close shengdan01.mp3"), NULL, 0, NULL);
				closegraph();
			}
			//点击开始游戏后
			if (msg.x >= 515 && msg.x <= 515 + 172 && msg.y >= 700 && msg.y <= 700 + 64) {

4.游戏音乐加载

我是直接把音乐放到了资源文件里面
大一期末C/C++基于EasyX图形库的期末课设_第3张图片
然后就加载:

mciSendString(L"open shengdan01.mp3", 0, 0, 0);

播放:

mciSendString(L"play shengdan01.mp3 repeat", 0, 0, 0);

注意:头文件一定要加上

5. 我的头文件

我用了点c++的类,就顺便加了c++的头文件

#include
//#include
using namespace std;
#include//包含图形库头文件
#include
#pragma comment(lib,"winmm.lib")
#include
#include"tool.h"
#include
#include
#include

6. 透明背景贴图的工具(不用做掩码图啦!!!)

这里我解释一下我头文件里面的"tool.h"
这是一个透明背景贴图工具,就不用自己再做掩码图,怪麻烦的,直接把这个工具加到自己的头文件里面,然后就用这个函数:

drawImg(1200, 10, &退出图标);
drawImg(pl.x, pl.y,100,150,&renwu,pl.img_x*100,pl.img_y);

用法和easyx里面的putimage一模一样

这个是我的工具代码:
把它直接复制粘贴到你的头文件里面;
大一期末C/C++基于EasyX图形库的期末课设_第4张图片

#pragma once
#include
void drawImg(int x, int y, IMAGE* src)
{
	// 变量初始化
	DWORD* pwin = GetImageBuffer();			//窗口缓冲区指针
	DWORD* psrc = GetImageBuffer(src);		//图片缓冲区指针
	int win_w = getwidth();				//窗口宽高
	int win_h = getheight();
	int src_w = src->getwidth();				//图片宽高
	int src_h = src->getheight();

	// 计算贴图的实际长宽
	int real_w = (x + src_w > win_w) ? win_w - x : src_w;			// 处理超出右边界
	int real_h = (y + src_h > win_h) ? win_h - y : src_h;			// 处理超出下边界
	if (x < 0) { psrc += -x;			real_w -= -x;	x = 0; }	// 处理超出左边界
	if (y < 0) { psrc += (src_w * -y);	real_h -= -y;	y = 0; }	// 处理超出上边界


	// 修正贴图起始位置
	pwin += (win_w * y + x);

	// 实现透明贴图
	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix] >> 24);//计算透明通道的值[0,256) 0为完全透明 255为完全不透明
			if (a != 0)
			{
				pwin[ix] = psrc[ix];
			}
		}
		//换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}

void drawImg(int x, int y, int dstW, int dstH, IMAGE* src, int srcX, int srcY)
{
	// 变量初始化
	DWORD* pwin = GetImageBuffer();			//窗口缓冲区指针
	DWORD* psrc = GetImageBuffer(src);		//图片缓冲区指针
	int win_w = getwidth();				//窗口宽高
	int win_h = getheight();
	int src_w = src->getwidth();				//图片宽高
	int src_h = src->getheight();


	// 计算贴图的实际长宽
	int real_w = (x + dstW > win_w) ? win_w - x : dstW;			// 处理超出右边界
	int real_h = (y + dstH > win_h) ? win_h - y : dstH;			// 处理超出下边界
	if (x < 0) { psrc += -x;			real_w -= -x;	x = 0; }	// 处理超出左边界
	if (y < 0) { psrc += (dstW * -y);	real_h -= -y;	y = 0; }	// 处理超出上边界

	//printf("realw,h(%d,%d)\n", real_w, real_h);
	// 修正贴图起始位置
	pwin += (win_w * y + x);

	// 实现透明贴图
	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix + srcX + srcY * src_w] >> 24);//计算透明通道的值[0,256) 0为完全透明 255为完全不透明
			if (a > 100)
			{
				pwin[ix] = psrc[ix + srcX + srcY * src_w];
			}
		}
		//换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}

7.其他判断游戏失败成功,袜子的移动,等等杂七杂八的就不一一解释了,直接给你们放我的代码

第一次写项目,那些函数的位置,代码就显得十分凌乱,看的可能会吃力点:

#include"swap.h"
#include"tool.h"
IMAGE sleep02, sleep01, zhujiemian, 退出图标01, 退出图标02,退出图标, 开始游戏图标,开始游戏图标01,close01;
IMAGE 游戏背景, imgOldman, renwu2, youyu01, youyu02, 娃娃[2], renwu, socks,fail,success;//定义图片变量
IMAGE restar, close,gametip;
enum My {
	bull_num = 1500,
};
void Bgm() {
	mciSendString(L"open shengdan01.mp3", 0, 0, 0);
	mciSendString(L"play shengdan01.mp3 repeat", 0, 0, 0);
}
void 点击bgm() {
	mciSendString(L"open dianjibgm.mp3", 0, 0, 0);
	mciSendString(L"play dianjibgm.mp3", 0, 0, 0);
}
void Gamebgm() {
	mciSendString(L"open youxibgm.mp3", 0, 0, 0);
	mciSendString(L"play youxibgm.mp3 repeat", 0, 0, 0);
}
void Gamesuccessbgm() {
	mciSendString(L"open gamesuccess.mp3", 0, 0, 0);
	mciSendString(L"play gamesuccess.mp3", 0, 0, 0);
}
void Gamefailbgm() {
	mciSendString(L"open gamefail.mp3", 0, 0, 0);
	mciSendString(L"play gamefail.mp3", 0, 0, 0);
}
void shotbgm() {
	mciSendString(L"open shotbgm.mp3", 0, 0, 0);
	mciSendString(L"play shotbgm.mp3", 0, 0, 0);
}
//封装定时器
bool timesleep() {
	int ms = rand() %  + 1;
	static DWORD t1, t2;
	if (t2 - t1 > ms) {
		t1 = t2;
		return true;
	}
	t2 = clock();
	return false;
}
void init_Zhujiemian() {
	initgraph(1300, 781);
	loadimage(&zhujiemian, L"tupian\\主界面背景.png");
	loadimage(&sleep02, L"tupian\\biaoti01.png");
	loadimage(&sleep01, L"tupian\\biaoti.png");
	loadimage(&退出图标01, L"tupian\\退出图标01.png");
	loadimage(&退出图标02, L"tupian\\退出图标02.png");
	loadimage(&开始游戏图标, L"tupian\\开始游戏图标.png");
	loadimage(&success, L"tupian\\success.png");
	loadimage(&fail, L"tupian\\fail.png");
	loadimage(&restar, L"tupian\\restar.png");
	loadimage(&close, L"tupian\\close.png");
	loadimage(&imgOldman, L"tupian\\oldman01.png");
	loadimage(&游戏背景, L"tupian\\游戏背景.png");
	loadimage(&renwu, L"tupian\\renwu111.png");
	loadimage(&socks, L"tupian\\socks.png");
	loadimage(&退出图标, L"tupian\\退出图标.png");
	loadimage(&开始游戏图标01, L"tupian\\开始游戏图标01.png");
	loadimage(&close01, L"tupian\\close01.png");
	loadimage(&gametip, L"tupian\\gametip.png");
}
struct Oldman {
	int man_x = 980, man_y = 220;
	int img_x = 4, img_y = 0;
	int manimg = 0;
}Man;
struct Role//定义人物坐标变量
{
	//人物坐标
	int x = 0, y = 300;
	int img_x = 0;
	int img_y = 0;
}pl;
//游戏过程中的鼠标操作
void Mousegame() {
	ExMessage msg;
	if (peekmessage(&msg, EM_MOUSE))
	{
		switch (msg.message) {
		case WM_LBUTTONDOWN:
			if (msg.x >= 1100 && msg.x <= 1300 && msg.y >= 10 && msg.y <= 200) {
				点击bgm();
				mciSendString(_T("stop youxibgm.mp3"), NULL, 0, NULL);
				mciSendString(_T("close youxibgm.mp3"), NULL, 0, NULL);
				closegraph();
			}
		}
	}
}
//定义一个子弹类
class Bullet {
public:
	int r_x = 1030;
	int r_y = 360;
	bool live = false;
	//初始化袜子图像
	void drawfirstsock() {
		drawImg(bull[0].r_x, bull[0].r_y, &socks);
	}
	void creatbull() {//创建一个袜子
		for (int i = 0; i < bull_num; i++) {
			if (!bull[i].live) {
				bull[i].r_x = 1030;
				bull[i].r_y = pl.y + 60;
				bull[i].live = true;
				shotbgm();
				break;
			}
		}
	}
	void drawsock() {
		for (int i = 0; i < bull_num; i++) {
			if (bull[i].live) {
				drawImg(bull[i].r_x, bull[i].r_y, &socks);
			}
		}
	}
	void socksfight() {
		//获取键盘的信号;
		if (GetAsyncKeyState(VK_LEFT) || GetAsyncKeyState(VK_UP) || GetAsyncKeyState(VK_DOWN) || GetAsyncKeyState(VK_RIGHT)) {	
			shotbgm();
			creatbull();		
		}

	}
	//袜子移动
	void socksmove() {
		for (int i = 0; i < bull_num; i++) {
			if (bull[i].live) {
				bull[i].r_x -= 4;
			}
		}
	}
}bull[bull_num];
//游戏结束的鼠标操作
void gameovermouse2() {
	ExMessage msg;
	if (peekmessage(&msg, EM_MOUSE))
	{
		if (msg.x >= 1150 && msg.x <= 1300 && msg.y >= 0 && msg.y <= 120) {
			drawImg(650, 580, &close01);
		}
		else {
			drawImg(650, 580, &close);
		}
		switch (msg.message) {
		case WM_LBUTTONDOWN:
			if (msg.x >= 650 && msg.x <= 650 + 187 && msg.y >= 580 && msg.y <= 580 + 83) {
				点击bgm();
				closegraph();
			}
			if (msg.x >= 450 && msg.x <= 450 + 150 && msg.y >= 580 && msg.y <= 580 +110 ) {
				点击bgm();
				closegraph();
			}
		}
	}
}
//游戏结束判定
void gameover() {
	//当oldman睁眼
	
	if (Man.img_x==0||Man.img_x==1) {
		//创建一个袜子
		bull[bull_num].socksfight();
	}
	//判断是否到达终点
	if (pl.x + 90 >= 980 && pl.x + 90 <= 1300 && pl.y >= 230 && pl.y <= 490 || pl.x + 90 >= 970 && pl.x + 90 <= 1300 && pl.y + 142 >= 250 && pl.y + 142 <= 490) {
		mciSendString(_T("stop youxibgm.mp3"), NULL, 0, NULL);
		mciSendString(_T("close youxibgm.mp3"), NULL, 0, NULL);
		cleardevice();
		Gamesuccessbgm();
		
		drawImg(350, 240, &success);
		drawImg(450, 580, &restar);
		drawImg(650, 580, &close);
		while (1) {
			gameovermouse2();
		}
		return;
	}
	//判断袜子是否与人物相撞
	for (int i = 0; i < bull_num; i++) {
		if (pl.x > bull[i].r_x && pl.x<bull[i].r_x + 60
			&& pl.y>bull[i].r_y && pl.y < bull[i].r_y + 60
			|| pl.x + 85>bull[i].r_x && pl.x + 85 < bull[i].r_x + 60
			&&pl.y+150 > bull[i].r_y && pl.y+150 < bull[i].r_y + 60
			|| pl.x + 85 > bull[i].r_x && pl.x + 85 < bull[i].r_x + 60
			&& pl.y + 75 > bull[i].r_y && pl.y + 75 < bull[i].r_y + 60) {
			cleardevice();
			mciSendString(_T("stop youxibgm.mp3"), NULL, 0, NULL);
			mciSendString(_T("close youxibgm.mp3"), NULL, 0, NULL);
			Gamefailbgm();
			drawImg(350, 240, &fail);
			drawImg(450, 580, &restar);
			drawImg(650, 580, &close);
			while (1) {
				gameovermouse2();
			}
		}
	}
}
void draw() {
	putimage(0, 0, &zhujiemian);
	putimage(0, 0, &sleep02, SRCAND);
	putimage(0, 0, &sleep01, SRCPAINT);
	putimage(1200, 10, &退出图标02, SRCAND);
	putimage(1200, 10, &退出图标01, SRCPAINT);
	drawImg(515, 680, &开始游戏图标);
	
}
void KeyCont() {//键盘控制人物移动函数
	int time = 60,v=13;
	if (GetAsyncKeyState(VK_UP) & 0X8000) {
		pl.img_x++;
		pl.img_y = 456;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}
		pl.y-=v;
		Sleep(time);
	}
	if (GetAsyncKeyState(VK_DOWN) & 0X8000) {
		pl.img_x++;
		pl.img_y = 0;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}
		pl.y+=v;
		Sleep(time);
	}
	if (GetAsyncKeyState(VK_RIGHT) & 0X8000) {
		pl.img_x++;
		pl.img_y = 304;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}

		pl.x+=v;
		Sleep(time);
	}
	if (GetAsyncKeyState(VK_LEFT) & 0X8000) {
		pl.img_x++;
		pl.img_y = 152;
		if (pl.img_x >= 4) {
			pl.img_x = 0;
		}
		pl.x-=v;
		Sleep(time);
	}
	if(1){
		Man.img_x++;
		if (Man.img_x >= 11) {
			Man.img_x = 0;
		}
		Sleep(time);
		time -= 1;
	}
}
void Mouse() {
	ExMessage msg;
	if (peekmessage(&msg, EM_MOUSE))
	{
		if (msg.x >= 515 && msg.x <= 515 + 172 && msg.y >= 700 && msg.y <= 700 + 64) {
			drawImg(515, 680, &开始游戏图标01);
		}
		else {
			drawImg(515, 680, &开始游戏图标);
		}
		switch (msg.message) {
		
		case WM_LBUTTONDOWN:
			if (msg.x >= 1150 && msg.x <= 1300 && msg.y >= 10 && msg.y <= 130) {
				点击bgm();
				mciSendString(_T("stop shengdan01.mp3"), NULL, 0, NULL);
				mciSendString(_T("close shengdan01.mp3"), NULL, 0, NULL);
				closegraph();
			}
			//点击开始游戏后
			if (msg.x >= 515 && msg.x <= 515 + 172 && msg.y >= 700 && msg.y <= 700 + 64) {
				点击bgm();
				drawImg(150,90 , &gametip);
				_getch();//实现按任意键开始游戏
				mciSendString(_T("stop shengdan01.mp3"), NULL, 0, NULL);
				mciSendString(_T("close shengdan01.mp3"), NULL, 0, NULL);
				cleardevice();
				//Gamebgm();
				while (1) {
					KeyCont();
					BeginBatchDraw();
					putimage(0, 0, &游戏背景);
					drawImg(1200, 10, &退出图标);
					drawImg(pl.x, pl.y,100,150,&renwu,pl.img_x*100,pl.img_y);
					drawImg(980, 220, 400, 280, &imgOldman, Man.img_x * 400+40, Man.img_y);
					bull[bull_num].socksmove();
					bull[bull_num].drawsock();
					EndBatchDraw();
					gameover();
					Mousegame();
				}
			}
		}
	}
}
int main() {
	init_Zhujiemian();
	draw();
	//Bgm();
	while (1) {
		Mouse();
	};
	return 0;
}

8.这个是我的图片素材


大一期末C/C++基于EasyX图形库的期末课设_第5张图片
在这里插入图片描述

有什么问题,后续会补充,评论区问.

你可能感兴趣的