gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた

phiary に引っ越しました. 毎日プログラミングやWebに関する情報を発信しています! RSS 登録してたまに覗いたり, tweet やハテブして拡散してもらえると幸いです.

Pocket

gl.enchant.js で 3D 空間を動きまわるウォークスルー(Walk Through)プログラムを作ってみました.

3D プログラミングで基礎を学ぶにもってこいなウォークスループログラム. プレイヤーの移動やカメラの挙動など基本的な部分を学ぶことができます.

コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.

image

Sample and Download

サンプルはこちら.

十字キーもしくはタッチで移動できます.

視点は, コックピット, 近, 遠の3タイプあり, スペースキーで切り替えることができます.

ダウンロードはこちらからできます.

Code

Walk Through プログラム全体のコードです.

<!DOCTYPE html>

<html>
    
    <head>
        <meta charset="UTF-8">
        <!--
        <base target="_blank">
        -->
        <title></title>
        
        <style>
            body {
                margin: 0px;
                padding: 0px;
            }
        </style>
        
        <script type="text/javascript" src="../js/gl.enchant.js/glMatrix-0.9.5.min.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/enchant.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/gl.enchant.js"></script>
        <script type="text/javascript" src="../js/gl.enchant.js/primitive.gl.enchant.js"></script>
        <script type="text/javascript" src="floor.gl.enchant.js"></script>
        <script>
            var param = (function(){
                var search = document.location.search;
                return search.substr(1);
            })();
            
            param = Number(param);
            console.log(param);
        </script>
        <script>
            // おまじない
            enchant();
            
            var game = null;
            
            var CAMERA_MODE_COCKPIT = 0;
            var CAMERA_MODE_NEAR    = 1;
            var CAMERA_MODE_FAR     = 2;
            
            window.onload = function() {
                var game = new Game(640, 640);
                //var game = new Game(window.innerWidth, window.innerHeight);
                game.fps = 60;
                game.keybind(90, 'a');      // z
                game.keybind(88, 'b');      // x
                game.keybind(32, "space");  // space
                
                game.onload = function() {
                    var scene = new Scene3D();
                    
                    // ライトをセット
                    var light = new DirectionalLight();
                    light.directionZ = 1;
                    light.color = [1.0, 1.0, 1.0];
                    scene.setDirectionalLight(light);
                    
                    // 通常時カメラ
                    var camera = new Camera3D();
                    camera.x = 0;
                    camera.y = 0;
                    camera.z = -20;
                    camera.centerX = 0;
                    camera.centerY = 0;
                    camera.centerZ = 0;
                    scene.setCamera(camera);
                    
                    // 遠カメラ
                    var farCamera = new Camera3D();
                    farCamera.x = 0;
                    farCamera.y = 200;
                    farCamera.z =-200;
                    farCamera.centerX = 0;
                    farCamera.centerY = 0;
                    farCamera.centerZ = 0;
                    
                    // 床
                    var floor = new Floor(100, 100, 17, 17);
                    floor.x = 0;
                    floor.y =-1;
                    floor.z = 0;
                    floor.mesh.ambient = [0.5, 0.5, 0.5, 0.75];
                    scene.addChild(floor);
                    
                    // プレイヤー生成
                    var player = new Cube();
                    player.x = player.y = player.z = 0;
                    player.vx = 0;
                    player.vy = 0;
                    player.vz = 1;
                    scene.addChild(player);
                    
                    
                    // タッチによるフラグ設定
                    var touchFlags = {
                        up: false,
                        down: false,
                        left: false,
                        right: false,
                    };
                    // タッチ関数
                    var touchFunc = function(e) {
                        var tempX = (e.x - game.width/2)/game.width;    // (-0.5 ~ 0.5)
                        var tempY = (e.y - game.height/2)/game.height;  // (-0.5 ~ 0.5)
                        if (Math.abs(tempX) > 0.125) {
                            touchFlags.left = (tempX < 0);
                            touchFlags.right= (tempX > 0);
                        }
                        else {
                            touchFlags.left = touchFlags.right = false;
                        }
                        
                        if (Math.abs(tempY) > 0.125) {
                            touchFlags.up   = (tempY < 0);
                            touchFlags.down = (tempY > 0);
                        }
                        else {
                            touchFlags.up = touchFlags.down = false;
                        }
                    };
                    game.rootScene.addEventListener("touchstart", touchFunc);
                    game.rootScene.addEventListener("touchmove", touchFunc);
                    game.rootScene.addEventListener("touchend", function(e) {
                        touchFlags.up = touchFlags.down = touchFlags.left = touchFlags.right = false;
                    });
                    
                    
                    // Walk Through
                    var camera_mode = param;
                    var matrix = new mat4.create(); // 回転行列用マトリックスバッファ
                    
                    game.rootScene.addEventListener("enterframe", function(e){
                        var input = game.input;
                        
                        // キーとマウスのフラグを統一
                        var upFlag      = input.up      || touchFlags.up;
                        var downFlag    = input.down    || touchFlags.down;
                        var leftFlag    = input.left    || touchFlags.left;
                        var rightFlag   = input.right   || touchFlags.right;
                        
                        // 前進
                        if (upFlag) {
                            player.x += player.vx;
                            player.z += player.vz;
                        }
                        // 後退
                        if (downFlag) {
                            player.x -= player.vx;
                            player.z -= player.vz;
                        }
                        
                        /*
                        if (leftFlag) {
                            player.x += player.vz;
                            player.z -= player.vx;
                        }
                        if (rightFlag) {
                            player.x -= player.vz;
                            player.z += player.vx;
                        }
                        /**/
                        
                        if (leftFlag || rightFlag) {
                            // 向きベクトルを回転
                            var angle_speed = 2 * ((leftFlag) ? 1 : -1);
                            var rad = angle_speed*Math.PI/180;
                            var s = Math.sin(rad);
                            var c = Math.cos(rad);
                            var temp_vx = player.vx;
                            var temp_vz = player.vz;
                            player.vx = temp_vx*c + temp_vz*s;
                            player.vz =-temp_vx*s + temp_vz*c;
                            
                            // 回転した分だけ Player も回転する
                            mat4.identity(matrix);
                            mat4.rotateY(matrix, rad);
                            mat4.multiply(player.rotation, matrix);
                        }
                        
                        
                        // コックピット時のカメラ処理
                        if (camera_mode == CAMERA_MODE_COCKPIT) {
                            // 視点はプレイヤーの中
                            camera.x        = player.x;
                            camera.y        = player.y;
                            camera.z        = player.z;
                            // プレイヤーの向いてる方向に注視点をセット
                            camera.centerX  = player.x + player.vx;
                            camera.centerY  = 0;
                            camera.centerZ  = player.z + player.vz;
                        }
                        // 近いカメラモード時の処理
                        else if (camera_mode == CAMERA_MODE_NEAR) {
                            // プレイヤーの後ろ(つまり向いている方向と逆の方向)に視点をセット
                            camera.x        = player.x - player.vx*16;
                            camera.y        = 2;
                            camera.z        = player.z - player.vz*16;
                            // 注視点はプレイヤー
                            camera.centerX  = player.x;
                            camera.centerY  = player.y;
                            camera.centerZ  = player.z;
                        }
                    });
                    
                    // カメラをセットアップする処理
                    var setupCamera = function() {
                        // カメラチェンジ
                        switch (camera_mode) {
                            case CAMERA_MODE_COCKPIT :
                                scene.setCamera(camera);
                                break;
                            case CAMERA_MODE_NEAR :
                                scene.setCamera(camera);
                                break;
                            case CAMERA_MODE_FAR :
                                scene.setCamera(farCamera);
                                break;
                        }
                    };
                    
                    // 一回実行しておく
                    setupCamera();
                    
                    
                    // スペースキーを押した際のイベントを登録
                    game.addEventListener("spacebuttondown", function(){
                        camera_mode += 1;
                        camera_mode %= 3;
                        setupCamera();
                    });
                };
                
                game.start();
            };
            

            
        </script>
    </head>
    
    <body>

    </body>
    
</html>

Reference

なんだか最近クォータニオンが流行ってるみたいなので自分も何か作ろうかな.

TRACK BACK URL

POST COMMENT

メールアドレスが公開されることはありません。

COMMENT

  • phi_jp より:

    コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/fFAHoVzy
    #javascript #webgl

  • nakamura001 より:

    コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/fFAHoVzy
    #javascript #webgl

  • shi3z_bot より:

    RT @phi_jp: コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/M8p8qyju

  • wokakiiiiiiiiii より:

    RT @phi_jp: コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/M8p8qyju

  • shi3z_bot より:

    コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/fFAHoVzy
    #javascript #webgl

  • lef より:

    RT @phi_jp: コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/M8p8qyju

  • k_e_n1 より:

    コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/fFAHoVzy
    #javascript #webgl

  • atsu_kaya より:

    コードはダウンロードできるようにしてあるので, よかったらイジって遊んでみてください.
    『gl.enchant.js で3D空間を動き回るウォークスループログラムを作ってみた』
    http://t.co/fFAHoVzy
    #javascript #webgl