本系列文章由zhmxy555编写,转载请注明出处。

http://blog.csdn.net/zhmxy555/article/details/7364697

作者:毛星云    邮箱: happylifemxy@qq.com

------------------------------------------------------------------------------------------------------------------------------

浅墨历时一年为游戏编程爱好者锻造的著作:《逐梦旅程:Windows游戏编程之从零开始》
如果你喜欢浅墨写的【Visual C++】游戏开发系列博客文章,那么你一定会爱上这本书。
这是浅墨专门为热爱游戏编程的朋友们写的入门级游戏编程宝典。
彩版样章试读PDF免费下载|配套源代码下载
书本维护页面|当当网|京东商城|亚马逊

------------------------------------------------------------------------------------------------------------------------------

地图是游戏元素里面不可缺少的一部分,要产生游戏地图,除了可以直接使用已经绘制好的位图外,对于一些画面不太复杂,并且具有重复性质的地图或场景,有一个比较好的解决方法,那就是利用地图拼接,将一小块一小块的小地图组合成较大的地图。

地图拼接的有点在于节省系统资源,因为一张大型的地图会占用比较多的内存空间,且加载速度较慢,如果游戏中使用了为数较多的大型地图,那么势必会降低程序运行时的性能,而且需要相当可观的内存空间。

接下来的几节笔记,我们将介绍有关地图拼接的概念,并学习利用不起眼的小地图堆砌出美妙无比的游戏地图的方法。

平面地图贴图

这种贴图方法相当直观,即利用一张张四方形的小地图块组成同样是四方形的大地图。下图就是一张由3种不同地图块组合而成的平面地图

我们可以看出,这张地图是由6*4张小地图块组成的,列方向是6张图块,行方向是4张图块。这张图里面共出现了3种不同的图块,这是因为程序会事先以数组来定义哪个位置要出现哪一种图块,使得拼接出来的地图能够符合要求,现假设图中3种不同的图块的编号分别为0,1,和2,那么可以用以下的这个一维数组来定义出上图中的地图

Int mapblock[24]={1,1,1,2,3,2           //第一列
1,1,2,2,2,3           //第二列
2,2,2,2,2,2           //第三列
2,2,2,2,2,1};          //第四列

将这个一维数组以行列的方式排列,可以看出每个数组元素对应图中哪个图块。要注意的是,我们使用的是一维数组,因此每个数组的每个元素的索引值是0,1,2,3……24。但是,由于程序里无论计算图块贴图的位置还是计算整张地图的长宽尺寸,都是以行列来换算的,所以需要将数组的索引值转换成相应的列编号和行编号。转换公式如下:

列编号=索引值/每列的图块个数(行数);

行编号=索引值%每列的图块个数(行数);

我们还需注意的是,列编号与行编号的起始值是从0开始算起,而一旦算出了列编号与行编号之后,便可以按照图块的宽与高来求出图块贴图的位置,下面是计算图块左上点贴图坐标的公式。

左上点X坐标=行编号*图块的宽度;

左上点Y坐标=列编号*图块的高度;

原理部分我们就介绍完了,下面我们来看一个实例:

