09-controls-gamepad.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>The Five Planets</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <style>
        body {
            width:100%;
            height:100%;
            padding:0;
            margin:0;
            overflow:hidden;
        }
    </style>
    <link rel="stylesheet" type="text/css" href="../css/screen.css"/>
    <link rel="stylesheet" type="text/css" href="../css/ui.css"/>
    
    <!-- LOAD JQUERY & REQUIERE -->
    <script src="../frameworks/require.min.js"></script>
    <script src="../frameworks/jquery-2.0.3.min.js"></script>
    <script src="../core/ui/ui_v01.js" defer></script>
    
    <!-- LOAD THREE.JS -->
    <script src="../frameworks/three.js" defer></script>
    <script src="../frameworks/renders/projector.js" defer></script>
    <script src="../frameworks/loaders/DDSLoader.js" defer></script>
    <script src="../frameworks/loaders/MTLLoader.js" defer></script>
    <script src="../frameworks/loaders/OBJLoader.js" defer></script>
    <script src="../frameworks/loaders/ColladaLoader.js" defer></script>
    <script src="../frameworks/loaders/collada/Animation.js" defer></script>
    <script src="../frameworks/loaders/collada/AnimationHandler.js" defer></script>
    <script src="../frameworks/loaders/collada/KeyFrameAnimation.js" defer></script>
    
    <!-- LOAD DAT.GUI & STATS-->
    <script src="../frameworks/dat.gui.min.js" defer></script>
    <script src="../frameworks/stats.js" defer></script>
    
    <!-- GAME FILES-->
    <script src="../core/controls/controls_gamepad_v01.js" defer></script>
    <script src="../core/world/world_v01.js" defer></script>
    <script src="../core/world/ground_v01.js" defer></script>
    <script src="../core/world/sky_v01.js" defer></script>
    <script src="../core/world/nature_v01.js" defer></script>
    <script src="../core/entities/template3D_v01.js" defer></script>
    <script src="../core/entities/entity3D_v02.js" defer></script>
    <script src="../core/ai/ai_path_v01.js" defer></script>
    <script src="../core/ai/ai_random_v01.js" defer></script>

<script>

