Pixi.js 渲染 Tilemap

源碼 預覽git

遊戲開發中或多或少都有接觸過Tilemap,在Tiled編輯器裏編輯好地圖以後,導出數據,而後在遊戲引擎(Cocos...)裏就能夠直接使用了,確實很方便。編輯器

因爲Pixi.js自身並不支持Tilemap的解析渲染,因此我一直在嘗試瞭解背後的機制。最初能想到的實現就是,在一個Container裏放一堆Sprite把地圖拼出來,Pixi.jsTexture支持以一個BaseTexture爲基礎,分塊讀取,因此實現一個也還能夠。代碼差很少就是這樣:this

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上的代碼後,因而有了今天這篇文章。code

實現思路

上面是v5的實現,v4實現起來略麻煩。orm

利用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裏。ci

還須要一段着色器代碼:遊戲開發

precision highp float;

uniform sampler2D tilesheet, bitmap;
uniform float tileSize, tileColumn;
uniform vec2 tilesheetSize, mapSize;
varying vec2 vTextureCoord, vVertexPosition;

void main() {
    vec4 color = texture2D(bitmap, vTextureCoord) * 255.0;

    if (color.a == 0.0) discard;

    vec2 coord = (vec2(color.r, color.g) * tileSize
        + mod(vTextureCoord * mapSize, tileSize)) / tilesheetSize;

    gl_FragColor = texture2D(tilesheet, coord);
}

這裏還有一些Pixi.js的操做,我就不寫出來了。弄明白原理,就行。感受和法線貼圖是一個道理,雖然我並無研究過。主要就是把索引數據變成紋理上傳到GPU,而後在着色器代碼裏讀取出來。開發

相關文章
相關標籤/搜索