CocosCreator 应用智能地表实现2D战争迷雾

在最近项目方案中,需要在2d透视地图中实现一种地宫探索的表现效果:

暂时能想到可以尝试实现的方法有:智能地表、法线光照和shader来实现类似的效果;法线光照和shader实现下期再讲,本文主要介绍一下智能地表的实现方法。

一、原理介绍

智能地表最早出现在魔兽争霸的地图编辑器中,是高效拼接地图地表的一种地块算法;如果没有使用智能地表,那拼接地形时必须每个地块都对齐比缘:

目前网络上有详细的原理和实现方式,所以这里就简单介绍一下:把相关联的地表块按下图编号,在拼接时按公式计算出需要替换和补齐的编号地块(地图摆放的顺序没关系,只要与地块编号对应就可以)

计算方法很简单:以(4,8,1,2)四个格子拼出的地形为起始单位(如下图),简称原型组;

image

每次点击指定地图格子,都以原型组平铺到地图上,如果和原有地表有重叠,则将原型组地表格子编号与原地表重叠的格子编号,得到的新编号后,到拼接表中找到对应的地表格子替换就完成了;

如上图所示:

  • 第一次点击: 地块8重叠 = 地块8 + 地块4 = 地块12
    地块2重叠 = 地块2 + 地块1 = 地块3

  • 第二次点击: 地块8重叠 = 地块8 + 地块1 = 地块9

  • 第三次点击: 地块12重叠 = 地块12 + 地块1 = 地块13
    地块9重叠 = 地块9 + 地块2 = 地块11
    地块4重叠 = 地块4 + 地块8 = 地块12

但这和战争迷雾有什么关系呢?其实是有的,拼地表是在空地图上补齐地块,如果在全填满的地图上吧地表块的区域置空,再拼接不就是在地图上镂空吗?

二、设计实现

迷雾(智能地表)拼图的图块顺序设置,可以看出来,和上文地表块中土地部分对应下图地表块是镂空的(自已画的测试图,没有做渐变):

按照上述方法实现功能后,游戏内最终表现效果如下:

实际实现上稍微做了一点优化,和前文的实现稍有不同,前文是以直接把地块编号的对应关系记录下来,省去了变换编号的重复计算,最终项目中代码实现如下:

    // 根据索引刷新迷雾
    public changeMistyShow(index: number) {
        //1. 获取周边9块贴片的索引
        let idxGrid = [
            -1, -1, -1,
            -1, -1, -1,
            -1, -1, -1,
        ]
        let row = Math.floor(index / this._mapCol)      // 行
        let col = index % this._mapCol                  // 列
        for (let i = 0; i < 3; i++)
            for (let j = 0; j < 3; j++) {      // todo: 暂时不考虑边缘情况
                idxGrid[i * 3 + j] = (row - 1 + i) * this._mapCol + (col - 1 + j)
            }
        //2. 根据获取贴片的拼接索引ID获取对应变化的拼接索引ID
        let sub = -1
        let id = -1
        let frameGrid = [1, 3, 2, 5, 15, 10, 4, 12, 8]
        for (let i = 0; i < 3; i++)
            for (let j = 0; j < 3; j++) {
                id = (i * 3) + j
                let item = this._mapMistys[idxGrid[id]]
                if (item && (item.imgIndex > -1)) {
                    sub = (item.imgIndex >= 0) ? item.imgIndex : frameGrid[id]
                    sub = this._getChangeFrameIndex(frameGrid[id], sub)
                    item.changeImg(sub, this._cellScale)
                    // 增加到开启列表
                    if (sub < 0)
                        this._addToOpenMistys(item.index)
                }
            }
    }

    private _getChangeFrameIndex(changeIdx: number, currentIdx: number): number {
        let retIdx = (changeIdx === currentIdx) ? changeIdx : (changeIdx | currentIdx)
        if ((retIdx < 0) || (retIdx >= 15)) retIdx = -1
        return retIdx
    }

欢迎扫码关注我的公众号,获取源码示例、插件代码,以及更多Cocos干货:

image

4赞

膜拜大佬!!

好帖,插眼

好帖,很赞…