$(document).ready(function () {
    $UI.drawloading();
    $UI.loading.setValue(0);
    $UI.loading.show();
    $WORLD.distance = 130;
    $WORLD.init3D({}, function () {
        $UI.loading.setValue(0.05);//5%
        $RG.templates={
            "castle_wall_a": {"model" : "../data/models/castle/wall_a.obj"},
            "castle_wall_b": {"model" : "../data/models/castle/wall_b.obj"},
            "castle_wall_c": {"model" : "../data/models/castle/wall_c.obj"},
            "castle_gate_wall": {"model" : "../data/models/castle/gate_wall.obj"},
            "castle_metal_gate": {"model" : "../data/models/castle/metal_gate.obj"},
            "castle_tower1": {"model" : "../data/models/castle/tower1.obj"},
            "castle_tower2": {"model" : "../data/models/castle/tower2.obj"},
            "castle_tower3": {"model" : "../data/models/castle/tower3.obj"},
            "house1": {"model": "../data/models/houses01/house1-01.obj"},
            "house2": {"model": "../data/models/houses01/house1-02.obj"},
            "house3": {"model": "../data/models/houses01/house1-03.obj"},
            "house4": {"model": "../data/models/houses01/house1-04.obj"},
            "well1": {"model": "../data/models/houses01/well-01.obj"},
            "bench1": {"model": "../data/models/houses01/bench-01.obj"},
            "house17": {"model": "../data/models/houses05/house5-01.obj"},
            "house18": {"model": "../data/models/houses05/house5-02.obj"},
            "house19": {"model": "../data/models/houses05/house5-03.obj"},
            "house20": {"model": "../data/models/houses05/house5-04.obj"},
            "house21": {"model": "../data/models/houses05/house5-05.obj"},
            "house22": {"model": "../data/models/houses06/house6-01.obj"},
            "house23": {"model": "../data/models/houses06/house6-02.obj"},
            "house25": {"model": "../data/models/houses06/house6-03.obj"},
            
            "tree07": {"model": "../data/graphics/textures/vegetation/tree07.png","width":10.2,"height":14.53,"type":3},
            "villager01": {"model": "../data/models/people/aldeano01.dae", "type":1, "animation":true, "ai":"PathAI", "scale":{"x":1.5,"y":1.5,"z":1.5}, "rotate":{"x":-90,"y":0,"z":0}},
            "aliendog": {"model": "../data/models/monsters/aliendog.dae", "type":1, "animation":true, "ai":"RandomAI", "scale":{"x":0.05,"y":0.05,"z":0.05}, "rotate":{"x":-90,"y":0,"z":-90}}
        }
        $WORLD.map = {
        "x":256,
        "z":256,
        "startPosX":126,
        "startPosZ":145,
        "ground": {
            "type":"basic",
            "texture":"../data/graphics/textures/terrain/grass1.jpg",
            "resX":2,
            "resY":2
        },
        "sky": {
            "type":"skysphere",
            "colorAmbient" : "rgb(90, 90, 90)",
            "intensityAmbient" : 0.5,
            "sunlightcolor" : "rgb(255, 255, 255)",
            "sunlightposition": {"x":10, "y":20, "z":0},
            "sunlightintensity" : 1,
            "texture":"../data/graphics/textures/sky/skydome.jpg",
            "fogColor": "rgb(225, 225, 225)",
            "fogNear":70,
            "fogFar":130
        },
            
        "nature": {
                "type":"basic",
                "patterns": {
                    "bushes":{
                        "freqX":5,
                        "freqZ":5,
                        "elements":[
                            {"object":"../data/graphics/textures/vegetation/grass.png","width":1.5,"height":1.5},
                            {"object":"../data/graphics/textures/vegetation/struik.png","width":1.5,"height":1.5}
                        ]
                    },
                    "forest":{
                        "freqX":10,
                        "freqZ":10,
                        "elements":[
                            {"object":"../data/graphics/textures/vegetation/tree01.png","width":8.75,"height":8.91},
                            {"object":"../data/graphics/textures/vegetation/tree02.png","width":10,"height":9.84},
                            {"object":"../data/graphics/textures/vegetation/tree03.png","width":9.59,"height":8.65},
                            {"object":"../data/graphics/textures/vegetation/tree04.png","width":6.1,"height":8.65},
                            {"object":"../data/graphics/textures/vegetation/tree05.png","width":10,"height":7.66},
                            {"object":"../data/graphics/textures/vegetation/tree06.png","width":8.94,"height":13.9},
                            {"object":"../data/graphics/textures/vegetation/tree07.png","width":10.2,"height":14.53}
                        ]
                    },
                    "hightTrees":{
                        "freqX":12,
                        "freqZ":12,
                        "elements":[
                            {"object":"../data/graphics/textures/vegetation/tree06.png","width":10,"height":20.68},
                            {"object":"../data/graphics/textures/vegetation/tree07.png","width":12,"height":22.43}
                        ]
                    }
                    
                },
                "zones": [
                    {"pattern":"forest","minX":0,"minZ":50,"maxZ":260,"maxX":114},
                    {"pattern":"bushes","minX":20,"minZ":50,"maxZ":260,"maxX":117},
                    
                    {"pattern":"hightTrees","minX":110,"minZ":40,"maxZ":110,"maxX":200},
                    {"pattern":"bushes","minX":110,"minZ":80,"maxZ":113,"maxX":140},
                    
                    {"pattern":"hightTrees","minX":0,"minZ":217,"maxZ":280,"maxX":230}
                ]
            
         }, 
        
         "map3D": [
            { "template": "castle_wall_c", "x": 214, "z": 110, "rY": -90 , "coment":"Size X:120-230, z:110-215"},
            { "template": "castle_tower2", "x": 210, "z": 110 },
            { "template": "castle_wall_a", "x": 199, "z": 110, "rY": -90 },
            { "template": "castle_tower1", "x": 188, "z": 110, "rY": -90  },
            { "template": "castle_gate_wall", "x": 177, "z": 110, "rY": -90 },
            { "template": "castle_metal_gate", "x": 177, "z": 110, "rY": -90 },
            { "template": "castle_tower1", "x": 166, "z": 110, "rY": -90  },
            { "template": "castle_wall_a", "x": 155, "z": 110, "rY": -90 },
            { "template": "castle_tower2", "x": 143, "z": 110 },

            { "template": "castle_wall_c", "x": 120, "z": 129},
            { "template": "castle_tower1", "x": 120, "z": 134},
            { "template": "castle_gate_wall", "x": 120, "z": 145},
            { "template": "castle_metal_gate", "x": 120, "z": 145, "y":2.5},
            { "template": "castle_tower1", "x": 120, "z": 156},
            { "template": "castle_wall_b", "x": 120, "z": 173},
            { "template": "castle_tower3", "x": 120, "z": 192},
            { "template": "castle_wall_c", "x": 140, "z": 215, "rY": 90},

            { "template": "castle_tower2", "x": 144, "z": 215},
            { "template": "castle_wall_b", "x": 157, "z": 215, "rY": 90 },
            { "template": "castle_tower2", "x": 176, "z": 215},
            { "template": "castle_wall_b", "x": 190, "z": 215, "rY": 90 },
            { "template": "castle_tower2", "x": 210, "z": 215},
            { "template": "castle_wall_c", "x": 233, "z": 199, "rY": 180 },
    
            { "template": "castle_tower2", "x": 233, "z": 132},
            { "template": "castle_wall_b", "x": 233, "z": 150, "rY": 180 },
            { "template": "castle_tower2", "x": 233, "z": 165},
            { "template": "castle_wall_b", "x": 233, "z": 185, "rY": 180 },
            { "template": "castle_tower2", "x": 233, "z": 199},

            { "template": "house1", "x": 155, "z": 150, "rY": -25,  "comment" : "houses01" },
            { "template": "well1", "x": 135, "z": 146, "rY": -45  },
            { "template": "bench1", "x": 145, "z": 153, "rY": -25 },
            { "template": "house22", "x": 134, "z": 130,"rY": 110 },
            { "template": "house23", "x": 150, "z": 125,"rY": 45 },
            { "template": "house4", "x": 170, "z": 132, "rY": -25},

            { "template": "house17", "x": 135, "z": 162, "rY": -100,  "comment" : "houses05" },
            { "template": "house18", "x": 154, "z": 172,"rY": -45},
            { "template": "house19", "x": 170, "z": 170,"rY": -55 },
            { "template": "house20", "x": 174, "z": 155,"rY": -35 },
            { "template": "house21", "x": 178, "z": 142,"rY": 45 },

            { "template": "house22", "x": 133, "z": 180,"rY": 200, "comment" : "houses06" },
            { "template": "house3", "x": 148, "z": 190, "rY": -15 },
            { "template": "house2", "x": 168, "z": 190, "rY": 20 },
            { "template": "house25", "x": 185, "z": 190, "rY": -5 },
            
            { "template": "tree07", "x": 145, "z": 141 },
            { "template": "tree07", "x": 146, "z": 166 },
            
            { "template": "villager01", "x": 139, "z": 144, "path":[[171,0,131],[164,0,130],[159,0,130],[156,0,134],[149,0,141],[145,0,145],[139,0,150],[129,0,149],[127,0,144]
            ,[133,0,140],[169,0,131],[140,0,138],[144,0,135],[145,0,131],[146,0,129],[147,0,128],[149,0,126],[148,0,128],[144,0,130],[142,0,126],[141,0,121],[149,0,117]
            ,[160,0,121],[136,0,129],[166,0,130],[169,0,131]]},
            { "template": "villager01", "x": 140, "z": 145, "path":[[135,0,133],[136,0,136],[131,0,142],[132,0,152],[141,0,152],[145,0,163],[144,0,173],[142,0,184],[138,0,190]
            ,[127,0,191.5],[120.5,0,191.5],[120.5,0,159],[121,0,156],[128,0,156],[133,0,150],[132,0,143],[137,0,138],[136,0,134]]},
            { "template": "villager01", "x": 140, "z": 145, "path":[[135,0,179],[136,0,179],[140,0,177],[152,0,181],[156,0,185],[157,0,190],[160,0,194],[163,0,192],[167,0,190]
            ,[172,0,189],[176,0,188],[179,0,190],[180,0,190],[183,0,190],[185,0,190]]},
            
            { "template": "aliendog", "x": 70, "z": 120, "minX":60,"maxX":85,"minZ":117,"maxZ":140},
            { "template": "aliendog", "x": 73, "z": 150, "minX":60,"maxX":85,"minZ":140,"maxZ":163},
            { "template": "aliendog", "x": 80, "z": 170, "minX":60,"maxX":85,"minZ":163,"maxZ":186},
            { "template": "aliendog", "x": 65, "z": 190, "minX":60,"maxX":85,"minZ":186,"maxZ":209},

            { "template": "aliendog", "x": 90, "z": 140, "minX":85,"maxX":111,"minZ":117,"maxZ":140},
            { "template": "aliendog", "x": 100, "z": 141, "minX":85,"maxX":111,"minZ":140,"maxZ":163},
            { "template": "aliendog", "x": 95, "z": 149, "minX":85,"maxX":111,"minZ":163,"maxZ":186},
            { "template": "aliendog", "x": 105, "z": 149, "minX":85,"maxX":111,"minZ":186,"maxZ":209},
            
            { "template": "aliendog", "x": 105, "z": 149, "minX":90,"maxX":110,"minZ":132,"maxZ":150}
            
        ]
    };
        
        $WORLD.showStats();        
        $WORLD.drawGround();
        $WORLD.drawSky();
        $WORLD.drawNature();
        
        $RG.loadTemplates( function() {

            var elements=$WORLD.map.map3D.length;
            for (var i=0;i<elements;i++){
            
                var props=$WORLD.map.map3D[i];
                var ent=new $RG.Entity3D(props);
                ent.addToWorld();
                $UI.loading.setValue( ((i/elements)*0.20) +0.80);
            }
            
            var path=new THREE.CatmullRomCurve3([
            new THREE.Vector3(0/2, 2, 100/2),
            new THREE.Vector3(10/2, 2, 80/2),
            new THREE.Vector3(30/2, 2, 110/2),
            new THREE.Vector3(50, 2, 0/2),
            new THREE.Vector3(60/2, 2, 0/2),
            new THREE.Vector3(70/2, 2, 100/2),
            new THREE.Vector3(85/2, 2, 55/2),
            new THREE.Vector3(100/2, 2, 65/2),
            new THREE.Vector3(0/2, 2, 100/2)])

            $WORLD.camera.position.set(126,2,145);
            $WORLD.controls = new $CONTROLS.FirstPersonControls ($WORLD.camera);
            $WORLD.controls.minX=60;
            $WORLD.controls.minZ=117;
            $WORLD.controls.maxX=226;
            $WORLD.controls.maxZ=209;
            $WORLD.controls.showPosition();
            $WORLD.addToListUpdate ($WORLD.controls);

            setTimeout(function() {
                $WORLD.startAnimation();
                $UI.loading.hide();
                },500
            )
        },function () {
            //error
        },function (template,i,elements) {
            //Calculo un 75% para la carga de las plantillas
            $UI.loading.setValue( ((i/elements)*0.75) +0.05);
        }
        );
    });
})
            
