首屏渲染 自定义启动流程 启动速度

思路:引擎作为分包加载 并 自行渲染首屏

支持的引擎版本:2.x

自定义引擎:
由于微信首次创建的是主canvas,后面创建的都是离屏 canvas,所以需要自定义一下引擎,点击编辑器打开文件builtin/adapters/platforms/wechat/wrapper/builtin/Canvas.js:修改下面代码

let first = true
export default function Canvas() {
 //const canvas = wx.createCanvas()
 const canvas = first ? wx.__first__canvas ? wx.__first__canvas : wx.createCanvas() : wx.createCanvas()
 first = false

然后重新构建。


1.引擎分包

修改game.json文件,新增engine文件夹作为分包:

"subpackages": [
        {
            "name":"engine",
            "root":"engine/"
        }
    ]

移动: 除assets、subpackages、game.json、project.config.json四个文件外,其他全部移动到engine文件夹下。

拷贝: 将assets文件夹拷贝到engine,然后删除engine/assets里所有的import、native文件夹和config.json文件,只剩下index.js文件。

引擎分包完成,接下来加载分包和自行渲染首屏。


2.首屏渲染:

根目录新增game.js、first-screen.js、first-screen.png文件

game.js代码:(游戏入口)

// 1.渲染首屏

wx.__first__canvas = wx.createCanvas();

const first_scene = require("./first-screen.js");

first_scene.drawImg("first-screen.png");

let inter = setInterval(() => {

    requestAnimationFrame(()=>{

        first_scene.drawImg("first-screen.png");

    })

}, 1);

// 2.加载引擎分包

function loadEngine(sub_name) {

  if (wx.loadSubpackage) {

    _load(sub_name).then((result) => {

      if (!result) {

        loadEngine(sub_name);

      }

    });

  } else {

    require(sub_name + '/game.js');

  }

}

function _load(sub_name) {

  return new Promise((resolve, reject) => {

    const t = new Date().getTime();

    const loadTask = wx.loadSubpackage({

      name: sub_name,

      success: function (res) {

          clearInterval(inter)

        console.log("引擎包加载完毕", new Date().getTime() - t, "ms");

        resolve(true);

      },

      fail: function (res) {

        console.log("引擎包加载失败", new Date().getTime() - t, "ms");

        resolve(false);

      }

    });

    loadTask.onProgressUpdate(res => {

    });

  });

}

loadEngine("engine");

first-screen.js代码:(一个简单的 WebGL 渲染图片的代码)

// Vertex shader program
var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'attribute vec2 a_TexCoord;\n' +
    'varying vec2 v_TexCoord;\n' +
    'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '  v_TexCoord = a_TexCoord;\n' +
    '}\n';

// Fragment shader program
var FSHADER_SOURCE =
    '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform sampler2D u_Sampler;\n' +
    'varying vec2 v_TexCoord;\n' +
    'void main() {\n' +
    '  gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
    '}\n';

/**
 * Create a program object and make current
 * @param gl GL context
 * @param vshader a vertex shader program (string)
 * @param fshader a fragment shader program (string)
 * @return true, if the program object was created and successfully made current 
 */
function initShaders(gl, vshader, fshader) {
    var program = createProgram(gl, vshader, fshader);
    if (!program) {
        console.log('Failed to create program');
        return false;
    }

    gl.useProgram(program);
    gl.program = program;

    return true;
}

/**
 * Create the linked program object
 * @param gl GL context
 * @param vshader a vertex shader program (string)
 * @param fshader a fragment shader program (string)
 * @return created program object, or null if the creation has failed
 */
function createProgram(gl, vshader, fshader) {
    // Create shader object
    var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
    var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
    if (!vertexShader || !fragmentShader) {
        return null;
    }

    // Create a program object
    var program = gl.createProgram();
    if (!program) {
        return null;
    }

    // Attach the shader objects
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    // Link the program object
    gl.linkProgram(program);

    // Check the result of linking
    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (!linked) {
        var error = gl.getProgramInfoLog(program);
        console.log('Failed to link program: ' + error);
        gl.deleteProgram(program);
        gl.deleteShader(fragmentShader);
        gl.deleteShader(vertexShader);
        return null;
    }
    return program;
}

/**
 * Create a shader object
 * @param gl GL context
 * @param type the type of the shader object to be created
 * @param source shader program (string)
 * @return created shader object, or null if the creation has failed.
 */
function loadShader(gl, type, source) {
    // Create shader object
    var shader = gl.createShader(type);
    if (shader == null) {
        console.log('unable to create shader');
        return null;
    }

    // Set the shader program
    gl.shaderSource(shader, source);

    // Compile the shader
    gl.compileShader(shader);

    // Check the result of compilation
    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (!compiled) {
        var error = gl.getShaderInfoLog(shader);
        console.log('Failed to compile shader: ' + error);
        gl.deleteShader(shader);
        return null;
    }

    return shader;
}

function initVertexBuffers(gl, vertices) {
    var verticesTexCoords = vertices || new Float32Array([
        // Vertex coordinates, texture coordinate
        -1, 1, 0.0, 1.0,
        -1, -1, 0.0, 0.0,
        1, 1, 1.0, 1.0,
        1, -1, 1.0, 0.0,
    ]);

    var n = 4; // The number of vertices

    // Create the buffer object
    var vertexTexCoordBuffer = gl.createBuffer();
    if (!vertexTexCoordBuffer) {
        console.log('Failed to create the buffer object');
        return -1;
    }

    // Bind the buffer object to target
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);

    var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
    //Get the storage location of a_Position, assign and enable buffer
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    if (a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return -1;
    }
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
    gl.enableVertexAttribArray(a_Position);  // Enable the assignment of the buffer object

    // Get the storage location of a_TexCoord
    var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
    if (a_TexCoord < 0) {
        console.log('Failed to get the storage location of a_TexCoord');
        return -1;
    }
    // Assign the buffer object to a_TexCoord variable
    gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
    gl.enableVertexAttribArray(a_TexCoord);  // Enable the assignment of the buffer object

    return n;
}

