游戏的卷轴效果主要有两种形式,一种是将游戏分为若干个场景的页面卷轴,比如FC上的洛克人,当人物走到边缘时,就会切换整个场景;一种就是魂斗罗式的那种均匀平铺的卷轴,这种卷动更为平滑。因为我要用在2.5D显示引擎中,只能选择第二种卷轴技术——均匀tile卷轴。
1. 卷轴要卷动哪些东西
首先要清楚卷动的是什么东西,比如下面的一个KOK1的截图:
这是一个典型的2.5D游戏界面,这个界面上的所有元素全都是由位图所组成的,但是不难分析出实际要卷动的只有地面的位图。因为传送门和柱子、树等等都是可以遮挡住人的,即渲染顺序是:
(1) 根据世界坐标卷动的地面贴图
(2) 玩家单位、建筑、环境元素单位以从上至下的顺序渲染,这样就会产生2.5D效果,即近景遮挡住远景。
2. 均匀平铺显示引擎的设计与实现
由上图的地板不难看出,其实这些地面是由一小块一小块拼接而成的,这样可以使位图得以重用,就像红警95的地图编辑器一样,一个地形可以在地图中反复出现。所以我们实际要有一个位图文件来存放这些一块一块的地板,比如我随便画了这个(第一个是我自己用画笔画的,后面两个是截图截的,效果都一般,可见优秀美工的重要性),有三块86*40的地板:
然后在程序中,我们需要创建一个显示表面的数组来分别存放这三个地板。
LPDIRECTDRAWSURFACE7 lpddsFloor[3];
接着,定义一个int数组来存放地图中地形的索引,比如我打算要创建一个3×3块地板的地图,则:
int map[3*3] = { 0, 0, 0, 1, 1, 1, 2, 2, 2 };
这样这个地图等于是第一行都是第0块地板,第二行都是第1块地板,第三行都是第2块地板。
现在就要创建世界表面,把世界加载到一个单独的大表面上:
lpddsMap = CreateSurface(MAP_WIDTH*TILE_WIDTH, MAP_HEIGHT*TILE_HEIGHT, 0); for (int y = 0; y < MAP_HEIGHT; ++y) { for (int x = 0; x < MAP_WIDTH; ++x) { RECT dest_rect = { x * TILE_WIDTH, y * TILE_HEIGHT, (x+1) * TILE_WIDTH, (y+1) * TILE_HEIGHT }; lpddsMap->Blt(&dest_rect, lpddsFloor[map[x + MAP_WIDTH * y]], NULL, DDBLT_WAIT, NULL); } }
现在所有的准备工作都做好了,就要在显示器显示的每一帧,根据视窗在世界中的坐标来Blt相关的区域到离屏表面,并且根据玩家的输入来调整视窗在世界中的坐标:
if (KEY_DOWN(VK_LEFT)) screen_x = screen_x > 5 ? screen_x - 5 : screen_x; if (KEY_DOWN(VK_UP)) screen_y = screen_y > 5 ? screen_y - 5 : screen_y; if (KEY_DOWN(VK_RIGHT)) screen_x = screen_x < MAP_WIDTH*TILE_WIDTH - SCREEN_WIDTH ? screen_x + 5 : screen_x; if (KEY_DOWN(VK_DOWN)) screen_y = screen_y < MAP_HEIGHT*TILE_HEIGHT - SCREEN_HEIGHT ? screen_y + 5 : screen_y; RECT rect = { screen_x, screen_y, screen_x + SCREEN_WIDTH, screen_y + SCREEN_HEIGHT}; lpddsoffscreen->Blt(NULL, lpddsMap, &rect, DDBLT_WAIT, NULL);
3. 放上一个截图,是完成的效果。