</script>
</head>
<body>
<!-- butons -->
<div id="sample-info">
</div>
<div id="sample-buttons" class="sample-btn">
</div>
<div id="lyr_loading">
    <div id="lyr_loading_background"></div>
    <div id="lyr_loading_logo" class="ui_logo"></div>
</div>
</body>
</html>

core/controls/controls_gamepad_v01.js


var $CONTROLS = $CONTROLS || {};

$CONTROLS.FirstPersonControls = function ( object, domElement ) {

    this.object = object;
    this.target = new THREE.Vector3( 0, 0, 0 );

    this.domElement = ( domElement !== undefined ) ? domElement : document;

    this.enabled = true;

    this.eyeY=2;
    this.movementSpeed = 3.5;
    this.movementSpeedRun = 6.0;
    this.lookSpeed = 0.02;

    this.mouseX = 0;
    this.mouseY = 0;

    this.lon = 0;
    this.theta = 0;

    this.moveForward = false;
    this.moveBackward = false;
    this.moveLeft = false;
    this.moveRight = false;
    this.run = false;
    this.jump = false;
    this.showPosition=false;
    
    this.minX=0;
    this.maxX=256;
    this.minZ=0;
    this.maxZ=256;

    this.viewHalfX = 0;
    
    this.hasAPIGamepad= ("getGamepads" in navigator);
    this.haveEventsGamepad = ('ongamepadconnected' in window);
    this.gamepad=null;
    
    if ( this.domElement !== document ) {
        this.domElement.setAttribute( 'tabindex', - 1 );
    }

    this.handleResize = function () {

        if ( this.domElement === document ) {
            this.viewHalfX = window.innerWidth / 2;
        } else {
            this.viewHalfX = this.domElement.offsetWidth / 2;
        }

    };

    this.getPosition = function ( ) {
        return this.object.position;
    }
    
    this.showPosition = function () {
        var o=document.createElement('div');
        o.id="panelInfoControls";
        document.body.appendChild(o);
        this.panelInfo=o;
        this.showPosition=true;
    }

    this.onMouseMove = function ( event ) {

        if ( this.domElement === document ) {

            this.mouseX = event.pageX - this.viewHalfX;


        } else {

            this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;

        }

    };

    this.onKeyDown = function ( event ) {

        switch ( event.keyCode ) {

            case 38: /*up*/
            case 87: /*W*/ this.moveForward = true; break;

            case 37: /*left*/
            case 65: /*A*/ this.moveLeft = true; break;

            case 40: /*down*/
            case 83: /*S*/ this.moveBackward = true; break;

            case 39: /*right*/
            case 68: /*D*/ this.moveRight = true; break;
            
            case 16: /*shift*/ this.run = true; break;

        }

    };

    this.onKeyUp = function ( event ) {

        switch ( event.keyCode ) {

            case 38: /*up*/
            case 87: /*W*/ this.moveForward = false; break;

            case 37: /*left*/
            case 65: /*A*/ this.moveLeft = false; break;

            case 40: /*down*/
            case 83: /*S*/ this.moveBackward = false; break;

            case 39: /*right*/
            case 68: /*D*/ this.moveRight = false; break;

            case 16: /*shift*/ this.run = false; break;

        }

    };

    this.update = function( delta ) {
        var bMoveForward=this.moveForward;
        var bMoveBackward=this.moveBackward;
        var bMoveLeft=this.moveLeft;
        var bMoveRight=this.moveRight;
        
        var actualLookSpeed = delta * this.lookSpeed;
        var nRotate=this.mouseX * actualLookSpeed;
        var bRun = this.run;
        
        if (this.hasAPIGamepad) {
            this.gamepad=navigator.getGamepads()[0];
            if (this.gamepad!=null) {
                bMoveRight=bMoveRight || (this.gamepad.axes[0]>0.3);
                bMoveLeft=bMoveLeft || (this.gamepad.axes[0]<-0.3);
                bMoveBackward=bMoveBackward || (this.gamepad.axes[1]>0.3);
                bMoveForward=bMoveForward || (this.gamepad.axes[1]<-0.3);
                if (this.gamepad.axes.length>2){
                    nRotate=this.gamepad.axes[2]*1500 * actualLookSpeed;
                }
                bRun = bRun || this.gamepad.buttons[4].pressed;
            }
        }
        if ( this.enabled === false ) return;

        var actualMoveSpeed = delta * (bRun?this.movementSpeedRun:this.movementSpeed);

        if ( bMoveForward) this.object.translateZ( - (actualMoveSpeed) );
        if ( bMoveBackward) this.object.translateZ( actualMoveSpeed );

        if ( bMoveLeft) this.object.translateX( - actualMoveSpeed );
        if ( bMoveRight) this.object.translateX( actualMoveSpeed );

        this.object.position.y=this.eyeY;
        if (this.minX>this.object.position.x) {
            this.object.position.x=this.minX;
        } else if (this.maxX<this.object.position.x) {
            this.object.position.x=this.maxX;
        }
        if (this.minZ>this.object.position.z) {
            this.object.position.z=this.minZ;
        } else if (this.maxZ<this.object.position.z) {
            this.object.position.z=this.maxZ;
        }
        if (this.showPosition) {
            this.panelInfo.innerHTML=" x: "+Math.round(this.object.position.x,0.1)+" z: "+Math.round(this.object.position.z,0.1)+" ";
        }

        this.lon += nRotate;
        this.theta = THREE.Math.degToRad( this.lon );

        var targetPosition = this.target,
        position = this.object.position;

        targetPosition.x = position.x + 100 * Math.cos( this.theta );
        targetPosition.z = position.z + 100 * Math.sin( this.theta );

        this.object.lookAt( targetPosition );

    };

    this.dispose = function() {
        this.domElement.removeEventListener( 'mousemove', _onMouseMove, false );
        window.removeEventListener( 'keydown', _onKeyDown, false );
        window.removeEventListener( 'keyup', _onKeyUp, false );
    }

    var _onMouseMove = bind( this, this.onMouseMove );
    var _onKeyDown = bind( this, this.onKeyDown );
    var _onKeyUp = bind( this, this.onKeyUp );

    this.domElement.addEventListener( 'mousemove', _onMouseMove, false );
    window.addEventListener( 'keydown', _onKeyDown, false );
    window.addEventListener( 'keyup', _onKeyUp, false );

    function bind( scope, fn ) {
        return function () {
            fn.apply( scope, arguments );
        };
    }

    this.handleResize();

};

