isobe_yakiのブログ

ニコ生ゲーム開発者向けの記事を書きます

3Dのニコ生ゲームを作ろう その2

前回は色々と下調べしてニコ生ゲームでWebGLを使ったゲームを作ろうというところまでやった。

今回はひとまずAkashicでWebGL描画をする最小サンプルを作っていこうと思う。ちなみにWebGLそのものの使い方自体は当ブログでは取り扱わない。それに関してはネットに十分情報があるのでそれらを見てもらえば問題ないだろう。

webglに関してはこちらのサイトが詳しい。 wgld.org

最小サンプル

// 描画時に呼び出されるコールバックを指定できるスプライトクラス
class CustomSprite extends g.Sprite {
    constructor(params) {
        super(params);
        this.drawer = params.drawer;
    }

    renderSelf(renderer, camera) {
        this.drawer();
        super.renderSelf(renderer, camera);
    }
}

exports.main = () => {
    var scene = new g.Scene({
        game: g.game
    });
    g.game.pushScene(scene);

    scene.onLoad.addOnce(() => {
        // サーフェース作成
        const src = g.game.resourceFactory.createSurface(200, 200);
        // WebGL2作成
        const gl = src._drawable.getContext('webgl2');

        // シェーダー作成
        const shader = gl.createProgram();
        const vs = gl.createShader(gl.VERTEX_SHADER);
        const fs = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(vs, '#version 300 es\n' +
            'uniform float angle;' +
            'out vec3 color;' +
            'void main(void){' +
            '   gl_Position = vec4(sin(float(gl_VertexID) * 2.094 + angle), cos(float(gl_VertexID) * 2.094 + angle), 1., 1.);' +
            '   color = vec3(gl_VertexID == 0 ? 1.0 : 0.0, gl_VertexID == 1 ? 1.0 : 0.0, gl_VertexID == 2 ? 1.0 : 0.0);' +
            '}');
        gl.shaderSource(fs, '#version 300 es\n' +
            'precision mediump float;' +
            'in vec3 color;' +
            'out vec4 result;' +
            'void main(void){' +
            '   result = vec4(color, 1.0);' +
            '}');
        gl.compileShader(vs);
        gl.compileShader(fs);
        gl.attachShader(shader, vs);
        gl.attachShader(shader, fs);
        gl.linkProgram(shader);

        // シェーダーパラメータ(ユニフォームロケーション)取得
        const angle = gl.getUniformLocation(shader, 'angle');

        // レンダリング結果表示用エンティティ作成
        const sprite = new CustomSprite({
            scene,
            src,
            parent: scene,
            anchorX: 0.5,
            anchorY: 0.5,
            drawer: () => {
                // WebGL描画処理(画面クリアと三角描画のみ)
                gl.clearColor(0, 0, 0, 1);
                gl.clear(gl.COLOR_BUFFER_BIT);

                gl.useProgram(shader);
                gl.uniform1f(angle, g.game.age * 0.02);
                gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
            }
        });
        // 適当にくるくる回しとく
        sprite.onUpdate.add(() => {
            sprite.x = Math.cos(g.game.age * 0.02) * 100 + g.game.width * 0.5;
            sprite.y = Math.sin(g.game.age * 0.02) * 100 + g.game.height * 0.5;
            sprite.modified();
        });

        // 後片付け
        scene.onStateChange.addOnce(state => {
            if (state == 'before-destroyed') {
                gl.deleteShader(vs);
                gl.deleteShader(fs);
                gl.deleteProgram(shader);
            }
        });
    });
};

このコードはスクショのような虹色の三角形がくるくる回るだけのサンプルである。適当にAkashicで新規プロジェクトを作成してmain.jsに上書きすれば動くと思う。 このようにAkashicとWebGLは共存させてもそんなに違和感なく使えるということが分かっていただけたと思う。まぁこれ以上特に解説することもないので今回はこれで終了だが何か質問等あればコメントにでも書いていただければ答えるかもしれないのでよろしく。

今後について

今後のWebGL記事についてだが、正直どうしようか迷ってる。ニコ生ゲーって大体はTypeScriptかJavaScriptで書かれていると思うので今回はjsで書いたが、元々GL関連の処理は全部c++で書いてるのでコード付きの解説などがしづらい。なので、恐らく具体的なコードを載せる感じではなくここはこんな感じでやりましたよ~という風に軽く紹介して流す感じになるかも。(もしくはc++で載せちゃうか)

一応c++でニコ生ゲームを作る記事も書こうかなと思っているがなかなか需要無さそうで今から頓挫する未来が見える見える・・・