DEV-C++ ege.h库 绘图教程——综合实践(一)

一、First of ALL

学习完了EGE库的所有函数后,今天我们就来综合实践一下。

今天我们将写一个数字华容道来简单练一练手。

准备好了吗,让我们开始。

DEV-C++ ege.h库 绘图教程合集

二、材料准备

1.音乐

我们可以为我们的游戏增加音乐,这里我找了一首MP3来做背景音乐。

2.按键侦测

虽然ege库内有自带的按键侦测函数,但我还是习惯使用windows.h库里的按键侦测函数。

#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000)? 1 : 0)

 例如,KEY_DOWN(VK_RETURN)会侦测在这一时刻,你是否按下了回车键。

三、代码实现

1.main函数

那么首先,我们得让画面看起来是这样的

首先就是initgraph和setbkcolor,这一部分很简单,不用多说。

	initgraph(640, 480);
	setcaption(L"数字华容道");         //设置标题
	setbkcolor(WHITE);                //背景颜色
	MUSIC mus;                        //音乐初始化
	mus.OpenFile(L"Piano.mp3");       //打开音乐
	mus.Play();                       //播放音乐

 然后就是初始化地图,绘制窗口。里面有些函数我们等一下会讲。

	init_map();                        //这些函数等一下会讲
	draw_map();
	draw_number();
	setfont(20, 10, L"Lucida Console");//字体
	outtext(L"按N静音");               //提示信息
	outtextxy(0, 20, L"按M重置");
	outtextxy(0, 40, L"按B退出");

然后就开始游戏循环了。

	for (;;) {
		move_map();                       //移动数字后
		draw_number();                    //重新绘制地图(数字)
		if (KEY_DOWN('N')) {
			if (mus_state == 0) {
				mus_state = 1;            //muw_state:记录音乐在播放还是停止
				mus.Pause();              //如果在播放时按下N,停止。
			} else {
				mus_state = 0;            //下同
				mus.Play();
			}
		}
		if (KEY_DOWN('M')) {              //M代表重开,再更新一遍地图
			init_map();
			draw_map();
			draw_number();
		}
		if (KEY_DOWN('B')) {              //B则是结束
			return 0;
		}
		if (is_win()) {                   //如果胜利了就退出
			break;
		}
		if (mus.GetLength() == mus.GetPosition()) {
			mus.Close();
			mus.OpenFile(L"Piano.mp3");
			mus.Play();
		}                                 //如果音乐播完了再播一次
		Sleep(100);                       //延迟
	}

最后如果胜利了,输出提示信息,结束。

	win();
	closegraph();
	return 0;

main函数:

int main() {
	initgraph(640, 480);
	setcaption(L"数字华容道");
	setbkcolor(WHITE);
	MUSIC mus;
	mus.OpenFile(L"Piano.mp3");
	mus.Play();
	init_map();
	draw_map();
	draw_number();
	setfont(20, 10, L"Lucida Console");
	outtext(L"按N静音");
	outtextxy(0, 20, L"按M重置");
	outtextxy(0, 40, L"按B退出");
	for (;;) {
		move_map();
		draw_number();
		if (KEY_DOWN('N')) {
			if (mus_state == 0) {
				mus_state = 1;
				mus.Pause();
			} else {
				mus_state = 0;
				mus.Play();
			}
		}
		if (KEY_DOWN('M')) {
			init_map();
			draw_map();
			draw_number();
		}
		if (KEY_DOWN('B')) {
			return 0;
		}
		if (is_win()) {
			break;
		}
		if (mus.GetLength() == mus.GetPosition()) {
			mus.Close();
			mus.OpenFile(L"Piano.mp3");
			mus.Play();
		}
		Sleep(100);
	}
	win();
	closegraph();
	return 0;
}

2.position结构体

这个结构体将记录每个数字的位置。

typedef struct {
	int x;
	int y;
} position;												//不是坐标轴的x,y,而是行和列

3.initmap函数

这个函数将初始化地图(也就是3×3的矩阵),具体操作见下。

void init_map() {
	bool b[9] = {0};            //记录每个数字是否已被选中过
	randomize();                //初始化随机数
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			do {                
				MAP[i][j] = random(9);            //取随机数
			} while (b[MAP[i][j]] != 0);          //如果这个数已经在矩阵里就再取一遍
			b[MAP[i][j]] = 1;                     //标记这个数取过了
		}                                         //这样就保证里面的数是012345678而不会有
                                                  //两个2这样的事情发生。
	}
	if (is_win()) init_map();                     //如果出来的矩阵已经是排列好的,就再init一遍
}

4.draw_map函数

init完之后就应该绘制框框来填数字了。

void draw_map() {
	int x[9] = {200, 280, 360, 200, 280, 360, 200, 280, 360};//记录每个框框的x
	int y[9] = {120, 120, 120, 200, 200, 200, 280, 280, 280};//记录每个框框的y
	setcolor(BLACK);        //设置颜色
	for (int i = 0; i < 9; i++) {
		rectangle(x[i], y[i], x[i] + 80, y[i] + 80);    //绘制框框,长宽各为80
	}
}

