美文网首页
自动拼接多地形地图的一种做法

自动拼接多地形地图的一种做法

作者: rekcah1986 | 来源:发表于2018-05-04 17:07 被阅读367次

最近要做一套自动拼接地图,网上看了各种实现方法,主要是rpgmaker和tile map的实现,发现要支持多种地形的话,并不是一件容易的事。主要是不同地形之间都有可能相接,这样就需要出多套过渡素材,比如草地、土地、雪地、水面四种地形,过渡的素材需要考虑到任意组合,当地形增多的时候图量就会成几何倍数增加。
后来我看了http://gad.qq.com/article/detail/16530的实现,它是只支持两种地形的,但是实现方法讲解的很清晰,我在其基础上扩展了一下,支持了多种地形。
和其他算法不同的是,我用的是带透明缺口的图片,即

tiles.png
每一行是16种形状,6种颜色对应不同的地形,所以当多种地形拼接的时候,则是由多张小图片组合在一起绘制的(避免效率问题,可以在程序里合并在一张Texture上,即人为的生成过渡素材)
地图画出来是这样的:
image.png
图虽然比较恶心,但是基本实现了多地形的问题,而且美术素材较少。

PS:【4,3】处有一个交叉地形的bug,可以在算法里处理掉,我就不写了。
代码的话,只贴一个MainScene吧,用"cocos new -l lua"命令新建demo,然后替换掉里面的就可以了。

local MainScene = class("MainScene", cc.load("mvc").ViewBase)

function MainScene:onCreate()
    self.tileWidth = 32     -- 图块宽
    self.tileHeight = 32    -- 图块高
    self.mapColumn = 20     -- 地图列
    self.mapRow = 14        -- 地图行
    self.mapData = nil      -- 地图数据
    self.selectedTerrainType = 0 -- 当前选择的地形
    -- 背景层
    self.bgLayer = cc.LayerColor:create(cc.c3b(128, 128, 0))
        :addTo(self)
    -- 地图显示层
    self.mapLayer = cc.LayerColor:create()
        :setIgnoreAnchorPointForPosition(false)
        :setContentSize(self.tileWidth * self.mapColumn, self.tileHeight * self.mapRow)
        :move(display.center)
        :onTouch(handler(self, self.onTouch))
        :addTo(self)
    -- 光标
    self.highlight = cc.Sprite:create("res/highlight.png")
        :setLocalZOrder(999)
        :move(0, 0)
        :addTo(self.mapLayer)
    -- tile素材
    local file = "res/tiles.png"
    self.tileTexture = cc.Director:getInstance():getTextureCache():addImage(file)
    -- 地形类型选择按钮
    local btns = ccui.RadioButtonGroup:create()
        :addTo(self)
    btns:addEventListener(function(btn, index)
        self.selectedTerrainType = index
        self.highlight:setTexture(btn.imageFile)
    end)
    for i=1,self.tileTexture:getContentSize().height / self.tileHeight do
        local file = "res/radio_select_" .. (i - 1) .. ".png"
        local btn = ccui.RadioButton:create(file, file)
            :move(i * 32 + 200, 60)
            :addTo(self)
        btn.imageFile = file
        btns:addRadioButton(btn)
    end
    btns:setSelectedButton(1)
    -- 初始化
    self:initMap()
end

-- 初始化地图数据
--[[
    value格式为{1,2,3,4}分别对应四个角的tile类型,即:
                                                    4 3
                                                    2 1
]]
function MainScene:initMap(value)
    self.mapData = {}
    self.mapTiles = {}
    value = value or {0, 0, 0, 0}
    for i=0,self.mapRow-1 do
        self.mapData[i] = {}
        self.mapTiles[i] = {}
        for j=0,self.mapColumn-1 do
            self.mapData[i][j] = clone(value)
        end
    end
    self:updateMap()
end

