CodeBus投稿落选代码——瓦片地图粗糙版 记录

Easyx官网上有个分享代码的网站。

然后心血来潮,想起来之前的瓦片地图编辑器

DevC++ easyx实现视口编辑--像素绘图板与贴图系统-CSDN博客

就去试试投稿。然后收到回复说要改格式,写注释,按帖子要求排版。

然后排版完了,有好心人提示几个地方修改,比如说题目英文中文之间空格隔开。

然后继续改,巧的是改着改着就来消息说代码比较多,建议上传项目文件压缩包。

然后就到 visualstdio 上跑一遍,发现可以。

然后再提交,然后手机响了,审核同志来询问这个软件的“应用”。然后提出来软件的应用性不够。

比如说整个png图像当游戏背景显然是不可能的,像素绘制瓦片就不如到PS上绘制了。

虽然发了一个png当跳一跳游戏背景的截图,然后有人就指出来实际游戏里运行的情况不同,提示说去可以看看官网推荐参考案例——FC红白机坦克大战的代码。

然后就谢谢指点。

总之后续又有几句话,强调了应用性,随即提示说背景是个二维数组里了,坦克到哪个数组,数组序号是1,1是砖头,坦克就不能继续前进。说可以导出二维数组。再然后就没有然后了,理解了整个故事,也翻看了坦克大战的数组地图,打算这个寒假重整一下瓦片地图,导出瓦片地图背后的二维数组。和二维数组对应的数字,数字对应的像素贴图。这样应该就能过审了。也可以产生价值了。

但是旧的代码呢?估计是雪藏了,但是又再网上搜索关键字,发现旧文案被转载了,然后想起来按格式改写的代码,觉得还是先整一篇新的吧,原来的篇目当做历史,记录无中生有的变化。也算是还原一下一个普通程序的发展历程。

完整代码

虽然代码确实和DevC++ easyx实现视口编辑--像素绘图板与贴图系统-CSDN博客一样,

但是一想起来转载到DevC++ easyx实现视口编辑--像素绘图板与贴图系统 - 技术栈 (jishuzhan.net)

没有注释的代码多少确实有点不够意思,或者说现在巧了,有个详细注释版本,就更新一下

记录一下一些原来应被改写的代码的原样。

一键整合版


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// main.cpp
 
#include <stdio.h>
#include <graphics.h>



// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// oripic.h
int w = 2600; 					// 大地图长
int h = 800;					// 大地图宽
IMAGE set(w, h);				// 大地图

struct pixlocal
{
	short x;				// 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素
	short y;
};

struct skline
{							// 另一个编辑器按绘制顺序打印线条生长动画,这里是 debug 用
	int lenth = 0;			// 线条长度
	int setx, sety;			// 锚点,线条参考位置,但是这个像素绘图板没有用到这个锚点
	struct pixlocal a[10000];	// 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素
} nf, ndnf;

struct drawdesksize
{							// 绿色绘图板的大小设置
	int x;					// 绿色绘图板左上角坐标
	int y;
	int a;					// 绿色绘图板长宽
	int h;
	int sizetile = 8;		// 像素大小为 8 正方形大小则是 8*8
	int smx;				// 悬浮窗大小
	int smy;
} ddm;						// 绿色绘图板参数,其设定完成后,用于计算其他配套网格参数

IMAGE maptile(ddm.a / ddm.sizetile, ddm.h / ddm.sizetile);	// 瓦片、和瓦片大小

struct pircle
{							// 拖动悬浮窗
	IMAGE img2;				// 悬浮窗图像
	IMAGE img3;				// 悬浮窗底线盖住的图像,用于恢复原来盖住图像
	int orilx, orily;		// 悬浮窗初始化时的左上角坐标
	int nowlx, nowly;		// 悬浮窗当前位置的左上角坐标
	int a, h;				// 悬浮窗长宽
	int m1x = 0, m1y = 0;	// img3 左上角坐标
	bool putflag = 0;		// 拖动 flag , 用于悬浮窗拖动
	int drawflag = 0;		// 瓦片绘制 flag , 用于实现长按鼠标绘制像素
	struct skline b;		// 线条长度存储,当时用于开发技能动画,但是在这里只是用来测试功能,比如拖动技能图标,实现技能启用关闭,就是这个变量在控制
} save;						// 待保存的悬浮窗数据,所以只能有一个

struct picsave
{							// 绿色网格插槽,暂存笔刷
	int lx;					// 左上角坐标
	int ly;
	int wide;				// 宽高
	int h;
	int useflag;			// 是否被使用
	struct skline b;		// 配套线条暂存
} a[28];					// 暂存上限 28 个瓦片



// 初始化绘图窗口
void OriPicDesk(int a, int h)
{
	initgraph(a, h, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	cleardevice();				//	创制绘图界面,背景色设置,以背景色填充

	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 1);	//	不含实线,矩形的面积为 8*8,含实线 9*9

	rectangle(0, 0, a - 2, h - 1);		//	确定工作界面范围

	setfillcolor(WHITE);
}



// 初始化整个软件窗口大小
void OriDrawDeskSize(struct drawdesksize* ddm, int x, int y)
{
	ddm->x = x;
	ddm->y = y;
	ddm->a = 640;
	ddm->h = 640;
	ddm->sizetile = 8;
	ddm->smx = ddm->x - ddm->a / ddm->sizetile;
	ddm->smy = ddm->y - ddm->h / ddm->sizetile;
}



// 初始化整个软件窗口大小
void DrawDesk(struct drawdesksize ddm)
{
	int i, j;
	int square = ddm.sizetile;
	for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square)
	{
		for (j = ddm.y; j < ddm.y + ddm.h; j += square)
		{
			fillrectangle(i, j, i + square, j + square);
		}
	}
	rectangle(ddm.smx - 1, ddm.smy - 1, ddm.x, ddm.y);
}



// 初始化白色小图
void OriPirCle(struct pircle* save, struct drawdesksize* ddm)
{
	save->orilx = ddm->smx, save->orily = ddm->smy;
	save->nowlx = ddm->smx, save->nowly = ddm->smy;		// img2 的左上角坐标
	save->a = ddm->a / ddm->sizetile;
	save->h = ddm->h / ddm->sizetile;
	save->m1x = 0, save->m1y = 0;						// img3 的左上角坐标
	save->putflag = 0;
	save->drawflag = 0;
}



// 初始化大地图
void OriSet(IMAGE* set, struct drawdesksize ddm)
{

	SetWorkingImage(set);
	setbkcolor(YELLOW);			// 背景黄色

	cleardevice();
	setlinecolor(BLACK);

	for (int i = 0; i < w; i += ddm.a / ddm.sizetile)
	{
		for (int j = 0; j < h; j += ddm.h / ddm.sizetile)
			rectangle(j + 1, i + 1, j + ddm.a / ddm.sizetile, i + ddm.h / ddm.sizetile);	// 网格绘制
	}
	line(0, 0, 800, 1400);
	SetWorkingImage();
}


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// show.h
extern struct skline nf, ndnf;
extern IMAGE maptile;


void DidShow(IMAGE* set, IMAGE maptile, ExMessage m, int show_x, int show_y, int nowlx, int nowly)
{
	static int flag = 0;
	static int oldx = -8, oldy = -8;
	int putx = 0, puty = 0;

	if (m.message == WM_LBUTTONDOWN)
	{
		// 左键批量绘制瓦片到大地图
		SetWorkingImage(set);
		putx = nowlx + m.x - show_x;				// 计算当前在大地图的坐标
		puty = nowly + m.y - show_y;
		putx = putx - putx % 80;					// 计算所在的网格
		puty = puty - puty % 80;
		putimage(putx, puty, &maptile);				// 把 maptile 粘贴到大地图中
		SetWorkingImage();
	}
	else
	{
		if (putx == oldx && puty == oldy)
		{											// 如果和上次的位置相同,则不贴图,避免了重复贴图
		}
		else
		{
			SetWorkingImage(set);
			putx = nowlx + m.x - show_x;			// 计算当前在大地图的坐标
			puty = nowly + m.y - show_y;
			putx = putx - putx % 80;				// 计算所在的网格
			puty = puty - puty % 80;
			putimage(putx, puty, &maptile);			// 把 maptile 粘贴到大地图中

			oldx = putx;							// 暂存本次绘图左上角坐标
			oldy = puty;
			SetWorkingImage();
		}
	}
}


// 视口函数
void Show(IMAGE* set, ExMessage m, int show_x, int show_y, int show_wideth, int show_height)
{
	//	视口的图片大小,视口的大小,在窗口的坐标,视口的大小
	static int nowlx, nowly, pic_wide, pic_heigh;
	static int m1x, m1y;
	static bool drawflag, putflag, attachflag;
	static	IMAGE olds(show_wideth, show_height);
	static	IMAGE news(show_wideth, show_height);
	static int m2x, m2y;							// 加速移动设置参数 m2x , m2y , 自动移动设置
	static int flag = 1;							// 视口初始化,要覆盖到窗口上

	if (flag == 1)
	{
		pic_wide = show_wideth;
		pic_heigh = show_height;
		m1x = 0;
		m1y = 0;
		m2x = 0;
		m2y = 0;
		drawflag = 0;
		putflag = 0;
		attachflag = 0;
		flag = 0;
		setlinecolor(BLACK);
		rectangle(show_x, show_y, show_x + show_wideth, show_y + show_height);
		SetWorkingImage(set);
		getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);
		SetWorkingImage();
		putimage(show_x, show_y, &olds);
	}
	else
	{
		if (m.message == WM_LBUTTONDOWN)
		{
			if (m.ctrl && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height)
			{
				// ctrl+左键视口,连续移动大地图
				SetWorkingImage(set);									// 获取视口里的图片
				getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);

				m1x = m.x;												// 长按开始时的坐标
				m1y = m.y;
				m2x = m.x;
				m2y = m.y;

				SetWorkingImage();
				putflag = true;											// 启动地图移动
			}
			else if (m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height)
			{
				// 鼠标左键实现瓦片贴图
				DidShow(set, maptile, m, show_x, show_y, nowlx, nowly);	// 开始把瓦片贴入大地图
				attachflag = true;										// 批量绘制启动
			}
		}
		else if (attachflag == true && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height)
		{
			// 连续贴图
			DidShow(set, maptile, m, show_x, show_y, nowlx, nowly);
			if (m.message == WM_LBUTTONUP)
			{
				attachflag = false;										// 长按结束,笔刷涂贴片停止
			}
			SetWorkingImage(set);										// 贴片涂完后台的大地图,从大地图拷贝后,立即在桌面更新显示
			getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);
			SetWorkingImage();
			putimage(show_x, show_y, &olds);
		}
		else if (putflag == true)
		{
			// 持续拖动大地图
			SetWorkingImage(set);										// 进行了位移放大
			nowlx = nowlx - 5 * (m.x - m1x);							// 位移同鼠标位移方向相反,长度为五倍关系
			nowly = nowly - 5 * (m.y - m1y);

			m1x = m.x;													// 不可改动这两行代码位置
			m1y = m.y;

			getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);
			SetWorkingImage();
			putimage(show_x, show_y, &olds);
			if (m.message == WM_LBUTTONUP || m.ctrl == 0)
			{
				putflag = 0;											// 长按停止,视口采样停止
			}
		}
	}
}




// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// draw.h
extern IMAGE maptile;


// 像素绘图板的小矩形绘制,开发顺序是先有这个 draw.h 代码,然后有 show.h 代码。这两个头文件是继承关系
void Remem(struct ExMessage m, int* lenth, struct drawdesksize ddm)
{
	int i = *lenth;
	static int oldx = -ddm.sizetile,
		oldy = -ddm.sizetile,
		a = ddm.sizetile,
		h = ddm.sizetile;
	if (m.x > oldx && m.x<oldx + a && m.y>oldy && m.y < oldy + h)
	{
																		// 修正可涂色范围,防止溢出。y 不可等于 640+100,x 等于 640+600-1 是边界小方块的最右侧像素
																		// 节约运算,不在相同位置重复绘制
	}
	else
	{
		int px = 0, py = 0, qx = 0, qy = 0;
		int mapqx = 0, mapqy = 0;

		px = m.x - ddm.x;												// 修正 600 的偏移,601=600+1;0==1%8,600=600+(601-600)%8
		py = m.y - ddm.y;

		qx = px - px % a;												// 取整,用于确定黑色像素矩形位置
		qy = py - py % h;

		mapqx = qx / a;													// 计算对应悬浮窗的像素坐标
		mapqy = qy / h;

		px = ddm.x + qx;												// 相对与绿色绘图区域左上角的坐标
		py = ddm.y + qy;


		setfillcolor(BLACK);
		fillrectangle(px, py, px + ddm.sizetile, py + ddm.sizetile);	// 绘制黑色像素矩形

		nf.a[i].x = mapqx;												// 悬浮窗技能动画数据存储
		nf.a[i].y = mapqy;
		i++;
		*lenth = i;
		nf.lenth = *lenth;


		printf("%d %d %d\n", i - 1, nf.a[i - 1].x, nf.a[i - 1].y);
		putpixel(ddm.smx + nf.a[i - 1].x, ddm.smy + nf.a[i - 1].y, BLACK);	// 绘制悬浮窗像素
		oldx = px;
		oldy = py;
	}
}

//	绘制函数,悬浮窗绘制与绿色网格绘制像素
void Draw(ExMessage m, int* lenth)
{
	static int flag = 0;
	if (m.message == WM_LBUTTONDOWN)
	{
		Remem(m, lenth, ddm);
		//		printf("draw function is running 222\n");					// 测试
		flag = 1;
	}
	else if (flag == 1)
	{
		Remem(m, lenth, ddm);
		if (m.message == WM_LBUTTONUP)
		{
			flag = 0;
		}
	}
}


// 绘制像素
void DrawMouseCheck(ExMessage m, int* lenth, struct drawdesksize* ddm)
{
	if (m.x > ddm->x && m.x<ddm->x + ddm->a && m.y>ddm->y && m.y < ddm->y + ddm->h)
	{
		Draw(m, lenth);
//		printf("333\n");
	}
}




// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// flowsave.h


// 用于保存悬浮窗图案,以及对应线条动画数据
void OriFlowSave(int x, int y, int w, int h)
{
	setfillcolor(GREEN);
	int i;
	int num = 0;
	for (int j = 0; j < h; j++)
	{
		for (i = 1; i <= w; i++)
		{
			a[num].lx = x + 1 + i * 81;
			a[num].ly = y + 1 + j * 81;
			a[num].wide = 80;
			a[num].h = 80;
			a[num].useflag = 0;
			fillrectangle(a[num].lx, a[num].ly, a[num].lx + a[num].wide, a[num].ly + a[num].h);
			num++;
		}
	}
}


// 选中暂存的瓦片的数据
void ReHave(ExMessage m, int w, int h)
{
	int i;
	int num = 0;
	for (int j = 0; j < w; j++)
	{
		for (i = 1; i <= h; i++)
		{
			if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h)
			{
				if (a[num].useflag == 1)
				{
					ndnf = a[num].b;							// 读取数据,但是 ndnf 没有用到
					break;
				}
			}
			num++;
		}
	}
}

// 选中暂存的瓦片的图案
void PickPen(ExMessage m, int w, int h)
{
	int i, j;
	int num = 0;
	for (j = 0; j < w; j++)
	{
		for (i = 1; i <= h; i++)
		{
			if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h)
			{
				if (a[num].useflag == 1)
				{
					getimage(&maptile, a[num].lx, a[num].ly, 80, 80);
					fillrectangle(20, 80, 100, 160);			// 左上角会显示图案,就是选中了
					putimage(20, 80, &maptile);
				}
			}
			num++;
		}
	}
}

// 鼠标放置悬浮窗
void FlowSave(ExMessage m, struct pircle* save, int w, int h)
{
	if (m.message == WM_LBUTTONDOWN)
	{
		PickPen(m, w, h);										// 左键选中画笔
	}
	else if (m.message == WM_LBUTTONUP)
	{
		int i;
		int num = 0;
		for (int j = 0; j < w; j++)
		{
			for (i = 1; i <= h; i++)
			{
				if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h)
				{
					if (a[num].useflag == 0)
					{											// 找到空白的插槽
						a[num].b = nf;

						if (save->nowlx != save->orilx && save->nowly != save->orily)
						{
							putimage(save->nowlx, save->nowly, &save->img3);
						}
						else
						{
							getimage(&save->img2, save->orilx, save->orily, save->a, save->h);
						}
						putimage(a[num].lx, a[num].ly, &save->img2);


						save->nowlx = save->orilx;				// 悬浮窗复位
						save->nowly = save->orily;
						save->m1x = 0;
						save->m1y = 0;
//						printf("%d\n", save->m1x);				// 测试
						save->putflag = false;					// 悬浮窗拖动停止
						a[num].useflag = 1;
						break;
					}
				}
				num++;
			}
		}
	}
	if (m.message == WM_RBUTTONDOWN)
	{
		ReHave(m, w, h);										// 在瓦片地图这里没有用,但是从这里衍生的其他编辑器用到了
	}
}



// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// movecheck.h
extern int w2, h2;

// 用于检测小地图拖动
void MoveCheck(struct ExMessage m, struct pircle* save)
{
	if (save->putflag == 0 && m.message == WM_LBUTTONDOWN)
	{
		if (save->m1x == 0 && save->m1y == 0 && m.x > save->orilx && m.x<save->orilx + save->a && m.y>save->orily && m.y < save->orily + save->h)
		{
			getimage(&save->img2, save->orilx, save->orily, save->a, save->h);	// 获取原图
			getimage(&save->img3, save->orilx, save->orily, save->a, save->h);	// 初始化底图
			save->m1x = m.x;
			save->m1y = m.y;
			save->putflag = true;
			//			printf("movecheck is running 2222\n");					// 测试
		}
		else if (m.x > save->nowlx && m.x<save->nowlx + save->a && m.y>save->nowly && m.y < save->nowly + save->h)
		{
			save->putflag = true;
			getimage(&save->img2, save->orilx, save->orily, save->a, save->h);
			save->m1x = m.x;
			save->m1y = m.y;
			//			printf("movecheck function is running11111\n");		 	// 测试
		}
	}
	else if (save->putflag == true)
	{
		BeginBatchDraw();

		putimage(save->nowlx, save->nowly, &save->img3);						// 先恢复原来底图
		save->nowlx = save->nowlx + m.x - save->m1x;							// 鼠标移动的距离变成图片更新的距离
		save->nowly = save->nowly + m.y - save->m1y;
		save->m1x = m.x;														// 鼠标的坐标被记录下来
		save->m1y = m.y;
		getimage(&save->img3, save->nowlx, save->nowly, save->a, save->h);		// 再获取新的底图
		putimage(save->nowlx, save->nowly, &save->img2);						// 然后才粘贴新的悬浮窗

		EndBatchDraw();															// 一次绘图出来,没有屏闪了

		if (m.message == WM_LBUTTONUP)
		{
			save->putflag = 0;													// 停止移动悬浮窗
		}
	}
}



// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// keycheck.h
extern IMAGE set;

// 重置绘图版
void Ori(struct drawdesksize ddm)
{
	int i, j;
	int square = ddm.sizetile;
	setfillcolor(WHITE);
	setlinecolor(GREEN);
	for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square)
	{
		for (j = ddm.y; j < ddm.y + ddm.h; j += square)
		{
			fillrectangle(i, j, i + square, j + square);			// 像素网格重置
		}
	}
	for (i = ddm.smx; i < ddm.smx + ddm.a / ddm.sizetile; i++)
	{
		for (j = ddm.smy; j < ddm.smy + ddm.h / ddm.sizetile; j++)
		{
			putpixel(i, j, WHITE);									// 悬浮窗重置
		}
	}
}


// 小地图轨迹打印,这个就是所谓的 skline 的作用。另一个编辑器实现了线条导出功能
void Pixnf(int lenth, struct drawdesksize ddm)
{
	int i = 0;
	for (i = 0; i < lenth; i++)
	{
		putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, WHITE);
		if (i % 55 == 0)
			Sleep(1);
	}
	for (i = 0; i < lenth; i++)
	{
		putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, BLACK);
		if (i % 55 == 0)
			Sleep(1);
	}
}

// 按键检测
void KeyCheck(ExMessage m, int* lenth)
{
	switch (m.vkcode)
	{
	case VK_F1:													// 重置绘图板
		Ori(ddm);
		*lenth = 0;
		break;
	case VK_F2:													// 导出为 gamemap0 的 png 图片
		saveimage(_T("gamemap.png"), &set);
		break;
	case VK_F5:													// 播放线条动画
		static int limf5 = 0;
		if (limf5 == 0)
		{
			Pixnf(*lenth, ddm);
			limf5 = 1;
		}
		else
		{
			limf5 = 0;											// 处理掉的 bug:按 F5 一次,打印两次线条
		}
		break;
	}
}

int x2 = 650, y2 = 100;									// 深绿色像素板的左上角坐标
int w2 = 3, h2 = 7;										// 绿色网格的列数、行数
int showx3 = 101, showy3 = 100;							// 黄色网格视口的左上角坐标


int main()
{
	OriPicDesk(1800, 870);								// 初始化整个软件窗口大小
	OriDrawDeskSize(&ddm, 1000, 100);					// 初始化整个软件窗口大小
	OriPirCle(&save, &ddm);								// 初始化白色小图
	OriSet(&set, ddm);									// 初始化大地图
	OriFlowSave(x2, y2, w2, h2);						// 初始化暂存瓦片的绿色网格
	DrawDesk(ddm);										// 绘制出像素绘图板


	ExMessage m;
	int lenth = 0;										// 用于记录绘制长度,在 debug 时看控制台窗口数据
	while (1)
	{
		m = getmessage(EX_MOUSE | EX_KEY);				// 获取鼠标、按键信息
		DrawMouseCheck(m, &lenth, &ddm);				// 像素绘制检测
		KeyCheck(m, &lenth);							// 按键检测
		MoveCheck(m, &save);							// 拖动检测
		FlowSave(m, &save, w2, h2);						// 暂存检测
		Show(&set, m, showx3, showy3, 600, 700);		// 大地图绘制
	}
	closegraph();

	return 0;
}