这样,我们就得到了3×3的一个矩形了。

5.draw_number函数

绘制好框框后,就该往里面填数字了。

void draw_number() {
	int x[9] = {200, 280, 360, 200, 280, 360, 200, 280, 360};//数字的x坐标
	int y[9] = {120, 120, 120, 200, 200, 200, 280, 280, 280};//数字的y坐标
	setfont(70, 35, L"Lucida Console");//字体
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (MAP[i][j] != 0) print_score(MAP[i][j], x[i * 3 + j] + 2, y[i * 3 + j] + 2);  
                //如果不是0就在框框内写入数字。
			else outtextxy(x[i * 3 + j] + 2, y[i * 3 + j] + 2, L" ");
                //如果是0就代表这里是空白
		}
	}
}

6.move_map函数

这个函数就是我们操作的核心了。

void move_map() {
	position p;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (MAP[i][j] == 0) {        //记录哪个地方是空白的
				p.x = i;
				p.y = j;
			}
		}
	}
	if (KEY_DOWN(VK_RIGHT)) {                //如果按下右键就让空白处左边的数移到空白处
		if (p.y != 0) {                      //而且空白处左边必须有数(y坐标不为0)
			swap(MAP[p.x][p.y], MAP[p.x][p.y - 1]);//移动(交换)
		}
	}
	if (KEY_DOWN(VK_LEFT)) {
		if (p.y != 2) {                      //下同
			swap(MAP[p.x][p.y], MAP[p.x][p.y + 1]);
		}
	}
	if (KEY_DOWN(VK_DOWN)) {
		if (p.x != 0) {
			swap(MAP[p.x][p.y], MAP[p.x - 1][p.y]);
		}
	}
	if (KEY_DOWN(VK_UP)) {
		if (p.x != 2) {
			swap(MAP[p.x][p.y], MAP[p.x + 1][p.y]);
		}
	}
}

7.is_win函数

判断是否已经胜利。 

bool is_win() {
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (MAP[i][j] != i * 3 + j + 1 && MAP[i][j] != 0) return 0;//如果这个数字不在它该在的位置上的话返回0
		}
	}
	return 1;
}

8.win函数

当判断胜利后,我们要输出生胜利信息.

void win() {
	cleardevice();
	setfont(80, 40, L"Lucida Console");
	outtextxy(200, 200, L"WIN!!!");
	Sleep(1000);
	getch();
}

这个就没什么好说的了。

9.int_to_string函数

将int转换为string,也没什么好说的。

string DX(string s) {
	string res = "";
	for (int i = s.size() - 1; i >= 0; i--)
		res += s[i];
	return res;
}

string int_to_string(int i) {
	string res = "";
	while (i % 10 != i) {
		res += i % 10 + '0';
		i /= 10;
	}
	res += i + '0';
	return DX(res);
}

10.print_score函数

前面的int_to_string就用在这里了,输出数字。

void print_score(int score, int x = 0, int y = 0) {    //x,y:坐标
	string s = int_to_string(score);                   //将score转为string型
	for (int i = 0; i < s.size(); i++) {
		switch (s[i]) {                                //输出第i位
			case '0':
				outtextxy(x + 10 * i, y, L"0");
				break;
			case '1':
				outtextxy(x + 10 * i, y, L"1");
				break;
			case '2':
				outtextxy(x + 10 * i, y, L"2");
				break;
			case '3':
				outtextxy(x + 10 * i, y, L"3");
				break;
			case '4':
				outtextxy(x + 10 * i, y, L"4");
				break;
			case '5':
				outtextxy(x + 10 * i, y, L"5");
				break;
			case '6':
				outtextxy(x + 10 * i, y, L"6");
				break;
			case '7':
				outtextxy(x + 10 * i, y, L"7");
				break;
			case '8':
				outtextxy(x + 10 * i, y, L"8");
				break;
			case '9':
				outtextxy(x + 10 * i, y, L"9");
				break;
			default:
				outtextxy(x + 10 * i, y, L"Error");        //如果不是0123456789中的一个就报错
				break;
		}
	}
}

这个函数是在draw_number里用到的,用来输出数字。

四、结束

那么现在我们的数字华容道就写完了,下面是代码:

#include<graphics.h>
#include<bits/stdc++.h>

#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000)? 1 : 0)

using namespace std;

int MAP[3][3];
bool mus_state = 0;

typedef struct {
	int x;
	int y;
} position;												//不是坐标轴的x,y,而是行和列

string DX(string s) {
	string res = "";
	for (int i = s.size() - 1; i >= 0; i--)
		res += s[i];
	return res;
}

string int_to_string(int i) {
	string res = "";
	while (i % 10 != i) {
		res += i % 10 + '0';
		i /= 10;
	}
	res += i + '0';
	return DX(res);
}

