当前位置:编程学习 > VC++ >>

(Visual C++)游戏开发笔记之九:游戏地图制作(一)平面地图贴图

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

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

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

 

平面地图贴图

 

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

 \


 

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


[cpp] view plaincopyprint?
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};          //第四列 
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坐标=列编号*图块的高度;

 

 

 

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

 

 

[cpp] view plaincopyprint?
#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列  
 

补充:软件开发 , Vc ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,