core/ai/ai_random_v01.js


var $AIS = $AIS || {};

$AIS.RandomAI = function (object, prop) {
    this._object=object;
    this.velocity=3; //unidades por segundo
    if (prop.velocity){
        this.velocity=prop.velocity;
    }
    this.minX=prop.minX;
    this.maxX=prop.maxX;
    this.minZ=prop.minZ;
    this.maxZ=prop.maxZ;
    this.directionWalk = new THREE.Vector3(0.5, 0, 0.5);
    this.changeDirection();
};

$AIS.RandomAI.prototype.changeDirection = function () {
    this._lastRandomX = Math.random();
    this._lastRandomZ = 1 - this._lastRandomX;
    if (Math.random() < 0.5) {
        this._lastRandomX = this._lastRandomX * -1;
    }
    if (Math.random() < 0.5) {
        this._lastRandomZ = this._lastRandomZ * -1;
    }
    this.directionWalk.x = this._lastRandomX;
    this.directionWalk.z = this._lastRandomZ;
    var pos = this.directionWalk.clone();
    pos.add(this._object.position);
    this._object.lookAt(pos);
}

$AIS.RandomAI.prototype.update = function ( delta ) {
    var p=this._object.position;
    var x=p.x+ this.directionWalk.x * this.velocity * delta;
    var z=p.z+ this.directionWalk.z * this.velocity * delta;
    var bChange=false;
    if (x<this.minX) {
        x=this.minX;bChange=true;
    } else if (x>this.maxX) {
        x=this.maxX;bChange=true;
    };
    if (z<this.minZ) {
        z=this.minZ;bChange=true;
    } else if (z>this.maxZ) {
        z=this.maxZ;bChange=true;
    };
    if (bChange) {
        this.changeDirection();
    };
    p.set(x, p.y, z)
}

