这是我参与8月更文挑战的第29天,活动详情查看: 8月更文挑战
Spark AR Studio 使用响应式编程模型的一种方法是允许你将值视为信号,这些信号是包含一个可以随时间变化的值的特殊对象。
信号可以绑定到对象的属性,这样当信号的值改变时,对象属性的值就会自动更新。
对于基本数据类型,有一些等效信号,包括数字(ScalarSignal【监控数值标量的信号】)、字符串(StringSignal【监控字符串的信号】)和布尔值(BoolSignal【监控布尔的信号】)。
绑定对象到对象属性
将信号绑定到对象的语法与执行标准赋值相同。
在下面的例子中,我们将来自源对象(用户的脸)的信号绑定到目标对象(plane,平面)上。因此,当 FaceTracking.face(0).cameratransform.rotationY 的信号变化时,plane.transform.x 的值就会被更新。
// Load in the required modules
const Scene = require('Scene');
const FaceTracking = require('FaceTracking');
// Enables async/await in JS [part 1]
(async function() {
// Locate the plane we've added to the Scene panel
const plane = await Scene.root.findFirst('plane0');
// Bind the user's face rotation in the Y-axis to the X-position of our plane
plane.transform.x = FaceTracking.face(0).cameraTransform.rotationY;
// Enables async/await in JS [part 2]
})();
该语句被视为信号绑定,因为赋值操作符(=)的左边值是响应对象,右边值是信号。
如果右值是标准 Scalar、String 或 Bool 类型,则该语句将被视为标准赋值。
转换值为信号
当将数字、字符串或布尔值传递给需要信号的函数或属性设置器(Setter)时,该值会隐式转换为常量信号:
// Load in the required modules
const FaceTracking = require('FaceTracking');
// Enables async/await in JS [part 1]
(async function() {
// The numerical value 0.1 is automatically converted to a ScalarSignal
const mouthOpen = FaceTracking.face(0).mouth.openness.gt(0.1);
// Enables async/await in JS [part 2]
})();
您还可以使用 ReactiveModule 类公开的 val() 方法显式地将原始数据类型转换为其等效信号(稍后将在用信号进行操作详细介绍这个类)。下面的示例将 Scalar(数值)值转换为 ScalarSignal 。
// Load in the required modules
const FaceTracking = require('FaceTracking');
const Reactive = require('Reactive');
// Enables async/await in JS [part 1]
(async function() {
// Convert the numerical value 0.1 to a ScalarSignal
const scalarSignal = Reactive.val(0.1);
// Use the converted value
const mouthOpen = FaceTracking.face(0).mouth.openness.gt(scalarSignal);
// Enables async/await in JS [part 2]
})();
您可以使用相同的方法将布尔值转换为 BoolSignal,或将字符串转换为 StringSignal 。
// Load in the required modules
const Reactive = require('Reactive');
// Enables async/await in JS [part 1]
(async function() {
// Convert the bool value 'true' to a BoolSignal
const boolSignal = Reactive.val(true);
// Convert the string value to a StringSignal
const stringSignal = Reactive.val("This is a string");
// Enables async/await in JS [part 2]
})();
从信号中检索值
如果你需要检索一个信号包含的值,你可以使用由 ScalarSignal, StringSignal 和 BoolSignal 类公开的 pinLastValue() 方法:
// Load in the required modules
const Diagnostics = require('Diagnostics');
const FaceTracking = require('FaceTracking');
// Enables async/await in JS [part 1]
(async function() {
// Get the value of mouth openness when this line of code is executed
const mouthOpennessValue = FaceTracking.face(0).mouth.openness.pinLastValue();
// Log the value
Diagnostics.log(mouthOpennessValue);
// Enables async/await in JS [part 2]
})();
当值随时间变化时,将返回调用方法之前信号所包含的最后一个值。
或者,可以通过 subscribeWithSnapshot() 方法订阅事件,该方法提供信号的值,以便在回调函数中使用:
// Load in the required modules
const Diagnostics = require('Diagnostics');
const FaceTracking = require('FaceTracking');
const TouchGestures = require('TouchGestures');
// Enables async/await in JS [part 1]
(async function() {
// Subscribe to tap gestures
TouchGestures.onTap().subscribeWithSnapshot({
// Get the value of mouth openness when the tap gesture is detected
'val' : FaceTracking.face(0).mouth.openness
}, function (gesture, snapshot) {
// Log the value from the snapshot
Diagnostics.log(snapshot.val);
});
// Enables async/await in JS [part 2]
})();
用信号进行操作
由于它们的值随时间而变化,标准的 JavaScript 操作符,如 +、-、* 和 / 不能直接在信号上执行。
作为替代,这些类型的计算是通过 ReactiveModule 类和 ScalarSignal 类公开的方法执行的,如下面的示例所示。
// Load in modules
const Diagnostics = require('Diagnostics');
const Reactive = require('Reactive');
// Enables async/await in JS [part 1]
(async function() {
// Create a new scalar signal with an initial value of 5
const originalValue = Reactive.val(5);
// Add 1 to the signal with the add() method exposed by the ScalarSignal
// class and store the result in a new variable
const valuePlusOne = originalValue.add(1);
// Add 2 to the signal with the add() method exposed by the ReactiveModule
// class and store the result in a new variable
const valuePlusTwo = Reactive.add(originalValue, 2);
// Multiply the signal by 2 with the mul() method exposed by the ReactiveModule
// class and store the result in a new variable
const valueDoubled = Reactive.mul(originalValue, 2);
// Log the signals' values to the console
Diagnostics.log(originalValue.pinLastValue());
Diagnostics.log(valuePlusOne.pinLastValue());
Diagnostics.log(valuePlusTwo.pinLastValue());
Diagnostics.log(valueDoubled.pinLastValue());
// Enables async/await in JS [part 2]
})();
此外,BoolSignal 和 StringSignal 类公开了它们自己的一组用于操作信号的方法:
// Load in modules
const Diagnostics = require('Diagnostics');
const Reactive = require('Reactive');
// Enables async/await in JS [part 1]
(async function() {
// Create a BoolSignal object
const boolSignal = Reactive.val(true);
// Perform a logical 'not' operation with boolSignal and store the result in a new variable
const newBool = boolSignal.not();
// Create a StringSignal object
const stringSignal = Reactive.val("This is a string");
// Concatenate 'stringSignal' with a new string and store the result in a new variable
const newString = stringSignal.concat(" made longer.");
// Log the signals' values to the console
Diagnostics.log(boolSignal.pinLastValue());
Diagnostics.log(newBool.pinLastValue());
Diagnostics.log(stringSignal.pinLastValue());
Diagnostics.log(newString.pinLastValue());
// Enables async/await in JS [part 2]
})();
监视一个信号的值
由 DiagnosticsModule (支持诊断日志记录)类暴露的 watch() 方法允许您向 Spark AR Studio 中 的 watch 视图添加一个信号,以监控其值如何随时间变化。
// Load in the required modules
const Diagnostics = require('Diagnostics');
const FaceTracking = require('FaceTracking');
// Add the mouth openness signal to the watch view
Diagnostics.watch("Mouth Openness - ", FaceTracking.face(0).mouth.openness);
观察视图出现在控制台的右上方: