?微调代码,实现图片笔刷暂存。
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <windows.h>
//#include "pentable.h"
typedef struct setmap
{
int lx = 0;
int ly = 0; // 游戏地图的左上角坐标
int rx = 0;
int ry = 0; // 优化计算,确定鼠标是否在网格里
int row = 0; // 游戏地图瓦片行个数
int column = 0; // 游戏地图瓦片列个数
int tileSize = 0; // 正方形瓦片的长宽像素
int** map = NULL; // 瓦片地图的二维数组数据,一个一维数组等同于一级指针,一个指针数组是二级指针。
IMAGE have[10] = { 0 }; // 每个瓦片序号对应的图片
}set;
typedef struct tile
{
int lx = 0;
int ly = 0;
int rx = 0;
int ry = 0;
int level = 0;
int tileSize = 0;
int ismove = 0;
int isoccupied = 0;
IMAGE* penimage = NULL; // 指针,初始化绘制贴图为空
}tile;
typedef struct tilegroup
{
int lx;
int ly;
int rx;
int ry;
int row; // 行
int column; // 列
int tileSize;
tile** pengroup;
}tilegroup;
void freshgamemap(set* gamemap) // 从pentable初始化中沿用的网格绘制代码,为后续卡马克卷轴开发准备
{
for (int i = 0; i < gamemap->row; i++)
{
int tiley = gamemap->ly + i * gamemap->tileSize;
for (int j = 0; j < gamemap->column; j++)
{
int tilex = gamemap->lx + j * gamemap->tileSize;
rectangle(tilex, tiley, tilex + gamemap->tileSize, tiley + gamemap->tileSize);
}
}
}
set* initgamemap()
{
int row = 26, column = 27;
//scanf_s("%d %d", &row, &column); // 游戏地图瓦片行列个数
set* gamemap = (set*)malloc(sizeof(set)); // 指针,因为 set 结构体的 map 数组需要修改。学习阶段属性:这是开发着自然而然意识到的问题。
if (gamemap == NULL)
{
printf("地图创建失败,可能是内存不足\n");
exit(0);
}
gamemap->lx = 100;
gamemap->ly = 100;
gamemap->row = row;
gamemap->column = column;
gamemap->tileSize = 16;
gamemap->rx = gamemap->lx + gamemap->column * gamemap->tileSize; // 根据数据计算右下角边缘,右下角行坐标=左上角横坐标+列个数*瓦片像素
gamemap->ry = gamemap->ly + gamemap->row * gamemap->tileSize;
gamemap->map = new int* [row]; // 数组动态生成,先生成列,就是一共有多少行,二级指针赋值指针数组
for (int i = 0; i < row; i++)
{
gamemap->map[i] = new int[column]; // 指针数组分别赋值一维数组,每个指针指向一个数组,一行有多少列。主要适配 save()函数部分的打印,一行一行打印
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
gamemap->map[i][j] = 0; // 默认0是无障碍
printf("%d", gamemap->map[i][j]);
}
printf("\n");
}
initgraph(1280, 800, 1);
setbkcolor(WHITE);
cleardevice();
setlinecolor(BLACK);
rectangle(gamemap->lx, gamemap->ly, gamemap->rx, gamemap->ry); // 绘制游戏地图边框
freshgamemap(gamemap);
return gamemap;
}
void draw(ExMessage msg, set* gamemap, tile* pen)
{
static int isdraw = 0;
static int oldtilex;
static int oldtiley;
if (msg.message == WM_LBUTTONDOWN && msg.x > gamemap->lx && msg.y > gamemap->ly && msg.x < gamemap->rx && msg.y < gamemap->ry)
{
int x = msg.x - gamemap->lx; // 距离游戏地图左上角的行距离
int y = msg.y - gamemap->ly;
int tilex = x / gamemap->tileSize; // 以距离游戏地图左上角的距离再除以瓦片长度,算出在第几个瓦片
int tiley = y / gamemap->tileSize;
int mapx = msg.x - x % gamemap->tileSize;
int mapy = msg.y - y % gamemap->tileSize;
if (oldtilex != tilex || oldtiley != tiley) // 性能优化,如果是相同瓦片,就不绘制,这里也有比较是因为打表检测有第一次按下时会不断打印,
{ // 所以需要对第一下按住左键也优化
oldtilex = tilex; // 记录本次瓦片位置,为下次瓦片是否相同比较,来减少重复绘制
oldtiley = tiley;
gamemap->map[tiley][tilex] = pen->level;
putimage(mapx, mapy, pen->penimage);
//setfillcolor(BLACK);
//fillrectangle(gamemap->lx + tilex * gamemap->tileSize, gamemap->ly + tiley * gamemap->tileSize, gamemap->lx + (tilex + 1) * gamemap->tileSize, gamemap->ly + (tiley + 1) * gamemap->tileSize);
printf("%d %d level = %d\n", tilex, tiley, pen->level);
}
isdraw = 1; // 实现鼠标长按效果,搭配后面的 if else
}
else if (isdraw == 1)
{
if (msg.message == WM_LBUTTONUP)
{
isdraw = 0;
}
else if (isdraw && msg.x > gamemap->lx && msg.y > gamemap->ly && msg.x < gamemap->rx && msg.y < gamemap->ry)
{
int x = msg.x - gamemap->lx; // 距离游戏地图左上角的行距离
int y = msg.y - gamemap->ly;
int tilex = x / gamemap->tileSize; // 以距离游戏地图左上角的距离再除以瓦片长度,算出在第几个瓦片
int tiley = y / gamemap->tileSize;
int mapx = msg.x - x % gamemap->tileSize;
int mapy = msg.y - y % gamemap->tileSize;
if (oldtilex != tilex || oldtiley != tiley) // 性能优化,如果是相同瓦片,就不绘制,这里也有比较是因为打表检测有第一次按下时会不断打印,
{ // 所以需要对第一下按住左键也优化
oldtilex = tilex; // 记录本次瓦片位置,为下次瓦片是否相同比较,来减少重复绘制
oldtiley = tiley;
gamemap->map[tiley][tilex] = pen->level;
putimage(mapx, mapy, pen->penimage);
printf("%d %d level = %d\n", tilex, tiley, pen->level);
}
}
}
}
void save(ExMessage msg, set* gamemap)
{
if (msg.message == WM_KEYDOWN || msg.message == WM_KEYUP)
{
if (msg.vkcode == VK_F1) // 因为peek读取一个按键信息,所以两个按键组合,需要暂存上一个,用来一个标志位,记录ctrl是否按下
{
printf("save\n");
FILE* fp;
fopen_s(&fp, "gamemap.txt", "w+");
if (fp == NULL)
{
printf("文件创建失败,可能是内存不足\n");
exit(0);
}
for (int i = 0; i < gamemap->row; i++)
{
for (int j = 0; j < gamemap->column; j++)
{
fprintf(fp, "%d", gamemap->map[i][j]);
}
fprintf(fp, "\n");
}
fclose(fp);
printf("save success\n");
wchar_t s[10];
InputBox(s, 10, L"不过是提示一下,解决重复保存bug");
}
}
}
tilegroup* initpentable()
{
int row = 8; // 行个数
int column = 1; // 列个数
//scanf_s("%d %d", &row, &column); // 笔刷瓦片存储区行列个数
tilegroup* pentable = (tilegroup*)malloc(sizeof(tilegroup));
if (pentable == NULL) {
printf("分配笔刷失败,可能是内存不足\n");
exit(0);
}
pentable->lx = 700; // 初始化瓦片存储区的左上角位置
pentable->ly = 100;
pentable->row = row;
pentable->column = column;
pentable->tileSize = 16;
pentable->rx = pentable->lx + pentable->column * pentable->tileSize; // 根据数据计算右下角边缘,右下角横坐标=左上角横坐标+列个数*瓦片像素
pentable->ry = pentable->ly + pentable->row * pentable->tileSize; // 根据数据计算右下角边缘,右下角纵坐标=左上角纵坐标+行个数*瓦片像素
pentable->pengroup = new tile * [row]; // 数组动态生成,先生成列,就是一共有多少行,二级指针赋值指针数组
if (pentable->pengroup == NULL)
{
printf("笔刷分配失败\n");
exit(0);
}
for (int i = 0; i < row; i++)
{
pentable->pengroup[i] = new tile[column]; // 指针数组分别赋值一维数组,每个指针指向一个数组,一行有多少列。主要适配 save()函数部分的打印,一行一行打印
}
for (int i = 0; i < row; i++)
{
int tiley = pentable->ly + i * pentable->tileSize;
setfillcolor(RGB(tiley * 3, tiley * 3, tiley * 5));
for (int j = 0; j < column; j++)
{
int tilex = pentable->lx + j * pentable->tileSize;
pentable->pengroup[i][j].lx = tilex;
pentable->pengroup[i][j].ly = tiley;
pentable->pengroup[i][j].rx = tilex + pentable->tileSize;
pentable->pengroup[i][j].ry = tiley + pentable->tileSize;
pentable->pengroup[i][j].isoccupied = 0;
pentable->pengroup[i][j].level = i; // 每个层级有3行插槽暂存笔刷
pentable->pengroup[i][j].penimage = new IMAGE(pentable->tileSize, pentable->tileSize);
SetWorkingImage(pentable->pengroup[i][j].penimage);
setfillcolor(RGB(tiley * 3, tiley * 3, tiley * 5));
fillrectangle(-1,-1,pentable->tileSize,pentable->tileSize);
SetWorkingImage();
fillrectangle(tilex, tiley, tilex + pentable->tileSize, tiley + pentable->tileSize);
}
printf("\n");
}
setlinecolor(BLACK);
rectangle(pentable->lx, pentable->ly, pentable->rx, pentable->ry); // 绘制笔刷存储区的边框
return pentable;
}
// 选取笔刷
void pickPen(ExMessage msg, tilegroup* have, tile* pen)
{
if (msg.message == WM_LBUTTONDOWN && msg.x > have->lx && msg.y > have->ly && msg.x < have->rx && msg.y < have->ry)
{
for (int i = 0; i < have->row; i++)
{
for (int j = 0; j < have->column; j++)
{
if (msg.x > have->pengroup[i][j].lx && msg.y > have->pengroup[i][j].ly && msg.x < have->pengroup[i][j].rx && msg.y < have->pengroup[i][j].ry)
{
pen->penimage = have->pengroup[i][j].penimage;
pen->level = have->pengroup[i][j].level;
printf("pick pen level = %d\n", pen->level);
}
}
}
if (pen->penimage != NULL)
{
putimage(600, 100, pen->penimage);
}
}
}
tile* initpen()
{
tile* pen = (tile*)malloc(sizeof(tile));
if (pen == NULL)
{
printf("分配笔刷失败,可能是内存不足\n");
exit(0);
}
pen->ismove = 0;
pen->lx = 0;
pen->ly = 0;
pen->rx = 0;
pen->ry = 0;
pen->tileSize = 0;
pen->penimage = new IMAGE(pen->tileSize, pen->tileSize);
return pen;
}
int main()
{
set* gamemap = initgamemap();
tilegroup* pentable = initpentable();
tile* pen = initpen();
ExMessage msg;
while (true)
{
while (peekmessage(&msg, EX_KEY || EX_MOUSE, true)) // 用 peekmessage()是因为无论有没有消息,都会执行后面的句子,这样可以持续刷新界面。
{
draw(msg, gamemap, pen);
save(msg, gamemap);
pickPen(msg, pentable, pen);
}
}
closegraph();
return 0;
}