JavaScriptでゲームエンジンを作りたいPart2

# はじめに
前回の予告通りにFortis.Gameのinit関数について書いていきます。
# キャンバス
Fortis.Gameのinit関数内に書くことは描画をするキャンバスについてです。
普通なら
~~~javascript:canvas
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
document.body.appendChild(canvas);
~~~
みたいにしてあげればよいのですが、これだと沢山描画の処理をすると重くなってしまうので、負荷を少しでも抑えるために**OffScreenCanvas**というのを使います。
簡単に説明すると、画面には表示させないキャンバスって感じです。

詳しくはこちらから↓
https://developer.mozilla.org/ja/docs/Web/API/OffscreenCanvas

そうすると、コードは以下のようになります。
~~~javascript:OffscreenCanvas
//オフスクリーンキャンバス
let offSCanvas = new OffscreenCanvas();
let offSContext = offSCanvas.getContext("2d");

//通常のキャンバス
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
document.body.appendChild(canvas);

//描画
function draw(){
    //オフスクリーンキャンバスで描画(例)
    offSContext.fillRect(0,0,100,100);

    //オフスクリーンキャンバスでレンダリングされたものをキャンバスに表示させる
    context.drawImage(offSCanvas.transferToImageBitmap(),0,0);
}
~~~
描画のAPIはキャンバスと同じなので、最後のキャンバスに表示させるのだけを忘れなければ大丈夫ですね。

これをFortis.Gameのところに書きます。
~~~javascript:engine/core.js
Fortis.Game = {
    //変数系
    canvas: null,//オフスクリーンキャンバス(エンジン外からのアクセスする可能性もあるので、の便宜上この名前とする)
    context: null,//canvasのコンテキスト(名前の理由は同上)
    finalCanvas: null,//最終的に描画されるキャンバス
    finalContext: null,//finalCanvasのコンテキスト
    config: {//設定
        debug: false,//デバッグモード
    },

    //関数
    init() {//初期化
        //オフスクリーンキャンバス
        this.canvas = new OffscreenCanvas();
        this.context = this.canvas.getContext("2d");

        //最終的な描画キャンバス
        this.finalCanvas = document.createElement("canvas");
        this.finalContext = this.finalCanvas.getContext("2d");
        document.body.appendChild(this.finalCanvas);

        //キャンバスのサイズ
        let width = 800;
        let height = 450;
        this.canvas.width = width;
        this.canvas.height = height;
        this.finalCanvas.width = width;
        this.finalCanvas.height = height;

        Fortis.info.SystemInitCompleted();//初期化完了
    },

    //ゲームループ
    loop() {
        this.draw();//描画関数を呼び出す
        requestAnimationFrame(this.loop.bind(this));//アニメーションループ
    },

    //描画
    draw: null,
}
~~~
~~~javascript:engine/util.js
Fortis.info = {
    //new
    SystemInitCompleted() { Fortis.util.console("Info", "ゲームシステムの初期化が完了しました。") },
    
    StartGameLoop() { Fortis.util.console("Info", "ゲームループを開始します。") },
}
~~~
util.jsのinfoにSystemInitCompletedを書いておきます。

描画の処理はdraw.jsというファイルを作ってそこに書きます。(addthis.jsのfilesに追加しておく)
~~~javascript:engine/draw.js
Fortis.Game.draw = function(){
    //オフスクリーンキャンバスで描画(例)
    Fortis.Game.context.fillStyle = "#252525";
    Fortis.Game.context.fillRect(0,0,Fortis.Game.canvas.width,Fortis.Game.canvas.height);//キャンバスを塗りつぶし
  
    Fortis.Game.context.fillStyle = "#a0a0a0";
    Fortis.Game.context.fillRect(100,100,50,50);//正方形を描画

    //オフスクリーンキャンバスでレンダリングされたものをキャンバスに表示させる
    Fortis.Game.finalContext.drawImage(Fortis.Game.canvas.transferToImageBitmap(),0,0);
}
~~~
適当に書いてみました。必要ないコードを省いで実行させると...
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="poMOMXR" data-pen-title="Untitled" data-user="Rei-Miyakawa" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Rei-Miyakawa/pen/poMOMXR">
  Untitled</a> by Rei-Miyakawa (<a href="https://codepen.io/Rei-Miyakawa">@Rei-Miyakawa</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
ちゃんと表示されましたね。

# まとめ
以下、今のところのファイル・フォルダの状況(変更されたところだけ)

~~~
root/
    ┣index.html
    ┣engine/
    ┃　　　┣addthis.js
    ┃　　　┣core.js
    ┃　　　┣draw.js
    ┃　　　┗util.js
    ┗script/
     　　　┗main.js
~~~
~~~javascript:engine/addthis.js
let files = [
    "core",
    "draw",//new
    "util",
];
~~~
~~~javascript:engine/core.js
Fortis.Game = {
    //変数系
    canvas: null,//オフスクリーンキャンバス(エンジン外からのアクセスする可能性もあるので、の便宜上この名前とする)
    context: null,//canvasのコンテキスト(名前の理由は同上)
    finalCanvas: null,//最終的に描画されるキャンバス
    finalContext: null,//finalCanvasのコンテキスト
    config: {//設定
        debug: false,//デバッグモード
    },

    //関数
    init() {//初期化
        //オフスクリーンキャンバス
        this.canvas = new OffscreenCanvas();
        this.context = this.canvas.getContext("2d");

        //最終的な描画キャンバス
        this.finalCanvas = document.createElement("canvas");
        this.finalContext = this.finalCanvas.getContext("2d");
        document.body.appendChild(this.finalCanvas);

        //キャンバスのサイズ
        let width = 800;
        let height = 450;
        this.canvas.width = width;
        this.canvas.height = height;
        this.finalCanvas.width = width;
        this.finalCanvas.height = height;

        Fortis.info.SystemInitCompleted();//初期化完了
    },

    //ゲームループ
    loop() {
        this.draw();//描画関数を呼び出す
        requestAnimationFrame(this.loop.bind(this));//アニメーションループ
    },

    //描画
    draw: null,
}
~~~
~~~javascript:engine/draw.js
Fortis.Game.draw = function(){
    //オフスクリーンキャンバスで描画(例)
    Fortis.Game.context.fillStyle = "#252525";
    Fortis.Game.context.fillRect(0,0,Fortis.Game.canvas.width,Fortis.Game.canvas.height);//キャンバスを塗りつぶし
  
    Fortis.Game.context.fillStyle = "#a0a0a0";
    Fortis.Game.context.fillRect(100,100,50,50);//正方形を描画

    //オフスクリーンキャンバスでレンダリングされたものをキャンバスに表示させる
    Fortis.Game.finalContext.drawImage(Fortis.Game.canvas.transferToImageBitmap(),0,0);
}
~~~
~~~javascript:engine/util.js
Fortis.info = {
    //new
    SystemInitCompleted() { Fortis.util.console("Info", "ゲームシステムの初期化が完了しました。") },
    
    StartGameLoop() { Fortis.util.console("Info", "ゲームループを開始します。") },
}
~~~

以上です。
前回は少し長かったですが、今回からはこのくらいの分量でやっていこうと思います。
次回からは描画関係について書いていきます。
それではまた次回。

前回：https://qiita.com/Rei-Miyakawa/items/456dd9798d0dffa44c11#%E3%81%BE%E3%81%A8%E3%82%81
次回：