$AIS.RandomAI.prototype.getPosition = function ( ) {
    return this._object.position;
}

core/ai/ai_path_v01.js



var $AIS = $AIS || {};

$AIS.PathAI = function (object, prop) {
    var vecs=[];
    for (var i=0;i 1) {this._pos = 0;};
    this._object.lookAt(this.path.getPointAt(this._pos));
}

$AIS.PathAI.prototype.showPath = function ( ) {
    var geometry = new THREE.Geometry();
    var points = this.path.getPoints(50);

    var material = new THREE.LineBasicMaterial({
        color: 0xff00f0
    });

    geometry.vertices = points;
    var line = new THREE.Line(geometry, material);
    line.position.set(0,0.25,0)
    $WORLD.scene.add(line);
}

$AIS.PathAI.prototype.getPosition = function ( ) {
    return this._object.position;
}

core/world/template3D_v01.js


var $RG = $RG || {};
$RG.templates=[];

$RG.Types = $RG.Types || {};
$RG.Types.type3D = { "OBJ": 0, "DAE":1, "JSON":2, "SPRITE":3 };

$RG.loadTemplates = function(fSuc, fFail, fProgress) {
    var i=0;
    var list=Object.keys($RG.templates);
    var _load = function () {
        if (list.length==i) {
            fSuc();
            return;
        }
        var ent=$RG.templates[list[i]].template3D=new $RG.Template3D(list[i]);
        if (fProgress) {fProgress(list[i],i+1,list.length);}
        i++;
        ent.load({},_load, fFail);
    }
    _load();
};

//CLASSE: Template3D    
$RG.Template3D = function (id) {
        this.id = id;
        this._template=$RG.templates[id];
        this.isReady = false;
        this.mesh = null; 
};

$RG.Template3D.prototype.load = function (oPars, fSuc, fFail) {
    var temp=this._template;
    if (!("type" in temp)) temp.type = $RG.Types.type3D.OBJ;
    if (temp.type == $RG.Types.type3D.OBJ) {
        this._loadOBJ(oPars,fSuc,fFail);
    } else if (temp.type == $RG.Types.type3D.DAE) {
        this._loadDAE(oPars,fSuc,fFail);
    } else if (temp.type == $RG.Types.type3D.SPRITE) {
        this._loadSPRITE(oPars,fSuc,fFail);
    } else {
        fFail();
    }
}

