最低限のゲームエンジンのソース

// 省略時のゲームブロック要素ID
var g_idStage = "#game-stage";
// ゲーム支援クラス
var clsGameUtl = function(id)
{
    this.Element = (id || g_idStage);
    // three オブジェクトの引数の格納用
    this.Core = {
        uFps:60                   // 描画速度(frame per second)
    };
    // インスタンス
    var inst = this;
    // フレーム処理を行う関数を得る
    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = (
          window.webkitRequestAnimationFrame
          || window.mozRequestAnimationFrame
          || window.oRequestAnimationFrame
          || window.msRequestAnimationFrame
          || function(callback) { return window.setTimeout(callback, 1000 / inst.Core.uFps); }
        );
    }
    // フレーム停止を行う関数を得る
    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = (
          window.webkitCancelRequestAnimationFrame
          || window.mozCancelRequestAnimationFrame
          || window.oCancelRequestAnimationFrame
          || window.msCancelRequestAnimationFrame
          || function(id) { window.clearTimeout(id); }
        );
    }
};
// ゲーム初期化
clsGameUtl.prototype.Initialize = function(Stage, NonRenderer, zIndex)
{
    // 描画関数スタック
    this.aryLayer = [];
    // 当オブジェクトを使用するオブジェクトを記憶
    this.Core.Stage = Stage;
    // レンダラの初期化
    if (!NonRenderer) {
        // レンダラの初期化をあれやこれや行う
    }
    // 開始時間
    this.StartTime = this.GetTime();
}
// レイア生成
clsGameUtl.prototype.CreateLayer = function(callback, newLayer, wantClear, wantHover, zIndex)
{
    var idx = this.aryLayer.length;
    // 描画用パラメータ記憶用
    var p = { wantClear:wantClear, wantHover:wantHover, layer:idx, Frame:-1 };
    // 新規レイアならキャンバスを作成
    if (newLayer) {
        var sz = this.GetSize();
        var ec = this.NewHiddenCanvas(this.Element, sz.cx, sz.cy);
        // 可視の状態で初期化
        $(ec).css("visibility", "visible");
        $(ec).css("z-index", zIndex || 0);
        p.Elemnt = ec;
        p.Canvas = ec.getContext("2d");
    }
    else
        p.Elemnt = this.Element;
    // コールバックを記憶する
    this.aryLayer.push( { fnc:callback, prm:p } );
    // THREE のオブジェクト指標を記憶する
    if (!newLayer)
        this.Core.RendererIndex = idx;
    // レイア番号を返す
    return idx;
}
// ゲーム停止
clsGameUtl.prototype.Stop = function()
{
    cancelAnimationFrame(this.Core.Timer);
    // ゲーム停止フラグを設定
    this.Playing = false;
}
// ゲーム開始
clsGameUtl.prototype.DoGame = function()
{
    // ゲーム中フラグを設定
    this.Playing = true;
    // 描画可能なら...
    if (this.CanRenderer) {
        if (this.Core.Renderer) {
            // 3d オブジェクトを使用するなら撮影を行なう
            if (this.Use3DObject) {
                // 3d ならあれやこれやを行う
            }
        }
        // 描画コールバック
        this.DrawLayer(-1);
    }
    // コールバック
    if (this.Playing)
        this.Core.Timer = window.requestAnimationFrame(this.DoGame.bind(this));
}
// 描画コールバック
clsGameUtl.prototype.DrawLayer = function(idx)
{
    if (idx >= 0) {
        if (idx < this.aryLayer.length) {
            var p = this.aryLayer[idx].prm;
            var c = (p.Canvas ? p.Canvas : this.Core.Canvas);
            // ゲーム実装オブジェクトの指定関数をコールバック
            if (this.aryLayer[idx].fnc)
                this.aryLayer[idx].fnc.call(this.Core.Stage, c, p);
        }
    }
    else
    {
        for (var idx = 0; idx < this.aryLayer.length; idx++)
            this.DrawLayer(idx);
    }
}
// 非表示 canvas 生成
clsGameUtl.prototype.NewHiddenCanvas = function(id, w, h, zIndex)
{
    // キャンバスタグ生成
    var cvs = document.createElement('canvas');
    // サイズを設定し非表示とする
    cvs.style.position = "absolute";
    cvs.style.left = "0px";
    cvs.style.top = "0px";
    cvs.style.border = "none";
    cvs.style.visibility = "hidden";
    cvs.style.zindex = (zIndex || 0);
    cvs.width = w;
    cvs.height = h;
    // 子要素を親へ追加
    $(id).append(cvs);
    // エレメントを返す
    return cvs;
}
// Dateよりも詳細な時間を取得
clsGameUtl.prototype.GetTime = function()
{
    var fncNow = (
        window.performance
        && (
            performance.now
            || performance.mozNow
            || performance.msNow
            || performance.oNow
            || performance.webkitNow
        )
    );
    // 現在時間を返す
    return (fncNow && fncNow.call(performance)) || ( new Date().getTime());
}
// 次のフレーム番号を得る
clsGameUtl.prototype.GetNextFrame = function(obj, interval, numFrame)
{
    var curFrame = (obj.Frame ? obj.Frame : 0);
    // 前回のフレーム時刻を記憶
    if (!obj.Time)
        obj.Time = this.GetTime();
    // フレーム更新間隔時間を過ぎたら次のフレームに移る
    if (this.GetTime() - obj.Time >= interval) {
        curFrame++;
        obj.Time = this.GetTime();
    }
    // フレーム番号を返す
    return (curFrame % numFrame);
}
// ゲーム領域のサイズ取得
clsGameUtl.prototype.GetSize = function()
{
    return ( { cx:$(this.Element).width(), cy:$(this.Element).height() } );
}
// 画像ロード
clsGameUtl.prototype.LoadImage = function(url)
{
    // 画像オブジェクト生成
    var img = new Image();
    // ソースを設定
    img.src = url;
    // 画像オブジェクトを返す
    return img;
}