Функция JavaScript включает только последний элемент (Three.js) - PullRequest
0 голосов
/ 12 ноября 2018

Я пытаюсь создать функцию генератора забора с помощью 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);

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Есть несколько вопросов.

  • Код создает менеджер загрузки для каждого забора. Вам нужен только один максимум
  • Код загружает один и тот же забор 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);
0 голосов
/ 12 ноября 2018

Есть пара проблем с вашим кодом, но я думаю, что проблема в старой 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) );

Проблема, вероятно, заключается в том, что все заборы абсолютно одинаковы, и из-за асинхронной операции все они рассчитаны на то же место и выглядят так, будто существует только один забор.

...