#include "stdafx.h"
#include <stdio.h>//全局变量声明
HINSTANCE hInst;
HBITMAP fullmap;     //声明fullmap位图对象,在初始函数中完成的地图会存到这个位图中
HDC     mdc;     //行列数声明
const int rows = 8,cols = 8;//全局函数的声明
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
void                MyPaint(HDC hdc);//***WinMain函数,程序入口点函数**************************************
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR     lpCmdLine,int       nCmdShow)
{MSG msg;MyRegisterClass(hInstance);//运行初始化函数if (!InitInstance (hInstance, nCmdShow)) {return FALSE;}//消息循环while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;
}//****设计一个窗口类,类似填空题,使用窗口结构体*************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX); wcex.style          = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = (WNDPROC)WndProc;wcex.cbClsExtra     = 0;wcex.cbWndExtra        = 0;wcex.hInstance     = hInstance;wcex.hIcon         = NULL;wcex.hCursor        = NULL;wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground   = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName  = NULL;wcex.lpszClassName  = "canvas";wcex.hIconSm      = NULL;return RegisterClassEx(&wcex);
}//****初始化函数*************************************
// 声明地图数组,进行图块贴图,完成地图拼接
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{HWND hWnd;HDC hdc,bufdc;hInst = hInstance;hWnd = CreateWindow("canvas", "地图贴图" , WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!hWnd){return FALSE;}MoveWindow(hWnd,10,10,430,450,true);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);int mapIndex[rows*cols] = { 2,2,2,2,0,1,0,1,  //第1列0,2,2,0,0,0,1,1,  //第2列0,0,0,0,0,0,0,1,  //第3列2,0,0,0,0,0,2,2,  //第4列2,0,0,0,0,2,2,2,  //第5列2,0,0,0,2,2,0,0,  //第6列0,0,2,2,2,0,0,1,  //第7列0,0,2,0,0,0,1,1 };//第8列hdc = GetDC(hWnd);mdc = CreateCompatibleDC(hdc);bufdc = CreateCompatibleDC(hdc);fullmap = CreateCompatibleBitmap(hdc,cols*50,rows*50); //先建立fullmap为空白的位图,将其宽与高分别为“行数*图块宽”与“列数*图块高”。
    SelectObject(mdc, fullmap);HBITMAP map[3];char filename[20] = "";int rowNum,colNum;int i,x,y;//加载各块位图for(i=0;i<3;i++)  //利用循环转换图文文件名,取出各个图块存与“map[i]”中。图块文件名为“map0.bmp”和“map1.bmp”等。{sprintf(filename,"map%d.bmp",i);map[i] = (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,50,50,LR_LOADFROMFILE);}//按照mapIndex数组中的定义取出对应图块,进行地图拼接 for (i=0;i<rows*cols;i++){SelectObject(bufdc,map[mapIndex[i]]);  //根据mapIndex[i]中的代号选取对应的图块到bufdc中。代号为“0”则取“map[0]”,以此类推rowNum = i / cols;   //求列编号colNum = i % cols;   //―求行编号x = colNum * 50;     //―求贴图X坐标 y = rowNum * 50;     //―求贴图Y坐标BitBlt(mdc,x,y,50,50,bufdc,0,0,SRCCOPY);  //在mdc上进行贴图}MyPaint(hdc);   //当上面代码的循环完成在mdc上的图块贴图之后,fullmap便是拼接出来的地图,此时再调用MyPaint()函数进行窗口贴图。ReleaseDC(hWnd,hdc);DeleteDC(bufdc);return TRUE;
}//****自定义绘图函数*********************************
void MyPaint(HDC hdc)
{//贴上拼接后的组合地图SelectObject(mdc,fullmap);BitBlt(hdc,10,10,cols*50,rows*50,mdc,0,0,SRCCOPY);//在窗口中贴上拼接后的组合地图,整个地图的贴图大小按照拼接地图的行数、列数和图块的宽高来决定。
}//****消息处理函数***********************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;switch (message){case WM_PAINT:                     //窗口重绘消息  hdc = BeginPaint(hWnd, &ps);MyPaint(hdc);EndPaint(hWnd, &ps);break;case WM_DESTROY:                  //窗口结束消息DeleteDC(mdc);DeleteObject(fullmap);PostQuitMessage(0);break;default:                           //其他消息return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}

我们需要把几幅位图文件放到工程文件夹下,有需要这个程序源码朋友可以留下邮箱,我会发给你。

运行结果如下图:

这个范例具有一定的灵活性。只要更改常数中的列数与行数的值,并重新定义mapIndex[]数组中的值,便可以组合出大小尺寸及内容不尽相同的平面地图来。

笔记九到这里就结束了。

本节源代码请点击这里下载:【Visual C++】Code_Note_9

(本节源码上传到CSDN下载频道出bug了,最后只好转到别的地方。现已经恢复正常)

感谢一直支持【Visual C++】游戏开发笔记系列专栏的朋友们,也请大家继续关注我的博客,我一有空就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。

精通游戏开发的路还很长很长,非常希望能和大家一起交流,共同学习和进步。

大家看过后觉得有启发的话可以顶一下这篇文章,让更多的朋友有机会看到它。也希望大家可以多留言来和我探讨编程相关的问题。

最后,谢谢大家一直的支持~~~

The end

------------------------------------------------------------------------------------------------------------------------------

浅墨历时一年为游戏编程爱好者锻造的著作:《逐梦旅程:Windows游戏编程之从零开始》
如果你喜欢浅墨写的【Visual C++】游戏开发系列博客文章,那么你一定会爱上这本书。
这是浅墨专门为热爱游戏编程的朋友们写的入门级游戏编程宝典。
彩版样章试读PDF免费下载|配套源代码下载
书本维护页面|当当网|京东商城|亚马逊

------------------------------------------------------------------------------------------------------------------------------

【Visual C++】游戏开发笔记之九 游戏地图制作(一)平面地图贴图相关推荐

  1. Visual C++ 游戏开发笔记 纹理映射技术(一)

                 一.引言 江山如此多娇,风景如画.万物都有其独特的特点.真实世界中的物体,在计算机三维世界中如果单单用各种各样的几何体以及顶点坐标,顶点颜色来模拟的话,往往缺乏生机,往往 ...

  2. 【Visual C++】游戏开发笔记十九 DirectX与OpenGL的博弈

    From: http://blog.csdn.net/zhmxy555/article/details/7522960 本系列文章由zhmxy555(毛星云)编写,转载请注明出处. http://bl ...

  3. 【Visual C 】游戏开发笔记十九 DirectX与OpenGL的博弈

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  4. 【Visual C++】游戏开发笔记四十一 浅墨DirectX教程之九 为三维世界添彩:纹理映射技术(一)...

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8523341 作者:毛星云(浅墨 ...

  5. 【Visual C++】游戏开发笔记三十九 浅墨DirectX教程之七 他山之石:几种几何体的快捷绘制法

    本篇文章里,我们对Direct3D之中几种几何体的简洁绘制方法进行了详细的剖析,最后依旧是提供文章配套的详细注释的demo源代码的欣赏,并在文章末尾提供了源代码下载.(这标题有些歧义的,这个几种是修饰 ...

  6. [置顶]       【Visual C++】游戏开发笔记之一——API函数、DirectX的关键系统...

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. http://blog.csdn.net/zhmxy555/article/details/7318264 作者:毛星云    邮箱: h ...

  7. 【Visual C++】游戏开发笔记四十六 浅墨DirectX教程十四 模板测试与镜面特效专场

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处.   文章链接: http://blog.csdn.net/zhmxy555/article/details/8632184 作者:毛星云( ...

  8. 【Visual C++】游戏开发笔记之一——API函数、DirectX的关键系统

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/7318264 作者:毛星云(浅墨)  ...

  9. 【Visual C++】游戏开发笔记四十 浅墨DirectX教程之八 绘制真实质感的三维世界:光照与材质专场...

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 作者:毛星云(浅墨)    邮箱: happylifemxy@163.com 本篇文章里,我们对Direct3D之中固定功能流水线中的3D ...

最新文章

  1. 3dmax2020安装失败原因及解决方法_电伴热带安装维护,线路断路器跳闸的原因及解决方法...
  2. SAP HANA是什么
  3. jQuery 的 slideUp 和 slideDown 下拉卷动问题
  4. php正则匹配js中变量_PHP正则表达式核心技术 第4节 php查找匹配函数使用心得
  5. spring-boot-mybatis
  6. python主函数入口_Python 入口函数(菜鸟入门)
  7. css3-13 如何改变文本框的轮廓颜色
  8. [css] css怎么更改表单的单选框或下拉框的默认样式?
  9. Android: 解决动画完成后位置恢复到初始位置的问题
  10. YII2 搭建redis拓展(教程)
  11. Linux 远程登录telnet和ssh
  12. 使用sshfs挂载服务器文件系统,用curlftpfs挂载FTP服务器
  13. 基恩士光纤传感器怎么恢复出厂设置_光纤故障排查测试必备神器
  14. 用正则彻底去除HTML\CSS\script代码
  15. 硬盘格式化后数据能不能恢复,硬盘格式化数据怎么恢复
  16. QQ是成年人的“不老神仙水”
  17. Linux学习手册大全
  18. ae 导出html5,AE脚本-导出json格式的Web动画工具 Bodymovin v5.7.0 + 使用教程
  19. 如何选择最合适的服务器?服务器配置方案
  20. mysql sending data 耗时_mysql查询语句出现sending data耗时解决

热门文章

  1. (Yuni)2021-02-16常见的DOS命令使用
  2. Spire.XLS:一款Excel处理神器(2)
  3. 与其被生活逼,不如被自己逼
  4. [蓝桥杯]蓝肽子序列(c++详解)
  5. 移动端字体显示大小和css设置大小的不一致解决方案
  6. 【100%通过率】华为OD机试真题 Python 实现【完美走位】【2022.11 Q4新题】
  7. JS--JS运行三部曲--渡一教育(视频笔记)
  8. 实现JSON在线美化(格式化)、JSON转CSV、CSV转XML工具-toolfk程序员工具网
  9. 朋友圈大数据:你的朋友圈出卖了你,大数据就是这么给力!!!
  10. Pdf.js 解决电子印章问题(最新)