function initTextures(gl, n, imgPath) {
    var texture = gl.createTexture();   // Create a texture object
    if (!texture) {
        console.log('Failed to create the texture object');
        return false;
    }

    // Get the storage location of u_Sampler
    var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
    if (!u_Sampler) {
        console.log('Failed to get the storage location of u_Sampler');
        return false;
    }
    var image = wx.createImage();  // Create the image object
    if (!image) {
        console.log('Failed to create the image object');
        return false;
    }
    // Register the event handler to be called on loading an image
    image.onload = function () { loadTexture(gl, n, texture, u_Sampler, image); };
    // Tell the browser to load an image
    image.src = imgPath;
    return true;
}

function loadTexture(gl, n, texture, u_Sampler, image) {
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // Flip the image's y axis
    // Enable texture unit0
    gl.activeTexture(gl.TEXTURE0);
    // Bind the texture object to the target
    gl.bindTexture(gl.TEXTURE_2D, texture);

    // Set the texture parameters
    // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    // Set the texture image
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);

    // Set the texture unit 0 to the sampler
    gl.uniform1i(u_Sampler, 0);

    gl.clear(gl.COLOR_BUFFER_BIT);   // Clear <canvas>

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // Draw the rectangle
}

function drawImg(imgPath) {
    const vertices = new Float32Array([
        -1, 1, 0.0, 1.0,
        -1, -1, 0.0, 0.0,
        1, 1, 1.0, 1.0,
        1, -1, 1.0, 0.0,
    ]);
    // Retrieve <canvas> element
    // var canvas = document.getElementById('webgl');

    // Get the rendering context for WebGL
    // var gl = getWebGLContext(canvas);
    const gl = wx.__first__canvas.getContext("webgl");
    if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
    }

    // Initialize shaders
    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('Failed to intialize shaders.');
        return;
    }

    // Set the vertex information
    var n = initVertexBuffers(gl, vertices);
    if (n < 0) {
        console.log('Failed to set the vertex information');
        return;
    }

    // Specify the color for clearing <canvas>
    gl.clearColor(1.0, 1.0, 1.0, 1.0);

    // Set texture
    if (!initTextures(gl, n, imgPath)) {
        console.log('Failed to intialize the texture.');
        return;
    }
}

exports.drawImg = drawImg;

first-screen.png图片(随便找一张启动图)


参考图

1
2

2赞

3.x or 3.4版本可以用吗

3.x用不着,构建的时候替换插屏即可

我看你这个是实现进游戏就出现一张图片吧 也就是在游戏第一帧还没出来的时候出现这个图片 3.x替换插屏是不能的


3.3之前可以参考这个方案,3.4 已经有集成 firstscreen 方案了

:grinning:首包只有10k

2.4.11 版本 用这个后 遇到cc.Mask 组件就白屏 有人遇到过吗?

NewProject_1.zip (1.6 MB)

1赞

https://store.cocos.com/app/detail/4442 可以用我的插件试试

1赞

我用了 确实可以了 感谢

creator 2.4.3,iOS首屏渲染后有白屏,然后才进入游戏场景