Google

2014年1月15日水曜日

HTML5で3Dゲー:CSS3Dプロトタイプ

今回は候補決定からThree.jsのプロト作成で速度と現実性を検討した話です。

まず具体的なゲームの画面要素はこんな感じになりました。

拙いですが、必要な要素は基本こんなもんです
ちなみにこれはUnity側で作った簡易プロト、つまりこの時点でUnityと同時進行だったので、これは置いておきますが、実はここが後々重要だったりします。
で、この上にGUIやらエフェクトやらが入る訳なんですが、この構成でThree.jsが担当しなければならない部分は以下という事に決めてしまいました。
  • 迫り来る物体(障害物、又はアイテム)
  • 無限にスクロールする床(壁)
  • 主人公とそれを追いかける敵
これらをThree.jsで、css3dRendererを使用して仮実装していきます。
まず迫り来る物体。これにモデルデータを使うかどうか検討した際、2つの現象に出くわしました。
  • 処理が凄まじく遅い
  • モデルが表示すらされない
まあ、後者は仕方ありません、スマホですし。
前者でも簡単なプリミティブなら出たのですが、複雑なデザインは絶望的でした。
しかし表示できない原因や高速化の手段を探す時間がなかったため、ここもバッサリ判断するしかありません。

  ペラペラの1枚板を物体として扱う

下位機種を考えるとこれしかありません。
となると主人公や敵もペラ1枚なのは当然ですし、見た目の差異や薄い物体の縦に対する当たり判定が問題になりますが、それは次のタイミングで考えることにしました。

次に壁と床です。
床には落とし穴などを作る案もありましたが、最初のバージョンでは単純にタイルが表示できれば良いという話になったため、2種類の案から選ぶ事になりました。
  • タイルを1枚1枚配置
  • 長いタイルを配置
こちらには当たり判定は関係なく、見た目として合っていればOKです。
また、この手のゲームにおいては、通路はゲーム中似たようなテクスチャがほぼ常に動き続けるという事が多いようなので、よくあるインスタンスの使い回しを適用することにしました。
やってる事は簡単で、以下の図のようにするだけです。


単純ではあってもメモリ節約、処理の簡略化に影響が大きく、Unityでも常にこうしないとなかなか効率化ができません。
それらを考慮し、一番最初に書いたプロト用サンプル(1枚タイルバージョン)はこんな代物でした。


画面はこんな感じで、ひたすら無限にスクロールします。
CSS3dサンプルデモの実際の動作はこちら(実際にブラウザで動きます)
画面等は一切気にせず、兎に角ひたすら床タイルがスクロールするというだけのものです。
壁があるデモバージョンもあるにはありますが、どのみちやることは一緒です。

シンプルで恐縮ですが、JavaScript側のコードはこんな感じで書きました。

// Three用変数の宣言
var camera, scene, renderer, root, arr;
// CSS3Dタイルの生成
var makeObj = function(pregress)
{
    // 画像CSSを生成
    var element = document.createElement('img');
    element.src = "http://jsrun.it/assets/l/N/z/R/lNzRT.gif";
    element.style.width = '240px';
    element.style.height = '120px';
    element.style.border = '0px';

    // CSS3オブジェクトを生成
    var object = new THREE.CSS3DObject( element );

    // 回転と位置を設定
    object.position.x = 0;
    object.position.y = 150;
    object.position.z = pregress;
    object.rotation.x = 1.57;
    object.rotation.y = 0;
    object.rotation.z = 0;
    scene.add( object );
    return object;
};
// Three.js初期化
var initThree = function()
{
    // カメラ生成
    camera = 
        new THREE.PerspectiveCamera(
                90,
                window.innerWidth / window.innerHeight,
                1,
                100);
 camera.position.set( 0, 0, 0 );
    // シーン生成
    scene = new THREE.Scene();

    // レンダラー
    renderer = new THREE.CSS3DRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.domElement.style.position = 'absolute';
 renderer.domElement.style.top = 0;
    document.body.appendChild( renderer.domElement );

    // 床の生成
    arr = [];
    for (var i = -1800; i < 0; i += 120)
    {
        arr.push(makeObj(i));
    }
};
// アニメーション処理
var animateThree = function()
{
    requestAnimationFrame( animateThree );
    renderer.render( scene, camera );
    var len = arr.length;
    for(var i = 0; i < len; i ++)
    {
        var obj = arr[i];
        obj.position.z += 6;
        if (obj.position.z >= 0)
        {
            obj.position.z = -1800;
        }
    }
};
initThree();
animateThree();

デモなのでマジックナンバーだらけですが、、(汗)
床を一定枚数生成し、それらをループで1個ずつ移動させ、指定位置に来たら遠くに戻すといった内容です。

しかし、こんなんでも確かに動きはします。
非効率な処理をしていますが、スマホでも動作は問題ありませんでした。

が、ここから検証のさらなる問題多発で、切り替えをせざるを得なくなったのですが、、、続きます。

0 件のコメント:

コメントを投稿