$RG.Template3D.prototype._loadOBJ = function (oPars, fSuc, fFail) {
        var $O = this;
        var onProgress = function (xhr) {    };
        var onError = function (xhr) { if (fFail) { fFail($O); } };
        var mtlLoader = new THREE.MTLLoader();
        var pathArray = $O._template.model.split('/');
        var mP = '';
        for (var i = 0; i < pathArray.length-1; i++) {
            mP += pathArray[i];
            mP += "/";
        }
        var model = pathArray[pathArray.length - 1];
        mtlLoader.setPath(mP);
        model=model.substr(0,model.length - 4)
        mtlLoader.load(model + '.mtl', function (materials) {
            materials.preload();
            var objLoader = new THREE.OBJLoader();
            objLoader.setMaterials(materials);
            objLoader.setPath(mP);
            objLoader.load(model + '.obj', function (object) {
                object.traverse(function (child) {
                    if (child instanceof THREE.Mesh) {
                        child.castShadow = true;
                    }
                });
                $O.mesh = object;
                $O.mesh.castShadow = true;
                $O.isReady = true;
                if (fSuc) { fSuc($O); }

            }, onProgress, onError);

        }, onProgress, onError);
};

$RG.Template3D.prototype._loadDAE = function (oPars, fSuc, fFail) {
    var $O = this;
    var temp=$O._template;
    var loader = new THREE.ColladaLoader();
    var onProgress = function (xhr) {    };
    var onError = function (xhr) { if (fFail) { fFail($O); } };
    loader.load(temp.model, function (collada) {
        var object = collada.scene;
        var mesh=null;
        object.traverse(function (child) {
            if (child instanceof THREE.Mesh) {
                child.castShadow = true;
                mesh=child;
               }
        });

        if (temp.scale) {
            mesh.scale.x = temp.scale.x;
            mesh.scale.y = temp.scale.y;
            mesh.scale.z = temp.scale.z; //Corregir escala
        }
        if (temp.rotate) {
            if (temp.rotate.x) {
                mesh.rotateX (temp.rotate.x * Math.PI / 180);
            };
            if (temp.rotate.y) {
                mesh.rotateY (temp.rotate.y * Math.PI / 180);
            };
            if (temp.rotate.z) {
                mesh.rotateZ (temp.rotate.z * Math.PI / 180);
            }//Corregir rotación
        }
        $O.mesh = object;
        $O.isReady = true;
        fSuc(mesh);
    }, onProgress, onError);
};

$RG.Template3D.prototype._loadSPRITE = function (oPars, fSuc, fFail) {
    var $O = this;
    var onProgress = function (xhr) {    };
    var onError = function (xhr) { if (fFail) { fFail($O); } };
    $WORLD.textureLoader.load($O._template.model, function (texture) {
        var mat = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: false, transparent: true,fog:true} );
        var object =new THREE.Sprite(mat);
        object.scale.y=$O._template.height;
        object.scale.x=$O._template.width;
        $O.mesh = object;
        $O.isReady = true;
        fSuc($O.mesh);
    }, onProgress, onError);
};

core/world/entity3D_v02.js


var $RG = $RG || {};
$RG.entities=[];

$RG.Entity3D = function (properties) {
    this.template=properties.template
    this.prop=properties;
    this.mesh=null;
    $RG.entities.push(this)
}

$RG.Entity3D.prototype.addToWorld = function () {
    var prop=this.prop;
    var templ=$RG.templates[prop.template];

    //Clonar la figura 3D, posicionar y rotar
    var mesh=templ.template3D.mesh.clone();
    var y=0
    mesh.position.set(prop.x, ((prop.y)?prop.y:0), prop.z);
    if (!(prop.rY)) prop.rY=0;
    if (templ.type=3) {
        mesh.translateY(templ.height/2-0.05);
    }
    mesh.rotateY(prop.rY * Math.PI / 180);
    this.mesh=mesh;
    
    //Animar el objeto si tienen una animación
    if (templ.animation) {
        mesh.traverse(function (child) {
            if (child instanceof THREE.SkinnedMesh) {
                var animation = new THREE.Animation(child, child.geometry.animation);
                animation.play();
            }
        })
    };
   
    //Aplicar la inteligencia artificial si hay definida
    if (templ.ai) {
    
        this.ai=new $AIS[templ.ai](this.mesh, this.prop);
        $WORLD.addToListUpdate (this.ai); 
    }
    $WORLD.scene.add(mesh);
    return mesh;
};

core/world/nature_v01.js


//****************************
// CREA LA NATURALEZA
//****************************

$WORLD.drawNature = function () {

        var nat=$WORLD.map.nature;
        //CARGAR EN MEMORIA TODOS LOS SPRITES
        var list=Object.keys(nat.patterns);
        for (var i=0;i<list.length;i++) {
            var pat=nat.patterns[list[i]];
            for (var n=0;n<pat.elements.length;n++) {
                var el=pat.elements[n];
                var mat = new THREE.SpriteMaterial( { map: $WORLD.textureLoader.load(el.object), useScreenCoordinates: false, transparent: true,fog:true} );
                var obj =new THREE.Sprite(mat);
                obj.scale.y=el.height;
                obj.scale.x=el.width;
                el._sprite = obj;
            }
        }
        //PARA CADA ZONA AÑADIR LOSaerboles
        for (var j=0;j<nat.zones.length;j++) {
            var zon=nat.zones[j];
            var pat=nat.patterns[zon.pattern];
            for (var x=zon.minX;x<zon.maxX-pat.freqX;x+=pat.freqX) {
                for (var z=zon.minZ;z<zon.maxZ-pat.freqZ;z+=pat.freqZ) {
                    var i=Math.round(Math.random()*(pat.elements.length-1));
                    var el=pat.elements[i];
                    var obj2=el._sprite.clone();z
                    obj2.position.set(x+(Math.random()*pat.freqX), el.height/2-0.05, z+(Math.random()*pat.freqZ));
                    $WORLD.scene.add(obj2);
                }
            }
        }
};

core/world/sky_v01.js


//****************************
// CREA EL CIELO, Y LAS LUCES
//****************************

$WORLD.sky= {
    update:function(delta){
        var p = $WORLD.controls.getPosition();
        $WORLD.sky.skyBox.position.set(p.x, 0, p.z);
    }    
};

$WORLD.drawSky = function () {
    var sky = $WORLD.map.sky;
    if (sky.type=="skybox"){
        $WORLD.drawSkybox(sky);
    } else if (sky.type=="skysphere" && sky.texture!="") {
        $WORLD.drawSkysphere(sky);
    } else {
        $WORLD.drawSkysphereNoImg(sky);
    }

    //CREAR LA LUZ DE AMBIENTE
    $WORLD.ambientLight.color = new THREE.Color(sky.colorAmbient);
    $WORLD.ambientLight.intensity = sky.intensityAmbient;

    //CREAR LA LUZ DEL SOL
    var light = new THREE.DirectionalLight(sky.sunlightcolor, sky.sunlightintensity);
    light.castShadow = true;
    light.shadow.mapSize.width = 2 * 512; 
    light.shadow.mapSize.height = 2 * 512;
    light.shadow.camera.near = 0;
    light.shadow.camera.far = 50; //ALTURA DEL CUBO

    //DES DEL PUNTO CENTRAL INDICAN EL CUADRADO.
    light.shadow.camera.top = 25; //X
    light.shadow.camera.right = 25;
    light.shadow.camera.left = -25;
    light.shadow.camera.bottom = -25;

    light.shadow.camera.visible = true;
    $WORLD.sky.skyBox.add(light);
    
    light.position.set(sky.sunlightposition.x, sky.sunlightposition.y, sky.sunlightposition.z); 
    light.target = $WORLD.sky.skyBox;
    
    $WORLD.scene.fog.near = sky.fogNear;
    if (sky.fogFar > 0 && ($WORLD.distance - $WORLD.distance / 4) > sky.fogFar) {
        $WORLD.scene.fog.far = sky.fogFar;
    }
    $WORLD.scene.fog.color = new THREE.Color(sky.fogColor);
    $WORLD.renderer.setClearColor($WORLD.scene.fog.color, 1);
    
    $WORLD.addToListUpdate ($WORLD.sky);
};

$WORLD.drawSkybox=function (sky){
    var cubemap = new THREE.CubeTextureLoader().load( sky.texture );
    cubemap.format = THREE.RGBFormat;
        
    var shader = THREE.ShaderLib['cube']; 
    shader.uniforms['tCube'].value = cubemap; 

    var skyBoxMaterial = new THREE.ShaderMaterial( {
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: shader.uniforms,
    depthWrite: false,
    side: THREE.BackSide
    });
    
    var distance=($WORLD.distance*2-20);
    var c = Math.pow ((distance*distance)/2,0.5);
    var skyBox = new THREE.Mesh(  new THREE.BoxGeometry(c, c, c),  skyBoxMaterial);
    $WORLD.scene.add(skyBox);
    $WORLD.sky.skyBox = skyBox;

};

$WORLD.drawSkysphere=function (sky){
    var skyTexture = $WORLD.textureLoader.load(sky.texture);
    var geometry = new THREE.SphereGeometry($WORLD.distance - 10, 30, 20);

    var uniforms = {
        texture: { type: 't', value: skyTexture }
    };
    var material = new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: "varying vec2 vUV;" +
        "\n" +
        "void main() {  " +
        "    vUV = uv;" +
        "    vec4 pos = vec4(position, 1.0);" +
        "    gl_Position = projectionMatrix * modelViewMatrix * pos;" +
        "}",
        fragmentShader: "uniform sampler2D texture;" +
        "varying vec2 vUV;" +
        "" +
        "    void main() {" +
        "        vec4 sample = texture2D(texture, vUV);" +
        "        gl_FragColor = vec4(sample.xyz, sample.w);" +
        "    }"
    });

    var skyBox = new THREE.Mesh(geometry, material);
    skyBox.scale.set(-1, 1, 1);
    skyBox.rotation.order = 'XZY';
    skyBox.renderDepth = $WORLD.distance;
    $WORLD.scene.add(skyBox);
    $WORLD.sky.skyBox = skyBox;
};

