美文网首页
Pixi.js 渲染 Tilemap

Pixi.js 渲染 Tilemap

作者: JetLu | 来源:发表于2018-07-04 18:00 被阅读326次

    源码
    预览

    游戏开发中或多或少都有接触过Tilemap,在Tiled编辑器里编辑好地图之后,导出数据,然后在游戏引擎(Cocos...)里就可以直接使用了,确实很方便。

    由于Pixi.js自身并不支持Tilemap的解析渲染,所以我一直在尝试了解背后的机制。最初能想到的实现就是,在一个Container里放一堆Sprite把地图拼出来,Pixi.jsTexture支持以一个BaseTexture为基础,分块读取,所以实现一个也还可以。代码差不多就是这样:

    const rect = new PIXI.Rectangle(0, 0, this.square, this.square)
    for (let i = 0, sn = 0; i < this.size.height; i++) {
        for (let j = 0; j < this.size.width; j++) {
            sn = this.data[i * this.size.width + j]
            if (!sn) continue
            sn--
            rect.x = (sn % this.tilesets.columns) * this.square
            rect.y = (~~(sn / this.tilesets.columns)) * this.square
            // 分块读取
            const tile = new PIXI.Sprite(new PIXI.Texture(this.tilesheet, rect))
            tile.position.set(j * this.square, i * this.square)
            tile.anchor.set(.5)
            this.addChild(tile)
        }
    }
    

    一天看到Pixi.js的作者在Codepen上的代码后,于是有了今天这篇文章。

    实现思路

    上面是v5的实现,v4实现起来略麻烦。

    利用shader去渲染Tilemap。我们从Tilemap导出的JSON数据可以知道,主要的数据其实就是地图元素(瓦片)在图集中的索引。如何在着色器里拿到索引数据呢?

    如果你看了上面Codepen的代码,或许你就知道了:

    const bitmap = new PIXI.Graphics()
    
    for (let i = 0; i < layer.height; i++) {
        for (let j = 0; j < layer.width; j++) {
            const
                index = layer.data[i * layer.width + j] - 1,
                column = this.mapData.tilesets[0].columns,
                x = index % column,
                y = Math.floor(index / column)
            bitmap.beginFill((x << 16) + (y << 8), index !== -1 ? 1 : 0)
            bitmap.drawRect(j, i, 1, 1)
            bitmap.endFill()
        }
    }
    
    // 生成纹理后面会传入纹理单元 一定要设置:PIXI.SCALE_MODES.NEAREST
    core.renderer.generateTexture(bitmap, PIXI.SCALE_MODES.NEAREST)
    

    创建一个bitmap,把地图的索引数据变成颜色值储存在这个bitmap里。

    还需要一段着色器代码:

    
    precision mediump float;
    
    uniform sampler2D tilesheet, bitmap;
    uniform float tileSize, tileColumn;
    uniform vec2 tilesheetSize;
    varying vec2 vTextureCoord, vVertexPosition;
    
    void main() {
        vec4 color = floor(texture2D(bitmap, vTextureCoord) * 255.0);
    
        if (color.a == 0.0) discard;
    
        vec2 coord = (vec2(color.r, color.g) * tileSize
            + mod(vVertexPosition, tileSize)) / tilesheetSize;
    
        gl_FragColor = texture2D(tilesheet, coord);
    }
    

    这里还有一些Pixi.js的操作,我就不写出来了。弄明白原理,就行。感觉和法线贴图是一个道理,虽然我并没有研究过。主要就是把索引数据变成纹理上传到GPU,然后在着色器代码里读取出来。

    相关文章

      网友评论

          本文标题:Pixi.js 渲染 Tilemap

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