【问题标题】:JavaScript function only shoes the last element (Three.js)JavaScript 函数只支持最后一个元素(Three.js)
【发布时间】:2018-11-12 10:13:13
【问题描述】:

我正在尝试用 Three.js 创建一个栅栏生成器函数,但我的函数只返回最后一个栅栏,我不知道为什么...

function generateFence(nb){
  var i;
  var value = -5;
  var loadingManager;
  for(i = 0; i < nb ; i++) {
    var arrayFence = [];
    loadingManager = new THREE.LoadingManager( function () {
      scene.add( arrayFence[i] );
    });

    var loader = new THREE.ColladaLoader( loadingManager );
    loader.load( 'fence/model.dae', function ( collada ) {
      arrayFence[i] = collada.scene;
      arrayFence[i].position.x = value;
      arrayFence[i].position.z = -5;
    });
    value = value + 3;      
  }
}

generateFence(3);

【问题讨论】:

  • 您要在每个循环中创建一个新围栏?
  • 你在哪里记录结果?由于所有这些操作都是异步的,因此您的函数将不会返回任何栅栏。此外,如果您正在观察输出,由于异步 all 您的 value 属性将是最后一个值道具。将value = value + 3 移动到您的回调内部,以便为添加的每个围栏增加它。

标签: javascript arrays function loops three.js


【解决方案1】:

您的代码存在一些问题,但我认为问题是旧的async 问题。加载器是异步的,这意味着代码实际上是稍后执行的,但您的代码假定它是同步的。正因为如此,当所有的循环完成后,你所有的栅栏都在读取value,它们通常只会在它们全部完成后触发。这是一种重构函数的方法,使其按预期运行:

function generateFence(nb){
  
  // First we will load the model once, as we want to reuse it.
  // Lets wrap it in a promise so its easier to use later.
  
  const value = -5;
  const fences = new THREE.Group;
  const model = new Promise(function( resolve ){
  
    THREE.ColladaLoader( loadingManager ).load( 'fence/model.dae', resolve );
    
  });
  
  // Use a `let` declaration to ensure that each loop remembers 
  // what the value for i was wen it ran, even if you perform an async operation.
  
  for( let i = 0; i < nb; i++ ){
    
    // The bit after `then` happens asynchronously, waiting until the model is loaded
    // Because of this, we need to ensure we don't rely too much on values defined in the synchronous loop.
    
    model.then(model => {
      
      // Let's clone it so we create copies of the one model
      
      const fence = model.scene.clone();
      
      // Calculate the x position based on value and the current state of i.
      
      fence.position.set( value + i * 3, 0, -5 );
      fences.add( fence );
      
    });
    
  }
  
  return fences;
  
}

// Returns a THREE.Group. When the fences are loaded, they will 
// be added to the group, which is already an invisible part of the scene.
scene.add( generateFence(3) );

问题可能是所有栅栏都完全相同,并且由于异步操作,所有栅栏都计算在同一个地方,看起来只有一个栅栏。

【讨论】:

    【解决方案2】:

    有几个问题。

    • 代码正在为每个栅栏创建一个加载管理器。您最多只需要一个
    • 代码加载同一个栅栏 5 次。它可能应该加载一次并克隆它
    • 代码除了等待场景外,没有对加载管理器进行任何操作,但它已经从 ColladLoader 获取场景,因此它根本不需要加载管理器。加载管理器用于帮助等待加载多个内容,但它只加载一个内容
    • y代码在回调中使用value,但只有一个值实例。在所有回调中都是相同的,所以所有的栅栏都在同一个地方。

    这应该可行。

    function generateFence(nb){
      const loader = new THREE.ColladaLoader();
      loader.load( 'fence/model.dae', function ( collada ) {
        const copy = collada.scene.clone();
        scene.add(copy);
        let value = -5;
        for(var i = 0; i < nb ; i++) {
          copy.position.x = value;
          copy.position.z = -5;
          value = value + 3;
        }
      });
    }
    
    generateFence(3);

    【讨论】:

      猜你喜欢
      • 2021-03-11
      • 1970-01-01
      • 2014-04-07
      • 2020-07-09
      • 2012-01-27
      • 2021-05-16
      • 1970-01-01
      • 2017-04-08
      • 1970-01-01
      相关资源
      最近更新 更多