$WORLD.drawSkysphereNoImg=function (sky){

    var vertexShader ="varying vec3 vWorldPosition;"+
    " "+
    "void main() {"+
    "    vec4 worldPosition = modelMatrix * vec4( position, 1.0 );"+
    "    vWorldPosition = worldPosition.xyz;"+ //xyz
    " "+
    "    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );"+
    "}";

    var fragmentShader ="uniform vec3 topColor;"+
    "uniform vec3 bottomColor;"+
    "uniform float offset;"+
    "uniform float exponent;"+
    " "+
    "varying vec3 vWorldPosition;"+
    " "+
    "void main() {"+
    "    float h = normalize( vWorldPosition + offset ).y;"+
    "    gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( h, exponent ), 0.0 ) ), 1.0 );"+
    "}";

    var uniforms = {
            topColor: {type: "c", value: new THREE.Color(sky.topColor)}, bottomColor: {type: "c", value: new THREE.Color(sky.bottomColor)},
            offset: {type: "f", value: 0}, exponent: {type: "f", value: 0.5} 
    }
    var skyMaterial = new THREE.ShaderMaterial({vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide, fog: false});
     
    var skyBox = new THREE.Mesh( new THREE.SphereGeometry($WORLD.distance - 10, 30, 20), skyMaterial);

    skyBox.rotation.order = 'XZY';
    skyBox.renderDepth = $WORLD.distance;
    
    $WORLD.scene.add(skyBox);
    $WORLD.sky.skyBox = skyBox;
}

core/world/ground_v01.js


//****************************
// CREA EL SUELO DEL MUNDO
//****************************

$WORLD.drawGround = function () {
    var map = $WORLD.map;
    var groundTexture = $WORLD.textureLoader.load(map.ground.texture);
    var x = $WORLD.distance * 2.25 + map.x
    var z = $WORLD.distance * 2.25 + map.z
    groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
    groundTexture.repeat.set(x / 2, z / 2); 
    groundTexture.anisotropy = 16;
    var groundMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, map: groundTexture });
    var mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(x, z), groundMaterial);
    mesh.position.y = 0;
    mesh.position.x = map.x / 2;
    mesh.position.z = map.z / 2;
    mesh.rotation.x = - Math.PI / 2;
    mesh.receiveShadow = true;
    $WORLD.scene.add(mesh);
}

core/world/world_v01.js


//*******************************
//DEFINIR EL MUNDO
//*******************************
var $WORLD = $WORLD || {};
$WORLD.distance = 80;
$WORLD.renderer = null;
$WORLD.scene = null;
$WORLD.clock = null;
$WORLD.map=null;
$WORLD.controls=null;
$WORLD._objUpdate = [];

$WORLD.init3D=function(oPars, fSuc, fFail) {

    var renderer = new THREE.WebGLRenderer();
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    $WORLD.renderer = renderer;
    $WORLD.scene = new THREE.Scene();
    
    $WORLD.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, $WORLD.distance);
    $WORLD.camera.position.set(0, 2, 0);
    $WORLD.camera.lookAt(new THREE.Vector3(0,2,0) );
    
    $WORLD.clock = new THREE.Clock();
    $WORLD.controls={
        getPosition: function(){
            return $WORLD.camera.position;
        }
    } 

    $WORLD.textureLoader = new THREE.TextureLoader();
    
    $WORLD.ambientLight = new THREE.AmbientLight(0xffffff,1);
    $WORLD.scene.add($WORLD.ambientLight);
 
    $WORLD.scene.fog = new THREE.Fog(0xffffff, 5, ($WORLD.distance - $WORLD.distance / 4)); //niebla
    $WORLD.renderer.setClearColor($WORLD.scene.fog.color, 1);
    
    window.addEventListener('resize', onWindowResize, false);
    THREE.Loader.Handlers.add(/\.dds$/i, new THREE.DDSLoader());
    fSuc();
}

$WORLD.showStats=function() {
    if (!($WORLD.stats)) {
        $WORLD.stats = new Stats();
        $WORLD.stats.setMode(0);
        document.body.appendChild($WORLD.stats.domElement);
        $WORLD.addToListUpdate($WORLD.stats);
    };

}

$WORLD.startAnimation = function () {
    $WORLD.animate();
}

$WORLD.pauseAnimation = function () {
    window.cancelAnimationFrame( $WORLD.idAnim );
}

$WORLD.addToListUpdate = function (obj) {
    $WORLD._objUpdate.push(obj);
}

$WORLD.animate = function () {
    $WORLD.idAnim = requestAnimationFrame($WORLD.animate);
    var delta = $WORLD.clock.getDelta();
    for (var i = 0; i < $WORLD._objUpdate.length; i++) {
        $WORLD._objUpdate[i].update(delta);
    };
    THREE.AnimationHandler.update(delta);
    $WORLD.renderer.render($WORLD.scene, $WORLD.camera);

};

function onWindowResize() {
    $WORLD.camera.aspect = window.innerWidth / window.innerHeight;
    $WORLD.camera.updateProjectionMatrix();
    $WORLD.renderer.setSize(window.innerWidth, window.innerHeight);
}