分部版本 

main.cpp


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// main.cpp
 
#include <stdio.h>
#include <graphics.h>


#include"oripic.h"									// 初始化函数集中在这个头文件里了
#include"show.h"									// 视口、粘贴瓦片
#include"draw.h"									// 绘制瓦片
#include"flowsave.h"								// 瓦片暂存
#include"movecheck.h"								// 鼠标点击检测
#include"keycheck.h"								// 按键按动检测


int x2 = 650, y2 = 100;									// 深绿色像素板的左上角坐标
int w2 = 3, h2 = 7;										// 绿色网格的列数、行数
int showx3 = 101, showy3 = 100;							// 黄色网格视口的左上角坐标


int main()
{
	OriPicDesk(1800, 870);								// 初始化整个软件窗口大小
	OriDrawDeskSize(&ddm, 1000, 100);					// 初始化整个软件窗口大小
	OriPirCle(&save, &ddm);								// 初始化白色小图
	OriSet(&set, ddm);									// 初始化大地图
	OriFlowSave(x2, y2, w2, h2);						// 初始化暂存瓦片的绿色网格
	DrawDesk(ddm);										// 绘制出像素绘图板


	ExMessage m;
	int lenth = 0;										// 用于记录绘制长度,在 debug 时看控制台窗口数据
	while (1)
	{
		m = getmessage(EX_MOUSE | EX_KEY);				// 获取鼠标、按键信息
		DrawMouseCheck(m, &lenth, &ddm);				// 像素绘制检测
		KeyCheck(m, &lenth);							// 按键检测
		MoveCheck(m, &save);							// 拖动检测
		FlowSave(m, &save, w2, h2);						// 暂存检测
		Show(&set, m, showx3, showy3, 600, 700);		// 大地图绘制
	}
	closegraph();

	return 0;
}

oripic.h 


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// oripic.h
int w = 2600; 					// 大地图长
int h = 800;					// 大地图宽
IMAGE set(w, h);				// 大地图

struct pixlocal
{
	short x;				// 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素
	short y;
};

struct skline
{							// 另一个编辑器按绘制顺序打印线条生长动画,这里是 debug 用
	int lenth = 0;			// 线条长度
	int setx, sety;			// 锚点,线条参考位置,但是这个像素绘图板没有用到这个锚点
	struct pixlocal a[10000];	// 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素
} nf, ndnf;

struct drawdesksize
{							// 绿色绘图板的大小设置
	int x;					// 绿色绘图板左上角坐标
	int y;
	int a;					// 绿色绘图板长宽
	int h;
	int sizetile = 8;		// 像素大小为 8 正方形大小则是 8*8
	int smx;				// 悬浮窗大小
	int smy;
} ddm;						// 绿色绘图板参数,其设定完成后,用于计算其他配套网格参数

IMAGE maptile(ddm.a / ddm.sizetile, ddm.h / ddm.sizetile);	// 瓦片、和瓦片大小

struct pircle
{							// 拖动悬浮窗
	IMAGE img2;				// 悬浮窗图像
	IMAGE img3;				// 悬浮窗底线盖住的图像,用于恢复原来盖住图像
	int orilx, orily;		// 悬浮窗初始化时的左上角坐标
	int nowlx, nowly;		// 悬浮窗当前位置的左上角坐标
	int a, h;				// 悬浮窗长宽
	int m1x = 0, m1y = 0;	// img3 左上角坐标
	bool putflag = 0;		// 拖动 flag , 用于悬浮窗拖动
	int drawflag = 0;		// 瓦片绘制 flag , 用于实现长按鼠标绘制像素
	struct skline b;		// 线条长度存储,当时用于开发技能动画,但是在这里只是用来测试功能,比如拖动技能图标,实现技能启用关闭,就是这个变量在控制
} save;						// 待保存的悬浮窗数据,所以只能有一个

struct picsave
{							// 绿色网格插槽,暂存笔刷
	int lx;					// 左上角坐标
	int ly;
	int wide;				// 宽高
	int h;
	int useflag;			// 是否被使用
	struct skline b;		// 配套线条暂存
} a[28];					// 暂存上限 28 个瓦片



// 初始化绘图窗口
void OriPicDesk(int a, int h)
{
	initgraph(a, h, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	cleardevice();				//	创制绘图界面,背景色设置,以背景色填充

	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 1);	//	不含实线,矩形的面积为 8*8,含实线 9*9

	rectangle(0, 0, a - 2, h - 1);		//	确定工作界面范围

	setfillcolor(WHITE);
}



// 初始化整个软件窗口大小
void OriDrawDeskSize(struct drawdesksize* ddm, int x, int y)
{
	ddm->x = x;
	ddm->y = y;
	ddm->a = 640;
	ddm->h = 640;
	ddm->sizetile = 8;
	ddm->smx = ddm->x - ddm->a / ddm->sizetile;
	ddm->smy = ddm->y - ddm->h / ddm->sizetile;
}



// 初始化整个软件窗口大小
void DrawDesk(struct drawdesksize ddm)
{
	int i, j;
	int square = ddm.sizetile;
	for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square)
	{
		for (j = ddm.y; j < ddm.y + ddm.h; j += square)
		{
			fillrectangle(i, j, i + square, j + square);
		}
	}
	rectangle(ddm.smx - 1, ddm.smy - 1, ddm.x, ddm.y);
}



// 初始化白色小图
void OriPirCle(struct pircle* save, struct drawdesksize* ddm)
{
	save->orilx = ddm->smx, save->orily = ddm->smy;
	save->nowlx = ddm->smx, save->nowly = ddm->smy;		// img2 的左上角坐标
	save->a = ddm->a / ddm->sizetile;
	save->h = ddm->h / ddm->sizetile;
	save->m1x = 0, save->m1y = 0;						// img3 的左上角坐标
	save->putflag = 0;
	save->drawflag = 0;
}



// 初始化大地图
void OriSet(IMAGE* set, struct drawdesksize ddm)
{

	SetWorkingImage(set);
	setbkcolor(YELLOW);			// 背景黄色

	cleardevice();
	setlinecolor(BLACK);

	for (int i = 0; i < w; i += ddm.a / ddm.sizetile)
	{
		for (int j = 0; j < h; j += ddm.h / ddm.sizetile)
			rectangle(j + 1, i + 1, j + ddm.a / ddm.sizetile, i + ddm.h / ddm.sizetile);	// 网格绘制
	}
	line(0, 0, 800, 1400);
	SetWorkingImage();
}

 

 show.h


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// show.h
extern struct skline nf, ndnf;
extern IMAGE maptile;


void DidShow(IMAGE* set, IMAGE maptile, ExMessage m, int show_x, int show_y, int nowlx, int nowly)
{
	static int flag = 0;
	static int oldx = -8, oldy = -8;
	int putx = 0, puty = 0;

	if (m.message == WM_LBUTTONDOWN)
	{
		// 左键批量绘制瓦片到大地图
		SetWorkingImage(set);
		putx = nowlx + m.x - show_x;				// 计算当前在大地图的坐标
		puty = nowly + m.y - show_y;
		putx = putx - putx % 80;					// 计算所在的网格
		puty = puty - puty % 80;
		putimage(putx, puty, &maptile);				// 把 maptile 粘贴到大地图中
		SetWorkingImage();
	}
	else
	{
		if (putx == oldx && puty == oldy)
		{											// 如果和上次的位置相同,则不贴图,避免了重复贴图
		}
		else
		{
			SetWorkingImage(set);
			putx = nowlx + m.x - show_x;			// 计算当前在大地图的坐标
			puty = nowly + m.y - show_y;
			putx = putx - putx % 80;				// 计算所在的网格
			puty = puty - puty % 80;
			putimage(putx, puty, &maptile);			// 把 maptile 粘贴到大地图中

			oldx = putx;							// 暂存本次绘图左上角坐标
			oldy = puty;
			SetWorkingImage();
		}
	}
}


// 视口函数
void Show(IMAGE* set, ExMessage m, int show_x, int show_y, int show_wideth, int show_height)
{
	//	视口的图片大小,视口的大小,在窗口的坐标,视口的大小
	static int nowlx, nowly, pic_wide, pic_heigh;
	static int m1x, m1y;
	static bool drawflag, putflag, attachflag;
	static	IMAGE olds(show_wideth, show_height);
	static	IMAGE news(show_wideth, show_height);
	static int m2x, m2y;							// 加速移动设置参数 m2x , m2y , 自动移动设置
	static int flag = 1;							// 视口初始化,要覆盖到窗口上

	if (flag == 1)
	{
		pic_wide = show_wideth;
		pic_heigh = show_height;
		m1x = 0;
		m1y = 0;
		m2x = 0;
		m2y = 0;
		drawflag = 0;
		putflag = 0;
		attachflag = 0;
		flag = 0;
		setlinecolor(BLACK);
		rectangle(show_x, show_y, show_x + show_wideth, show_y + show_height);
		SetWorkingImage(set);
		getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);
		SetWorkingImage();
		putimage(show_x, show_y, &olds);
	}
	else
	{
		if (m.message == WM_LBUTTONDOWN)
		{
			if (m.ctrl && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height)
			{
				// ctrl+左键视口,连续移动大地图
				SetWorkingImage(set);									// 获取视口里的图片
				getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);

				m1x = m.x;												// 长按开始时的坐标
				m1y = m.y;
				m2x = m.x;
				m2y = m.y;

				SetWorkingImage();
				putflag = true;											// 启动地图移动
			}
			else if (m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height)
			{
				// 鼠标左键实现瓦片贴图
				DidShow(set, maptile, m, show_x, show_y, nowlx, nowly);	// 开始把瓦片贴入大地图
				attachflag = true;										// 批量绘制启动
			}
		}
		else if (attachflag == true && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height)
		{
			// 连续贴图
			DidShow(set, maptile, m, show_x, show_y, nowlx, nowly);
			if (m.message == WM_LBUTTONUP)
			{
				attachflag = false;										// 长按结束,笔刷涂贴片停止
			}
			SetWorkingImage(set);										// 贴片涂完后台的大地图,从大地图拷贝后,立即在桌面更新显示
			getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);
			SetWorkingImage();
			putimage(show_x, show_y, &olds);
		}
		else if (putflag == true)
		{
			// 持续拖动大地图
			SetWorkingImage(set);										// 进行了位移放大
			nowlx = nowlx - 5 * (m.x - m1x);							// 位移同鼠标位移方向相反,长度为五倍关系
			nowly = nowly - 5 * (m.y - m1y);

			m1x = m.x;													// 不可改动这两行代码位置
			m1y = m.y;

			getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);
			SetWorkingImage();
			putimage(show_x, show_y, &olds);
			if (m.message == WM_LBUTTONUP || m.ctrl == 0)
			{
				putflag = 0;											// 长按停止,视口采样停止
			}
		}
	}
}

 

 draw.h


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// draw.h
extern IMAGE maptile;


// 像素绘图板的小矩形绘制,开发顺序是先有这个 draw.h 代码,然后有 show.h 代码。这两个头文件是继承关系
void Remem(struct ExMessage m, int* lenth, struct drawdesksize ddm)
{
	int i = *lenth;
	static int oldx = -ddm.sizetile,
		oldy = -ddm.sizetile,
		a = ddm.sizetile,
		h = ddm.sizetile;
	if (m.x > oldx && m.x<oldx + a && m.y>oldy && m.y < oldy + h)
	{
																		// 修正可涂色范围,防止溢出。y 不可等于 640+100,x 等于 640+600-1 是边界小方块的最右侧像素
																		// 节约运算,不在相同位置重复绘制
	}
	else
	{
		int px = 0, py = 0, qx = 0, qy = 0;
		int mapqx = 0, mapqy = 0;

		px = m.x - ddm.x;												// 修正 600 的偏移,601=600+1;0==1%8,600=600+(601-600)%8
		py = m.y - ddm.y;

		qx = px - px % a;												// 取整,用于确定黑色像素矩形位置
		qy = py - py % h;

		mapqx = qx / a;													// 计算对应悬浮窗的像素坐标
		mapqy = qy / h;

		px = ddm.x + qx;												// 相对与绿色绘图区域左上角的坐标
		py = ddm.y + qy;


		setfillcolor(BLACK);
		fillrectangle(px, py, px + ddm.sizetile, py + ddm.sizetile);	// 绘制黑色像素矩形

		nf.a[i].x = mapqx;												// 悬浮窗技能动画数据存储
		nf.a[i].y = mapqy;
		i++;
		*lenth = i;
		nf.lenth = *lenth;


		printf("%d %d %d\n", i - 1, nf.a[i - 1].x, nf.a[i - 1].y);
		putpixel(ddm.smx + nf.a[i - 1].x, ddm.smy + nf.a[i - 1].y, BLACK);	// 绘制悬浮窗像素
		oldx = px;
		oldy = py;
	}
}

//	绘制函数,悬浮窗绘制与绿色网格绘制像素
void Draw(ExMessage m, int* lenth)
{
	static int flag = 0;
	if (m.message == WM_LBUTTONDOWN)
	{
		Remem(m, lenth, ddm);
		//		printf("draw function is running 222\n");					// 测试
		flag = 1;
	}
	else if (flag == 1)
	{
		Remem(m, lenth, ddm);
		if (m.message == WM_LBUTTONUP)
		{
			flag = 0;
		}
	}
}


// 绘制像素
void DrawMouseCheck(ExMessage m, int* lenth, struct drawdesksize* ddm)
{
	if (m.x > ddm->x && m.x<ddm->x + ddm->a && m.y>ddm->y && m.y < ddm->y + ddm->h)
	{
		Draw(m, lenth);
//		printf("333\n");
	}
}

 

flowsave.h 


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// flowsave.h


// 用于保存悬浮窗图案,以及对应线条动画数据
void OriFlowSave(int x, int y, int w, int h)
{
	setfillcolor(GREEN);
	int i;
	int num = 0;
	for (int j = 0; j < h; j++)
	{
		for (i = 1; i <= w; i++)
		{
			a[num].lx = x + 1 + i * 81;
			a[num].ly = y + 1 + j * 81;
			a[num].wide = 80;
			a[num].h = 80;
			a[num].useflag = 0;
			fillrectangle(a[num].lx, a[num].ly, a[num].lx + a[num].wide, a[num].ly + a[num].h);
			num++;
		}
	}
}


// 选中暂存的瓦片的数据
void ReHave(ExMessage m, int w, int h)
{
	int i;
	int num = 0;
	for (int j = 0; j < w; j++)
	{
		for (i = 1; i <= h; i++)
		{
			if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h)
			{
				if (a[num].useflag == 1)
				{
					ndnf = a[num].b;							// 读取数据,但是 ndnf 没有用到
					break;
				}
			}
			num++;
		}
	}
}

// 选中暂存的瓦片的图案
void PickPen(ExMessage m, int w, int h)
{
	int i, j;
	int num = 0;
	for (j = 0; j < w; j++)
	{
		for (i = 1; i <= h; i++)
		{
			if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h)
			{
				if (a[num].useflag == 1)
				{
					getimage(&maptile, a[num].lx, a[num].ly, 80, 80);
					fillrectangle(20, 80, 100, 160);			// 左上角会显示图案,就是选中了
					putimage(20, 80, &maptile);
				}
			}
			num++;
		}
	}
}

// 鼠标放置悬浮窗
void FlowSave(ExMessage m, struct pircle* save, int w, int h)
{
	if (m.message == WM_LBUTTONDOWN)
	{
		PickPen(m, w, h);										// 左键选中画笔
	}
	else if (m.message == WM_LBUTTONUP)
	{
		int i;
		int num = 0;
		for (int j = 0; j < w; j++)
		{
			for (i = 1; i <= h; i++)
			{
				if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h)
				{
					if (a[num].useflag == 0)
					{											// 找到空白的插槽
						a[num].b = nf;

						if (save->nowlx != save->orilx && save->nowly != save->orily)
						{
							putimage(save->nowlx, save->nowly, &save->img3);
						}
						else
						{
							getimage(&save->img2, save->orilx, save->orily, save->a, save->h);
						}
						putimage(a[num].lx, a[num].ly, &save->img2);


						save->nowlx = save->orilx;				// 悬浮窗复位
						save->nowly = save->orily;
						save->m1x = 0;
						save->m1y = 0;
//						printf("%d\n", save->m1x);				// 测试
						save->putflag = false;					// 悬浮窗拖动停止
						a[num].useflag = 1;
						break;
					}
				}
				num++;
			}
		}
	}
	if (m.message == WM_RBUTTONDOWN)
	{
		ReHave(m, w, h);										// 在瓦片地图这里没有用,但是从这里衍生的其他编辑器用到了
	}
}

 

movecheck.h 


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// movecheck.h
extern int w2, h2;

// 用于检测小地图拖动
void MoveCheck(struct ExMessage m, struct pircle* save)
{
	if (save->putflag == 0 && m.message == WM_LBUTTONDOWN)
	{
		if (save->m1x == 0 && save->m1y == 0 && m.x > save->orilx && m.x<save->orilx + save->a && m.y>save->orily && m.y < save->orily + save->h)
		{
			getimage(&save->img2, save->orilx, save->orily, save->a, save->h);	// 获取原图
			getimage(&save->img3, save->orilx, save->orily, save->a, save->h);	// 初始化底图
			save->m1x = m.x;
			save->m1y = m.y;
			save->putflag = true;
			//			printf("movecheck is running 2222\n");					// 测试
		}
		else if (m.x > save->nowlx && m.x<save->nowlx + save->a && m.y>save->nowly && m.y < save->nowly + save->h)
		{
			save->putflag = true;
			getimage(&save->img2, save->orilx, save->orily, save->a, save->h);
			save->m1x = m.x;
			save->m1y = m.y;
			//			printf("movecheck function is running11111\n");		 	// 测试
		}
	}
	else if (save->putflag == true)
	{
		BeginBatchDraw();

		putimage(save->nowlx, save->nowly, &save->img3);						// 先恢复原来底图
		save->nowlx = save->nowlx + m.x - save->m1x;							// 鼠标移动的距离变成图片更新的距离
		save->nowly = save->nowly + m.y - save->m1y;
		save->m1x = m.x;														// 鼠标的坐标被记录下来
		save->m1y = m.y;
		getimage(&save->img3, save->nowlx, save->nowly, save->a, save->h);		// 再获取新的底图
		putimage(save->nowlx, save->nowly, &save->img2);						// 然后才粘贴新的悬浮窗

		EndBatchDraw();															// 一次绘图出来,没有屏闪了

		if (m.message == WM_LBUTTONUP)
		{
			save->putflag = 0;													// 停止移动悬浮窗
		}
	}
}

 

keycheck.h 


// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// keycheck.h
extern IMAGE set;

// 重置绘图版
void Ori(struct drawdesksize ddm)
{
	int i, j;
	int square = ddm.sizetile;
	setfillcolor(WHITE);
	setlinecolor(GREEN);
	for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square)
	{
		for (j = ddm.y; j < ddm.y + ddm.h; j += square)
		{
			fillrectangle(i, j, i + square, j + square);			// 像素网格重置
		}
	}
	for (i = ddm.smx; i < ddm.smx + ddm.a / ddm.sizetile; i++)
	{
		for (j = ddm.smy; j < ddm.smy + ddm.h / ddm.sizetile; j++)
		{
			putpixel(i, j, WHITE);									// 悬浮窗重置
		}
	}
}


// 小地图轨迹打印,这个就是所谓的 skline 的作用。另一个编辑器实现了线条导出功能
void Pixnf(int lenth, struct drawdesksize ddm)
{
	int i = 0;
	for (i = 0; i < lenth; i++)
	{
		putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, WHITE);
		if (i % 55 == 0)
			Sleep(1);
	}
	for (i = 0; i < lenth; i++)
	{
		putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, BLACK);
		if (i % 55 == 0)
			Sleep(1);
	}
}

// 按键检测
void KeyCheck(ExMessage m, int* lenth)
{
	switch (m.vkcode)
	{
	case VK_F1:													// 重置绘图板
		Ori(ddm);
		*lenth = 0;
		break;
	case VK_F2:													// 导出为 gamemap0 的 png 图片
		saveimage(_T("gamemap.png"), &set);
		break;
	case VK_F5:													// 播放线条动画
		static int limf5 = 0;
		if (limf5 == 0)
		{
			Pixnf(*lenth, ddm);
			limf5 = 1;
		}
		else
		{
			limf5 = 0;											// 处理掉的 bug:按 F5 一次,打印两次线条
		}
		break;
	}
}

相关推荐

  1. CodeBus投稿落选代码——瓦片地图粗糙 记录

    2024-01-06 03:16:01       41 阅读
  2. 百度地图瓦片下载地址

    2024-01-06 03:16:01       8 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-06 03:16:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-06 03:16:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-06 03:16:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-06 03:16:01       20 阅读

热门阅读

  1. 【学习记录】找最低位1/模块多次例化

    2024-01-06 03:16:01       40 阅读
  2. 《微信小程序开发从入门到实战》学习七十二

    2024-01-06 03:16:01       35 阅读
  3. Unity组件开发--事件管理器

    2024-01-06 03:16:01       35 阅读
  4. vue中导航守卫有哪三种?分别有什么作用

    2024-01-06 03:16:01       39 阅读
  5. 01.PostgreSQL基本SELECT语句

    2024-01-06 03:16:01       51 阅读
  6. 1944. 队列中可以看到的人数

    2024-01-06 03:16:01       39 阅读