图形库编程学习笔记(二)

图形库编程中级篇

一:基本的贴图操作

  1. 在贴图前先做好准备工作,比如:添加相关的头文件graphics.h,创建一个供贴图的窗口等等
  2. 用IMAGE类型去定义一个标识符来表示一张图片。
  3. 用loadimage();加载资源:也就是将图片资源的位置传给刚刚定义的IMAGE类型的变量,这样就达到了将名字和相应的资源绑定。(该图形库仅支持.bmp和.jpg格式的图片贴图)
  4. putimage();将图片贴到创建的窗口上。
    在这里插入图片描述
    前两个参数是表明将图片左上角贴到创建的窗口的坐标系统位置。第三个参数是图片变量的地址。

loadimage();
第1个参数为IMAGE变量的地址。
第2个参数为图片资源的位置即路径。
关于图片资源的路径问题,这里有相对引用绝对引用两种。

已经将项目属性改为多字节(关于这个问题参见:图形的可视化编程(一))

相对引用:
当图片资源与.cpp文件在同一目录下时我们可以用其相对路径进行引用。例如我们将图片:1.jpg与该.cpp文件放在同一目录下。我们就可以用相对引用,这时只需要用到图片资源的名称即可。
如:
在这里插入图片描述
这种引用方法。
绝对引用:
绝对引用适用的范围更加广阔,当图片资源和.cpp文件不在同一目录下,比如图片资源在与.cpp同目录的一个文件夹中或者在计算机某个盘的某个文件夹下面时。那么我们就无法用相对引用了。此时我们必须要用到其绝对位置了。
如下面这种情况:
在这里插入图片描述
获取绝对路径的方法:
在这里插入图片描述
这里的对象名称就是其绝对位置了。我们可以将其复制粘贴到代码中了。
在这里插入图片描述
注意:由于\字符转义的问题,我们在使用时要讲单反斜杠\改为\\ 双反斜杠,或者改为/单斜杠

另外:使用loadimage()加载图片时可以用第三第四个参数进行图片的缩放。

示例:

#include<graphics.h>
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main(void)
{
	initgraph(800, 600);
	IMAGE m;
	//loadimage(&m, "C:\\Users\\付河林\\Desktop\\图片坐标\\images\\1.jpg");绝对引用
	loadimage(&m, "1.jpg");
	putimage(0, 0, &m);
	_getch();
	closegraph();
	return 0;
}

效果:
在这里插入图片描述

我们可以用m.getwidth()和m.getheight()来获取图片的长和宽,如果我们将获取的图片的尺寸传给initgraph()来创建窗口,那么就可以避免创建的窗口大小和图片的大小不一致的问题了。
如:
在这里插入图片描述

二:基本的鼠标操作

基本框架

  1. 声明一个鼠标类型的消息:MOUSEMSG m;
  2. 获取鼠标消息:m=GetMouseMsg();
  3. 获取鼠标消息的基本属性: 鼠标的坐标:m.x和m.y;鼠标的类型:m.uMsg(消息类型的标记)
    基本的应用实例:
    代码:
#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<conio.h>
int main(void)
{
	initgraph(800, 600);
	MOUSEMSG m;
	while (1)
	{
		m = GetMouseMsg();
		switch (m.uMsg)
		{
		case WM_LBUTTONDOWN:      //L:left
			setfillcolor(RED);
			solidcircle(m.x, m.y, 50);
			break;
		case WM_RBUTTONDOWN:      //R:right button:  按钮  down:向下
			setfillcolor(WHITE);
			solidcircle(m.x, m.y, 50);
			break;
		case WM_MOUSEMOVE:         //W:Windows M:message mouse:鼠标  move:移动
			circle(m.x, m.y, 10);
			break;
		default:
			break;
		}
	}
	closegraph();
	return 0;
}

效果:
在这里插入图片描述

按下鼠标左键,在当前位置画一个半径50的红色填充圆,右键,在当前位置画一个半径为50的白色填充圆。

鼠标操作的菜单模型:

#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<conio.h>
void makeMenu()
{
	setfillcolor(RGB(192,192,192));
	fillrectangle(300, 200, 500, 250);
	fillrectangle(300, 250 + 10, 500, 250 + 10 + 50);
	settextstyle(35, 0, "黑体");
	settextcolor(BLUE);
	setbkmode(TRANSPARENT);
	outtextxy(300 + 25, 200 + 10, "开始游戏");
	outtextxy(300 + 25, 250 + 10 + 10, "结束游戏");
	MOUSEMSG m;
	while (1)//监视鼠标
	{
		m = GetMouseMsg();
		if (m.x >= 300 && m.x <= 500 && m.y >= 200 && m.y <= 250)
		{
			setfillcolor(YELLOW);
			fillrectangle(300, 200, 500, 250);
			outtextxy(300 + 25, 200 + 10, "开始游戏");
			if (m.uMsg == WM_LBUTTONDOWN)
			{
				break;
			}
		}
		else if (m.x >= 300 && m.x <= 500 && m.y >= 260 && m.y <= 310)
		{
			setfillcolor(YELLOW);
			fillrectangle(300, 250 + 10, 500, 250 + 10 + 50);
			outtextxy(300 + 25, 250 + 10 + 10, "结束游戏");
			if (m.uMsg == WM_LBUTTONDOWN)
			{
				Sleep(3000);//休眠3000毫秒后关闭程序
				exit(0);
			}
		}
		else
		{
			setfillcolor(RGB(192,192,192));
			fillrectangle(300, 200, 500, 250);
			fillrectangle(300, 250 + 10, 500, 250 + 10 + 50);
			outtextxy(300 + 25, 200 + 10, "开始游戏");
			outtextxy(300 + 25, 250 + 10 + 10, "结束游戏");
		}
	}
}
int main(void)
{
	initgraph(800, 600);
	makeMenu();
	//game();  当点击开始游戏后break;退出循环执行下一条语句game();我们将鼠标操作菜单放在游戏模块之前就行了
	closegraph();
	return 0;
}

在这里插入图片描述

三:音乐播放

  1. 播放音乐需要另外添加头文件mmsystem.h和静态库#pragma comment(lib,“winmm.lib”)
  2. 用mciSendString和一些指令来控制音乐的播放
  3. 如:mciSendString(“open 说好不哭.mp3 alias music”,0,0,0);
    其中指令open:打开音乐文件 alias:起别名(当音乐文件的名称过长时为其起个别名,在后面的引用中会更加方便)
    一些其他的指令:
    play:播放
    stop: 停止
    pause:暂停
    resume: 继续
    close: 关闭

示例:

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
int main()
{
	mciSendString("open 说好不哭.mp3 alias music", 0, 0, 0);
	mciSendString("play music repeat", 0, 0, 0);
	_getch();
	return 0;
}

四:推箱子图形化

二维数组与推箱子:

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
//模块设计理念:尽量避免功能交叉,做到高内聚,底耦合。
///*
//	//1.墙:	■
//	//0.空地 :两个空格
//	//3.目的地		☆
//	//4.箱子		★
//	//5:人		※
//	//3+4:箱子到达目的地	●
//*/
int cas = 0;
	int map[3][8][8] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 3, 4, 0, 0, 1,
1, 0, 1, 0, 5, 1, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 4, 3, 0, 4, 1,
1, 4, 1, 0, 0, 1, 3, 1,
1, 3, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 0, 0, 0, 1,
1, 0, 1, 0, 5, 1, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 4, 3, 0, 4, 1,
1, 4, 1, 0, 0, 1, 3, 1,
1, 3, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 0, 0, 0, 4, 3, 1,
1, 4, 1, 0, 5, 1, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 1, 0, 4, 3, 0, 4, 1,
1, 0, 4, 0, 0, 1, 3, 1,
1, 0, 3, 1, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1
	};
void gotoxy(int x, int y) //光标移动到(x,y)位置,在游戏中打印一张画面后将光标拉到(x,y)处进行打印。
	{
		HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
		COORD pos;
		pos.X = x;
		pos.Y = y;
		SetConsoleCursorPosition(handle, pos);
	}
void drawGraph()
{
	printf("推箱子第%d关\n", cas+1);
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			switch (map[cas][i][j])
			{
			case 0:
				printf("  ");//打印空地
				break;
			case 1:
				printf("■");//打印墙
				break;
			case 3:
				printf("☆");//打印目的地
				break;
			case 4:
				printf("★");//打印箱子
				break;
			case 5:
			case 8://人到达目的地
				printf("※");//打印人
				break;
			case 7:
				printf("●");//箱子到达目的地
				break;
			}
		}
		printf("\n");
	}
}
void keyDown()
{
	//定位
	int i;
	int j;
	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 8; j++)
		{
			if (map[cas][i][j] == 5 || map[cas][i][j] == 8)
			{
				break;
			}
		}
		if (map[cas][i][j] == 5 || map[cas][i][j] == 8)
		{
			break;
		}
	}
	printf("%d%d", i, j);
	char userKey = _getch();
	switch (userKey)
	{
	case 'W':
	case 'w':
	case 72:
		if (map[cas][i - 1][j] == 0 || map[cas][i - 1][j] == 3)
		{
			map[cas][i - 1][j] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i - 1][j] == 4 || map[cas][i - 1][j] == 7)
		{
			if (map[cas][i - 2][j] == 0 || map[cas][i - 2][j] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i - 1][j] += 1;
				map[cas][i - 2][j] += 4;
			}
		}
		break;
	case 'S':
	case 's':
	case 80:
		if (map[cas][i + 1][j] == 0 || map[cas][i + 1][j] == 3)
		{
			map[cas][i + 1][j] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i + 1][j] == 4 || map[cas][i + 1][j] == 7)
		{
			if (map[cas][i + 2][j] == 0 || map[cas][i + 2][j] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i + 1][j] += 1;
				map[cas][i + 2][j] += 4;
			}
		}
		break;
	case 'A':
	case 'a':
	case 75:
		if (map[cas][i][j - 1] == 0 || map[cas][i][j - 1] == 3)
		{
			map[cas][i][j - 1] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i][j - 1] == 4 || map[cas][i][j - 1] == 7)
		{
			if (map[cas][i][j - 2] == 0 || map[cas][i][j - 2] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i][j - 1] += 1;
				map[cas][i][j - 2] += 4;
			}
		}
		break;
	case 'D':
	case 'd':
	case 77:
		if (map[cas][i][j + 1] == 0 || map[cas][i][j + 1] == 3)
		{
			map[cas][i][j + 1] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i][j + 1] == 4 || map[cas][i][j + 1] == 7)
		{
			if (map[cas][i][j + 2] == 0 || map[cas][i][j + 2] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i][j + 1] += 1;
				map[cas][i][j + 2] += 4;
			}
		}
		break;
	}
}
int gameOver()
{
	int flag = 1;
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			if (map[cas][i][j] == 4)
			{
				flag = 0;
			}
		}
	}
	return flag;
}
int main(void)
{
	while (1)
	{
		gotoxy(0, 0);
		drawGraph();
		keyDown();
		if (gameOver() == 1)
		{
			cas++;
			if (cas == 3)
			{
				//drawGraph();
				break;
			}
		}
	}
	system("cls");
	printf("Victory\n");
	return 0;
}

