本文介绍了如何在动画循环中创建闭包(保护全局变量)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing and animation loop using three.js and all the examples (mrdoob, stemkoski) I see online use unprotected globals at the beginning of the script. I tried to enclose these in the init() function and then pass them as arguments through the animation loop. However, the renderer is coming up undefined.

我不确定下面我缺少什么。我的主要问题是如何了解建立具有良好闭合效果的动画循环的最佳实践(保护否则将是全局变量)。

I'm not sure what I'm missing below. My primary question is how to understand best practice for setting up an animation loop with good closure (protecting variables that would otherwise be global). Thanks!

// 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样式模块中重写了动画循环,该模块返回一个对象,该对象充满了可以访问现在受保护的变量的特权方法。这适用于寻找类似模式的任何人:

I followed @Bergi 's advice above and rewrote the animation loop in a Crockford style module that returns an object full of privileged methods that can access the now protected variables. Here it is for anyone looking for a similar pattern:

// ************************
// 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
};

这篇关于如何在动画循环中创建闭包(保护全局变量)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 10:13