-- 根据传进来的data:{1,2,3,4}生成对应的地块图,是由1~4张小图片组合起来的
-- TODO 拼接完后可以生成Texture缓存起来,可以优化绘制效率
function MainScene:getTile(data)
    local tmp = data
    assert(#tmp == 4)
    local foos = {}
    for i,terrainType in pairs(tmp) do
        local cornerType = math.pow(2, 4 - i) -- 2的(4-i)次方
        foos[terrainType] = (foos[terrainType] or 0) + cornerType
    end
    local ret = cc.Node:create()
    for terrainType,cornerType in pairs(foos) do
        local x = cornerType * self.tileWidth
        local y = terrainType * self.tileHeight
        local tile = cc.Sprite:createWithTexture(self.tileTexture, 
                    cc.rect(x, y, self.tileWidth, self.tileHeight))
            :setAnchorPoint(0, 0)
            :addTo(ret)
    end
    return ret
end

-- 更新地图
function MainScene:updateMap(x1, y1, x2, y2)
    x1 = math.max(x1 or 0, 0)
    y1 = math.max(y1 or 0, 0)
    x2 = math.min(x2 or self.mapColumn-1, self.mapColumn-1)
    y2 = math.min(y2 or self.mapRow-1, self.mapRow-1)
    for i=y1,y2 do
        for j=x1,x2 do
            if(self.mapTiles[i][j]) then
                self.mapTiles[i][j]:removeFromParent()
            end
            self.mapTiles[i][j] = self:getTile(self.mapData[i][j])
                :move(j * self.tileWidth, (self.mapRow - i - 1) * self.tileHeight)
                :addTo(self.mapLayer)
        end
    end
end

-- 处理点击事件
function MainScene:onTouch(event)
    local pos = self.mapLayer:convertToNodeSpace(event)
    local size = self.mapLayer:getContentSize()
    local x = math.floor((pos.x + self.tileWidth / 2) / self.tileWidth)
    local y = math.floor((pos.y + self.tileHeight / 2) / self.tileHeight)
    if(x < 0 or y < 0 or x > self.mapColumn or y > self.mapRow) then
        return false
    end
    self.highlight:move(x * self.tileWidth, y * self.tileHeight)
    y = self.mapRow - y
    local POS = {
            {y-1, x-1},
            {y-1, x},
            {y, x-1},
            {y, x}
        }
    for i,v in pairs(POS) do
        local r, c = v[1], v[2]
        if(self.mapData[r] and self.mapData[r][c]) then
            self.mapData[r][c][i] = self.selectedTerrainType
        end
    end
    self:updateMap(x-1, y-1, x, y)
    return true
end

return MainScene

编译好的exe放网盘里了,里面还有res和src
链接: https://pan.baidu.com/s/1G0IIuCJ8L1J63rAAMMN7nA 密码: 94ti

相关文章

  • 自动拼接多地形地图的一种做法

    最近要做一套自动拼接地图,网上看了各种实现方法,主要是rpgmaker和tile map的实现,发现要支持多种地形...

  • worldcreator Special:导出讲解10

    在这里你可以调整所有与地形表面相关的设置。 地图类型让您选择要导出的地图类型。地形高度图包含地形高程数据(高度贴图...

  • 地图软件缩小与放大的原理

    实现地图放大与缩小的功能是基于瓦片地图的拼接与显示的。 TMS是tile map service的缩写,是一种瓦片...

  • 地形要点

    地形是作战的关键,除了提前看地图,指挥作战的将领还需要亲自去查看地形,然后分析。地图只是参考物,实地考察才能具体了...

  • 打造地图拼接利器(五)地图采集与拼接

    获取到经纬度范围后,我们需要计算出瓦片的范围。 本文涉及的地图瓦片都以左上角为原点开始编号的,从左至右为 x 轴,...

  • 5-1 在GMT中使用高精度地形数据SRTM3

    在GMT中,最常用的地图就是地形图,本文要讲的就是高精度地形图如何在Windows中使用。 高精度地形图简介 et...

  • 手机、平板无线投屏液晶拼接大屏

    手机、平板无线投屏液晶拼接大屏 今天跟大家介绍一种无线投屏屏幕拼接方案,主要应用在拼接屏的多屏显示上。拼接屏本身就...

  • tif 高度图

    Building Worlds In Unreal 学习笔记——15-19 高度图地形专题&地形自动材质专题[ht...

  • 登山常识大科普!

    山野寻路,无论是电子地图还是纸质地图,都离不开等高线图。 识别等高线图是一种简单易懂的登山知识,掌握后可以辨识地形...

  • 清除图片缓存

    获取缓存大小 1.找到沙盒路径 2.拼接路径 拼接路径会自动加/,拼接字符串不会//拼接路径NSString *f...

网友评论

      本文标题:自动拼接多地形地图的一种做法

      本文链接:https://www.haomeiwen.com/subject/qnodrftx.html