void print_score(int score, int x = 0, int y = 0) {
	string s = int_to_string(score);
	for (int i = 0; i < s.size(); i++) {
		switch (s[i]) {
			case '0':
				outtextxy(x + 10 * i, y, L"0");
				break;
			case '1':
				outtextxy(x + 10 * i, y, L"1");
				break;
			case '2':
				outtextxy(x + 10 * i, y, L"2");
				break;
			case '3':
				outtextxy(x + 10 * i, y, L"3");
				break;
			case '4':
				outtextxy(x + 10 * i, y, L"4");
				break;
			case '5':
				outtextxy(x + 10 * i, y, L"5");
				break;
			case '6':
				outtextxy(x + 10 * i, y, L"6");
				break;
			case '7':
				outtextxy(x + 10 * i, y, L"7");
				break;
			case '8':
				outtextxy(x + 10 * i, y, L"8");
				break;
			case '9':
				outtextxy(x + 10 * i, y, L"9");
				break;
			default:
				outtextxy(x + 10 * i, y, L"Error");
				break;
		}
	}
}

bool is_win();

void init_map() {
	bool b[9] = {0};
	randomize();
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			do {
				MAP[i][j] = random(9);
			} while (b[MAP[i][j]] != 0);
			b[MAP[i][j]] = 1;
		}
	}
	if (is_win()) init_map();
}

void draw_map() {
	int x[9] = {200, 280, 360, 200, 280, 360, 200, 280, 360};
	int y[9] = {120, 120, 120, 200, 200, 200, 280, 280, 280};
	setcolor(BLACK);
	for (int i = 0; i < 9; i++) {
		rectangle(x[i], y[i], x[i] + 80, y[i] + 80);
	}
}

void draw_number() {
	int x[9] = {200, 280, 360, 200, 280, 360, 200, 280, 360};
	int y[9] = {120, 120, 120, 200, 200, 200, 280, 280, 280};
	setfont(70, 35, L"Lucida Console");
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (MAP[i][j] != 0) print_score(MAP[i][j], x[i * 3 + j] + 2, y[i * 3 + j] + 2);
			else outtextxy(x[i * 3 + j] + 2, y[i * 3 + j] + 2, L" ");
		}
	}
}

void move_map() {
	position p;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (MAP[i][j] == 0) {
				p.x = i;
				p.y = j;
			}
		}
	}
	if (KEY_DOWN(VK_RIGHT)) {
		if (p.y != 0) {
			swap(MAP[p.x][p.y], MAP[p.x][p.y - 1]);
		}
	}
	if (KEY_DOWN(VK_LEFT)) {
		if (p.y != 2) {
			swap(MAP[p.x][p.y], MAP[p.x][p.y + 1]);
		}
	}
	if (KEY_DOWN(VK_DOWN)) {
		if (p.x != 0) {
			swap(MAP[p.x][p.y], MAP[p.x - 1][p.y]);
		}
	}
	if (KEY_DOWN(VK_UP)) {
		if (p.x != 2) {
			swap(MAP[p.x][p.y], MAP[p.x + 1][p.y]);
		}
	}
}

bool is_win() {
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (MAP[i][j] != i * 3 + j + 1 && MAP[i][j] != 0) return 0;
		}
	}
	return 1;
}

void win() {
	cleardevice();
	setfont(80, 40, L"Lucida Console");
	outtextxy(200, 200, L"WIN!!!");
	Sleep(1000);
	getch();
}

int main() {
	initgraph(640, 480);
	setcaption(L"数字华容道");
	setbkcolor(WHITE);
	MUSIC mus;
	mus.OpenFile(L"Piano.mp3");
	mus.Play();
	init_map();
	draw_map();
	draw_number();
	setfont(20, 10, L"Lucida Console");
	outtext(L"按N静音");
	outtextxy(0, 20, L"按M重置");
	outtextxy(0, 40, L"按B退出");
	for (;;) {
		move_map();
		draw_number();
		if (KEY_DOWN('N')) {
			if (mus_state == 0) {
				mus_state = 1;
				mus.Pause();
			} else {
				mus_state = 0;
				mus.Play();
			}
		}
		if (KEY_DOWN('M')) {
			init_map();
			draw_map();
			draw_number();
		}
		if (KEY_DOWN('B')) {
			return 0;
		}
		if (is_win()) {
			break;
		}
		if (mus.GetLength() == mus.GetPosition()) {
			mus.Close();
			mus.OpenFile(L"Piano.mp3");
			mus.Play();
		}
		Sleep(100);
	}
	win();
	closegraph();
	return 0;
}

五、程序下载

今天写的游戏和音乐我都会放到这里,需要的可以下载。

六、Conclusion

今天我们用ege库写出了我们的第一个游戏,下期,我们将会用ege库写出更好的游戏。

敬请期待!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值