图形化优化:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
int cas = 0;
int map[3][8][8] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 3, 4, 0, 0, 1,
1, 0, 1, 0, 5, 1, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 4, 3, 0, 4, 1,
1, 4, 1, 0, 0, 1, 3, 1,
1, 3, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 0, 0, 0, 1,
1, 0, 1, 0, 5, 1, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 4, 3, 0, 4, 1,
1, 4, 1, 0, 0, 1, 3, 1,
1, 3, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 0, 0, 0, 4, 3, 1,
1, 4, 1, 0, 5, 1, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 1, 0, 4, 3, 0, 4, 1,
1, 0, 4, 0, 0, 1, 3, 1,
1, 0, 3, 1, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
IMAGE img[6];
int imgIndex[6] = { 0,1,3,4,5,7 };
void loadResource()
{
	for (int i = 0; i < 6; i++)
	{
		char fileName[20] = "";
		sprintf(fileName, "%d.bmp", imgIndex[i]);
		loadimage(&img[i], fileName);
	}
}
void gotoxy(int x, int y) //光标移动到(x,y)位置,在游戏中打印一张画面后将光标拉到(x,y)处进行打印。
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(handle, pos);
}
void drawGraph()
{

	//printf("推箱子第%d关\n", cas + 1);
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			int x = 60 * j;
			int y = 60 * i;
			switch (map[cas][i][j])
			{
			case 0:
				putimage(x, y, &img[0]);
				//printf("  ");//打印空地
				break;
			case 1:
				putimage(x, y, &img[1]);

				//printf("■");//打印墙
				break;
			case 3:
				putimage(x, y, &img[2]);

				//printf("☆");//打印目的地
				break;
			case 4:
				putimage(x, y, &img[3]);

				//printf("★");//打印箱子
				break;
			case 5:
			case 8://人到达目的地
				//printf("※");//打印人
				putimage(x, y, &img[4]);

				break;
			case 7:
				putimage(x, y, &img[5]);

				//printf("●");//箱子到达目的地
				break;
			}
		}
		//printf("\n");
	}
}
void keyDown()
{
	//定位
	int i;
	int j;
	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 8; j++)
		{
			if (map[cas][i][j] == 5 || map[cas][i][j] == 8)
			{
				break;
			}
		}
		if (map[cas][i][j] == 5 || map[cas][i][j] == 8)
		{
			break;
		}
	}
	//printf("%d%d", i, j);
	char userKey = _getch();
	switch (userKey)
	{
	case 'W':
	case 'w':
	case 72:
		if (map[cas][i - 1][j] == 0 || map[cas][i - 1][j] == 3)
		{
			map[cas][i - 1][j] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i - 1][j] == 4 || map[cas][i - 1][j] == 7)
		{
			if (map[cas][i - 2][j] == 0 || map[cas][i - 2][j] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i - 1][j] += 1;
				map[cas][i - 2][j] += 4;
			}
		}
		break;
	case 'S':
	case 's':
	case 80:
		if (map[cas][i + 1][j] == 0 || map[cas][i + 1][j] == 3)
		{
			map[cas][i + 1][j] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i + 1][j] == 4 || map[cas][i + 1][j] == 7)
		{
			if (map[cas][i + 2][j] == 0 || map[cas][i + 2][j] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i + 1][j] += 1;
				map[cas][i + 2][j] += 4;
			}
		}
		break;
	case 'A':
	case 'a':
	case 75:
		if (map[cas][i][j - 1] == 0 || map[cas][i][j - 1] == 3)
		{
			map[cas][i][j - 1] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i][j - 1] == 4 || map[cas][i][j - 1] == 7)
		{
			if (map[cas][i][j - 2] == 0 || map[cas][i][j - 2] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i][j - 1] += 1;
				map[cas][i][j - 2] += 4;
			}
		}
		break;
	case 'D':
	case 'd':
	case 77:
		if (map[cas][i][j + 1] == 0 || map[cas][i][j + 1] == 3)
		{
			map[cas][i][j + 1] += 5;
			map[cas][i][j] -= 5;
		}
		else if (map[cas][i][j + 1] == 4 || map[cas][i][j + 1] == 7)
		{
			if (map[cas][i][j + 2] == 0 || map[cas][i][j + 2] == 3)
			{
				map[cas][i][j] -= 5;
				map[cas][i][j + 1] += 1;
				map[cas][i][j + 2] += 4;
			}
		}
		break;
	}
}
int gameOver()
{
	int flag = 1;
	for (int i = 0; i < 8; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			if (map[cas][i][j] == 4)
			{
				flag = 0;
			}
		}
	}
	return flag;
}
void makeMenu()
{
	initgraph(800, 600);
	setfillcolor(RGB(192, 192, 192));
	fillrectangle(300, 200, 500, 250);
	fillrectangle(300, 250 + 10, 500, 250 + 10 + 50);
	settextstyle(35, 0, "黑体");
	settextcolor(BLUE);
	setbkmode(TRANSPARENT);
	outtextxy(300 + 25, 200 + 10, "开始游戏");
	outtextxy(300 + 25, 250 + 10 + 10, "结束游戏");
	MOUSEMSG m;
	while (1)//监视鼠标
	{
		m = GetMouseMsg();
		if (m.x >= 300 && m.x <= 500 && m.y >= 200 && m.y <= 250)
		{
			setfillcolor(YELLOW);
			fillrectangle(300, 200, 500, 250);
			outtextxy(300 + 25, 200 + 10, "开始游戏");
			if (m.uMsg == WM_LBUTTONDOWN)
			{
				break;
			}
		}
		else if (m.x >= 300 && m.x <= 500 && m.y >= 260 && m.y <= 310)
		{
			setfillcolor(YELLOW);
			fillrectangle(300, 250 + 10, 500, 250 + 10 + 50);
			outtextxy(300 + 25, 250 + 10 + 10, "结束游戏");
			if (m.uMsg == WM_LBUTTONDOWN)
			{
				Sleep(3000);//休眠3000毫秒后关闭程序
				exit(0);
			}
		}
		else
		{
			setfillcolor(RGB(192, 192, 192));
			fillrectangle(300, 200, 500, 250);
			fillrectangle(300, 250 + 10, 500, 250 + 10 + 50);
			outtextxy(300 + 25, 200 + 10, "开始游戏");
			outtextxy(300 + 25, 250 + 10 + 10, "结束游戏");
		}
	}
	closegraph();
}
int main(void)
{
	loadResource();
	makeMenu();
	initgraph(8 * 60, 8 * 60);
	while (1)
	{
		//gotoxy(0, 0);
		//initgraph(8 * 60, 8 * 60);
		drawGraph();
		keyDown();
		if (gameOver() == 1)
		{
			cas++;
			if (cas == 3)
			{
				break;
			}
		}
		//closegraph();
	}
	closegraph();
	return 0;
}

这里我们加上了前面用鼠标操作写的makeMenu()菜单

效果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值