如何在动画循环中创建闭包(保护全局变量)



我正在使用三个.js和所有示例(mrdoob,stemkoski)编写和动画循环,我看到在线在脚本开头使用未受保护的全局变量。我试图将它们包含在 init() 函数中,然后通过动画循环将它们作为参数传递。但是,渲染器未定义。

我不确定我在下面错过了什么。我的主要问题是如何理解设置具有良好闭包的动画循环的最佳实践(保护本来是全局的变量)。谢谢!

// THE MAIN ANIMATION LOOP:
// UPDATE the scene
function update(keyboard, controls, stats, clock) {
    // delta = change in time since last call (in seconds)
    var delta = clock.getDelta(); 
    // functionality provided by THREEx.KeyboardState.js    
    if ( keyboard.pressed("z") ) 
    { 
        // do something
    }
    controls.update();
    stats.update();
};
// RENDER the scene
function render(renderer, scene, camera) {
    renderer.render(scene, camera);
};
// ANIMATE the scene
function animate(scene, camera, renderer, controls, stats, keyboard, clock) {
    requestAnimationFrame(animate);
    render(renderer, scene, camera);        
    update(keyboard, controls, stats, clock);
};

// *********************
// INITIALIZES THE SCENE
function init(images) { // `images` is passed by a callback from loadImages
    // standard global variables, held privately
    var container, scene, camera, renderer, controls, stats;
    var keyboard = new THREEx.KeyboardState();
    var clock = new THREE.Clock();
    ///////////
    // SCENE //
    ///////////
    scene = new THREE.Scene();
    ////////////
    // CAMERA //
    ////////////
    // set the view size in pixels (custom or according to window size)
    var SCREEN_WIDTH = 1920, SCREEN_HEIGHT = 1080;
    // var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;     
    // camera attributes
    var VIEW_ANGLE = 20, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
    // set up camera
    camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
    // add the camera to the scene
    scene.add(camera);
    // the camera defaults to position (0,0,0)
    //  so pull it back (z = 400) and up (y = 100) and set the angle towards the scene origin
    // (x,y,z)
    camera.position.set(0,150,1000);
    camera.lookAt(scene.position);  
    //////////////
    // RENDERER //
    //////////////
    // create and start the renderer; choose antialias setting.
    if (Detector.webgl)
        renderer = new THREE.WebGLRenderer( {antialias:true} );
    else
        renderer = new THREE.CanvasRenderer(); 
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    // attach div element to variable to contain the renderer
    container = document.getElementById( 'ThreeJS' );
    // attach renderer to the container div
    container.appendChild( renderer.domElement );
    ///////////
    // STATS //
    ///////////
    // displays current and past frames per second attained by scene
    stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.bottom = '0px';
    stats.domElement.style.zIndex = 100;
    container.appendChild( stats.domElement );
    ///////////
    // LIGHT //
    ///////////
    // create a light
    var light = new THREE.PointLight(0xffffff);
    light.position.set(100,250,0);
    scene.add(light);
    ////////////
    // IMAGES //
    ////////////
    var element1 = THREE.ImageUtils.loadTexture(images.dresser10);
    var element2 = THREE.ImageUtils.loadTexture(images.dresser14);
    var element1Material = new THREE.SpriteMaterial( { map: element1, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft  } );
    var sprite = new THREE.Sprite(element1Material);
    sprite.position.set( 50, 50, 0 );
    sprite.scale.set( 64, 64, 1.0 ); // imageWidth, imageHeight
    scene.add(sprite);

    animate(container, scene, camera, renderer, controls, stats, keyboard, clock);      
};

// ********************************************************
// CHECKS TO SEE IF THE WINDOW HAS LOADED BEFORE PROCEEDING
// Once the window is loaded, calls the init function
window.addEventListener ("load", eventWindowLoaded, false);
function eventWindowLoaded() {
    loadImages(init); // calls to initialize the scene once the images are loaded
}

我按照上面的@Bergi的建议,在Crockford风格的模块中重写了动画循环,该模块返回了一个充满特权方法的对象,可以访问现在受保护的变量。这里适用于任何寻找类似模式的人:

// ************************
// THE MAIN ANIMATION LOOP:
var animLoop = (function () {
    // standard global variables, held privately in this module
    var container, scene, camera, renderer, controls, stats;
    var keyboard = new THREEx.KeyboardState();
    var clock = new THREE.Clock();
    // SCENE
    scene = new THREE.Scene();
    // CAMERA
    var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;    
    var VIEW_ANGLE = 20, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
    camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
    scene.add(camera);
    camera.position.set(0,150,1000);
    camera.lookAt(scene.position);  
    // RENDERER
    if (Detector.webgl) {
        renderer = new THREE.WebGLRenderer( {antialias:true} );
    } else {
        renderer = new THREE.CanvasRenderer();
    } 
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    container = document.getElementById( 'ThreeJS' );
    container.appendChild( renderer.domElement );
    // LIGHT
    var light = new THREE.PointLight(0xffffff);
    light.position.set(100,250,0);
    scene.add(light);
    // IMAGES
    var images;
    var element1, element2, element1Material, sprite;   
    // RETURN:
    // *** returns an object full of functions with priviledged access to the private variables listed above ***
    return { 
        setImages: function (images_) { // sets the value of the images (array) above
            images = images_; 
        },
        createSprites: function () {
            var element1 = THREE.ImageUtils.loadTexture(images.dresser10.src);
            var element1Material = new THREE.SpriteMaterial( { map: element1, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft  } );
            var sprite = new THREE.Sprite(element1Material);
            sprite.position.set( 50, 50, 0 );
            sprite.scale.set( 64, 64, 1.0 );
            scene.add(sprite);  
        },
        update: function () {
            var delta = clock.getDelta();
            // functionality provided by THREEx.KeyboardState.js    
            if ( keyboard.pressed("z") ) 
            { 
                // do something
            }
        },
        render: function () {
            renderer.render(scene, camera);
        }
    };
}());

// ANIMATE the scene
function animate() {
        requestAnimationFrame( animate );
        animLoop.render();  
        animLoop.update();
};
// INITIALIZES THE SCENE
function init(images) { // `images` is passed by a callback not included here
    animLoop.setImages(images); // places the initial array of images as a private variable in the animLoop object    
    animLoop.createSprites();
    animate();      
};
window.addEventListener ("load", eventWindowLoaded, false);
function eventWindowLoaded() {
    loadImages(init); // calls to initialize the scene once the images are loaded
};

相关内容

  • 没有找到相关文章

最新更新