Dynamic Instantiation with for-loop

Hi everyone, I am trying to use Dynamic Instantiation with for loop to create ‘Plane’ according to an array and what I am getting here, the ‘Plane’ was created one by one after the other. Is this the correct way how Spark AR are executing the script?

I am using project example from Spark AR Documentation website, you guys can download it here

And here’s my code, I modified a bit by adding for-loop to create the ‘Plane’

// Load in the required modules
const Scene = require('Scene');
const Materials = require('Materials');
const TouchGestures = require('TouchGestures');

// Enables async/await in JS [part 1]
(async function () {
	let arr = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];

	// Locate the focal distance object in the Scene panel and the material in the Materials panel
	const [focalDistance, material] = await Promise.all([
		Scene.root.findFirst('Focal Distance'),
		Materials.findFirst('material0'),
	]);

	// Dynamically instantiate a plane and set initial properties
	for (let index = 0; index < arr.length; index++) {
		const dynamicPlane = await Scene.create("Plane", {
			"name": "Dynamic Plane" + index,
			"width": 0.1,
			"height": 0.1,
			"x": 0.15 * index,
			"y": 0,
			"hidden": false,
			"material": material,
		});

		// Add the dynamic plane as a child of the Focal Distance object in the Scene panel
		focalDistance.addChild(dynamicPlane);

		// Destroy the dynamic plane when tapped
		TouchGestures.onTap(dynamicPlane).subscribe((gesture) => {
			Scene.destroy(dynamicPlane);
		});
	}
})();

Here are the demo video
Dynamic Instantiation

I tend to use the blocks module to instantiate blocks. You get more flexibility and control over the object that way, even if it’s just a plane.

In terms of the way you are instantiating, I think you could use Promise.all to run the loop in parallel instead of serial. Right now it’s waiting to create each plane before moving on to the next one.

const planePromises = arr.map((v, i) => {
  return Scene.create("Plane", {...})
})
const planes = await Promise.all(planePromises)
planes.forEach(plane => {
  // add plane to scene, add touch event
})
1 Like

Great, it’s working! Thanks Josh

But I have one more question and the question is related to Javascript. How can I map multidimension array?

Because I need to create Column Plane under Row Plane

I tried to create something like this

(async function () {

	let arr = [
		[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
		[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
	];

	const [focalDistance, material] = await Promise.all([
		Scene.root.findFirst('Focal Distance'),
		Materials.findFirst('material0'),
	]);

	const row = arr[0].map((row, i) => {
		return arr.map((col, i) => {
			return Scene.create("Plane", {
				"name": "Row" + row,
				"width": 0.05 * arr[0].length,
				"height": 0.05,
				"x": 0.15,
				"y": 0.15 * i,
				"hidden": false,
				"material": material,
			})
			return Scene.create("Plane", {
				"name": "Col" + col,
				"width": 0.05 * arr[0].length,
				"height": 0.05,
				"x": 0.15,
				"y": 0.15 * i,
				"hidden": false,
				"material": material,
			})
		})
	})
	
	const rows = await Promise.all(row)
	rows.forEach(row => {
		focalDistance.addChild(row);
	})
})();

But I got this error

You can’t return more than one value. Once you use the return keyword, the function exits, so any returns after that are essentially dead code.

Anyway, you only need to create one plane in each callback. I think maybe there’s some confusion about the row and columns though. I’m not sure I get it, but from my perspective, each element in the array is part of a row and a column at the same time.

Here’s some code to illustrate.


arr.map((rowArr, y) => {
    return rowArr.map((colIndex, x) => {
        return [x, y]
    })
})

Screenshot 2022-11-22 at 10.08.54 AM

1 Like