简体   繁体   English

JavaScript函数只会占用最后一个元素(Three.js)

[英]JavaScript function only shoes the last element (Three.js)

I'm trying to create a fence generator function with Three.js , but my function only return the last fence, I don't know why... 我正在尝试使用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);

There are a couple of problems with your code, but I think the issue is the old async problem. 您的代码有两个问题,但是我认为问题是旧的async问题。 Loaders are asynchronous, which means that the code is actually executed later, but your code assumes it is synchronous. 加载程序是异步的,这意味着代码实际上在以后执行,但是您的代码假定它是同步的。 Because of this, all your fences are reading the value when all the looping has been done, and they will usually only trigger after they are all done. 因此,完成所有循环后,所有篱笆都将读取value ,并且通常只有在全部完成之后才触发它们。 Here a way to refactor your function so it behaves as expected: 这是一种重构函数以使其按预期运行的方法:

 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) ); 

The issue is probably that all fences are exactly the same and, because of the async operation, all calculated to be in the same place, looking like there is only one fence. 问题可能是所有围墙都完全相同,并且由于异步操作,所有计算出的围墙都位于同一位置,就像只有一个围墙一样。

There's several issues. 有几个问题。

  • The code is creating a loading manager for every fence. 该代码正在为每个围栏创建一个加载管理器。 You only need one at most 您最多只需要一个
  • The code is loading the same fence 5 times. 该代码将相同的篱笆加载5次。 It should probably load it once and clone it 它可能应该加载一次并克隆它
  • The code is not doing anything with the loading manager except waiting for the scene but it's already getting the scene from the ColladLoader so it does't need the loading manager at all. 除了等待场景,代码没有对加载管理器做任何事情,但是它已经从ColladLoader获取场景,因此根本不需要加载管理器。 Loading managers are for helping wait on multiple things to load but it's only loading one thing 加载管理器用于帮助等待加载多个事物,但这仅加载一件事
  • yThe code is using value in a callback but there is only one instance of value. y代码在回调中使用value ,但是只有value的一个实例。 It will be the same in all the callbacks so all the fences will be at the exact same place. 所有回调都将是相同的,因此所有围栅都将位于完全相同的位置。

This should work. 这应该工作。

 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); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM