跳到主要内容
本页面由机器自动翻译,可能包含错误。 查看英文原文

参考

tact-js 包提供了从 JavaScript 控制 bHaptics 触觉设备的函数。它使您能够播放触觉模式、直接控制设备马达,以及管理触觉播放。

import Tact from "tact-js";

基于事件的触觉播放

播放绑定到特定事件的触觉模式(在 bHaptics Designer/Portal 中设计)。对于大多数应用程序,这些是推荐使用的函数。

play

play({ eventKey, startTime, intensityRatio, durationRatio, offsetX, offsetY, deviceIndex }: PlayParams): Promise<void>;

type PlayParams = {
eventKey: string; // Name of the haptic event
startTime?: number; // Playback start position in milliseconds
intensityRatio?: number; // Intensity multiplier [0.0 - 2.0]
durationRatio?: number; // Duration multiplier
offsetX?: number; // Rotation offset [0.0 - 360.0]
offsetY?: number; // Vertical offset [-0.5 - 0.5]
deviceIndex?: number; // Target device index
};

播放预定义的触觉事件。

参数

  • eventKey:触觉事件的名称。
  • startTime(可选):播放起始位置(以毫秒为单位)——事件的前 startTime 毫秒会被跳过。例如,以 startTime: 2000 播放一个 3,260ms 的事件时,只会播放最后的 1,260ms。(默认值:0
  • intensityRatio(可选):触觉 Intensity 倍数。有效范围:[0.0 - 2.0](默认值:1.0
  • durationRatio(可选):Duration 倍数。(默认值:1.0
  • offsetX(可选):将触觉逆时针旋转。有效范围:[0.0 - 360.0](默认值:0.0
  • offsetY(可选):将触觉上移或下移。有效范围:[-0.5 - 0.5](默认值:0.0
  • deviceIndex(可选):当连接了多个相同位置类型的设备时,作为目标的设备索引。(默认值:-1,不指定特定设备)

返回值

请求发送到 bHaptics Player 后,promise 会以无返回值(undefined)的形式 resolve。

请注意,即使事件键未注册,它也会正常 resolve——在这种情况下不会播放任何内容,也不会抛出错误。请使用 getEvent 检查事件键是否存在。

示例

import Tact from "tact-js";

const playExample = async () => {
await Tact.play({ eventKey: "heartbeat" });
};

const playMoreExample = async () => {
await Tact.play({
eventKey: "hit",
startTime: 0,
intensityRatio: 1.0,
durationRatio: 1.0,
offsetX: 180.0,
offsetY: 0.25,
});
};

playLoop

playLoop({ eventKey, intensityRatio, durationRatio, interval, maxCount, offsetX, offsetY, deviceIndex }: PlayLoopParams): Promise<number>;

type PlayLoopParams = {
eventKey: string; // Name of the haptic event
intensityRatio?: number; // Intensity multiplier [0.0 - 2.0]
durationRatio?: number; // Duration multiplier
interval: number; // Pause between repetitions (milliseconds)
maxCount: number; // Total number of plays
offsetX: number; // Rotation offset [0.0 - 360.0]
offsetY: number; // Vertical offset [-0.5 - 0.5]
deviceIndex?: number; // Target device index
};

将触觉事件循环播放指定的次数。

参数

  • eventKey:触觉事件的名称。
  • intensityRatio(可选):触觉 Intensity 倍数。有效范围:[0.0 - 2.0](默认值:1.0
  • durationRatio(可选):Duration 倍数。(默认值:1.0
  • interval:重复之间的暂停时间(以毫秒为单位),从一次播放结束到下一次播放开始进行测量。例如,以 interval: 500maxCount: 3 播放一个 460ms 的事件,会在约 2,380ms(460 + 500 + 460 + 500 + 460)后结束。
  • maxCount:播放触觉事件的总次数(包括第一次播放)。小于 1 的值会按 1 处理。
  • offsetX:将触觉逆时针旋转。有效范围:[0.0 - 360.0](默认值:0.0
  • offsetY:将触觉上移或下移。有效范围:[-0.5 - 0.5](默认值:0.0
  • deviceIndex(可选):当连接了多个相同位置类型的设备时,作为目标的设备索引。(默认值:-1,不指定特定设备)

返回值

标识此播放请求的请求 ID。

请注意,即使事件键未注册,也会返回请求 ID——在这种情况下不会播放任何内容。要停止循环播放的事件,请使用带有事件键的 stopstopAll

在循环运行期间,isPlayingByEventKey 在包括重复之间的 interval 暂停在内的整个区间内都返回 true

示例

import Tact from "tact-js";

const playLoopExample = async () => {
const requestId = await Tact.playLoop({
eventKey: "hit",
intensityRatio: 1.0,
durationRatio: 1.0,
interval: 1000,
maxCount: 5,
offsetX: 0.0,
offsetY: 0.0,
});

console.log(`Playback request ID: ${requestId}`);
};

直接播放触觉

如果您想在不使用事件的情况下播放触觉,请使用这些函数。

playDot

playDot({ position, motorValues, duration, deviceIndex }: PlayDotParams): Promise<number>;

type PlayDotParams = {
position: PositionType; // Device position type
motorValues: number[]; // Array of motor intensity values [0 - 100]
duration?: number; // Duration in milliseconds
deviceIndex?: number; // Target device index
};

在特定的触觉执行器上播放触觉反馈。

参数

  • position:要播放的触觉设备类型。请参考 PositionType enum
  • motorValues:每个马达的 Intensity 值数组。数组长度必须与设备中的马达数量一致。每个值必须为整数且在范围内。有效范围:[0 - 100]。
  • duration(可选):触觉反馈的 Duration(以毫秒为单位)。建议大于或等于 100
  • deviceIndex(可选):当连接了多个相同位置类型的设备时,作为目标的设备索引。(默认值:-1,不指定特定设备)

返回值

标识此播放请求的请求 ID。要停止播放,请使用 stopAll

请注意,参数不会在客户端进行验证——例如,即使 motorValues 的长度不正确或包含超出范围的值,也会返回请求 ID;在这种情况下,触觉可能根本不会播放。

示例

import Tact, { PositionType } from "tact-js";

const playDotExample = async () => {
const requestId = await Tact.playDot({
position: PositionType.ForearmL, // Left TactSleeve
motorValues: [100, 80, 60], // TactSleeve has 3 motors
duration: 100
});

console.log(`Playback request ID: ${requestId}`);
}

playPath

playPath({ position, x, y, intensity, duration, deviceIndex }: PlayPathParams): Promise<number>;

type PlayPathParams = {
position: PositionType; // Device position type
x: number[]; // Array of x coordinates [0.0 - 1.0]
y: number[]; // Array of y coordinates [0.0 - 1.0]
intensity: number[]; // Array of intensity values [0 - 100]
duration?: number; // Duration in milliseconds
deviceIndex?: number; // Target device index
};

沿指定的坐标播放触觉反馈。与控制单个马达的 playDot 不同,此方法为设备上的特定坐标指定触觉 Intensity。

在指定触觉位置时,playDot 提供离散控制,而 playPath 则更为连续。playDot 为单个执行器分配 Intensity,而 playPath 允许为特定坐标(X 轴和 Y 轴均在 0 到 1 之间)指定 Intensity,从而使附近的执行器相应地振动。

您可以指定多个坐标和多个 Intensity。请注意,列表中这些坐标周围的所有执行器都会同时激活,而不是依次激活。所有数组(xyintensity)的大小必须相同。

注意

如果 xyintensity 数组的长度不同,SDK 内部的 WebAssembly 模块会因不可恢复的错误而崩溃(已在 tact-js 2.0.4 中确认)——在重新加载页面之前,触觉将无法工作。在调用之前,请务必确保这三个数组的长度相同。

通过在逐渐改变值的同时持续调用此函数,您可以实现触觉点移动的效果。

Coordinate

参数

  • position:要播放的触觉设备类型。请参考 PositionType enum
  • x:触觉效果的 X 坐标数组。每个值必须在范围内:[0.0 - 1.0]
  • y:触觉效果的 Y 坐标数组。每个值必须在范围内:[0.0 - 1.0]
  • intensity:每个坐标的 Intensity 值数组。每个值必须为整数且在范围内:[0 - 100]
  • duration(可选):触觉反馈的 Duration(以毫秒为单位)。建议大于或等于 100
  • deviceIndex(可选):当连接了多个相同位置类型的设备时,作为目标的设备索引。(默认值:-1,不指定特定设备)

返回值

标识此播放请求的请求 ID。要停止播放,请使用 stopAll

示例

import Tact, { PositionType } from "tact-js";

const HAPTIC_PATHS = [
{
x: [0.738, 0.723, 0.709, 0.696, 0.682, 0.667, 0.653],
y: [0.680, 0.715, 0.749, 0.782, 0.816, 0.852, 0.885],
intensity: 20
},
{
x: [0.061, 0.072, 0.102, 0.184, 0.254, 0.310, 0.363],
y: [0.632, 0.587, 0.542, 0.498, 0.411, 0.366, 0.301],
intensity: 60
}
];

const TIME_OF_FRAME = 250; // milliseconds

const playPathExample = async () => {
const frames = HAPTIC_PATHS[0].x.length;

for (let i = 0; i < frames; i++) {
await Tact.playPath({
position: PositionType.Vest, // TactSuit Pro
x: HAPTIC_PATHS.map(point => point.x[i]),
y: HAPTIC_PATHS.map(point => point.y[i]),
intensity: HAPTIC_PATHS.map(point => point.intensity),
duration: TIME_OF_FRAME
});
await new Promise(resolve => setTimeout(resolve, TIME_OF_FRAME));
}
}

playGlove

playGlove({ position, motors, playtimes, shapes, repeatCount }: PlayGloveParams): Promise<number>;

type PlayGloveParams = {
position: PositionType; // GloveL or GloveR
motors: Int32Array; // Array of 8 motor intensity values [0 - 100]
playtimes: Int32Array; // Array of 8 time interval values
shapes: Int32Array; // Array of 8 waveform values
repeatCount: number; // Number of times to play the pattern
};

仅限 TactGlove。 在 TactGlove 上播放触觉,并对 Duration 和 Intensity 模式进行精细控制。与 playDot 相比,这提供了更详细的控制。

每个数组参数必须正好包含八个元素,对应手套中的每个马达。

参数

  • position:要播放的触觉设备类型。必须使用 PositionType.GloveLPositionType.GloveR

  • motors:由 8 个 Intensity 值组成的数组,每个马达一个。每个值必须为整数且在范围内:[0 - 100]

    Array Index马达所在位置…
    0拇指尖
    1食指尖
    2中指尖
    3无名指尖
    4小指尖
    5手腕处
    6手掌(拇指侧)
    7手掌(小指侧)
  • playtimes:由 8 个时间间隔值组成的数组。有效值为:

    ValueDuration
    15ms
    210ms
    420ms
    630ms
    840ms
  • shapes:由 8 个波形值组成的数组,用于控制 Intensity 随时间的变化方式:

    ValueWaveform Pattern
    0在该 Duration 内保持恒定 Intensity
    1从指定的 Intensity 开始并减小一半
    2从一半 Intensity 开始并增大至最大
  • repeatCount:播放 8 马达模式的总次数(包括第一次播放)。

返回值

标识此播放请求的请求 ID。要停止播放,请使用 stopAll

示例

import Tact, { PositionType } from "tact-js";

const playGloveExample = async () => {
const motors = new Int32Array([100, 100, 100, 100, 100, 100, 100, 100]);
const playtimes = new Int32Array([8, 8, 8, 8, 8, 8, 8, 8]);
const shapes = new Int32Array([2, 2, 2, 2, 2, 2, 2, 2]);

const requestId = await Tact.playGlove({
position: PositionType.GloveR,
motors,
playtimes,
shapes,
repeatCount: 3
});

console.log(`Playback request ID: ${requestId}`);
}

播放控制

pause

pause(eventKey: string): Promise<void>

暂停当前正在播放的特定触觉事件。

参数

  • eventKey:要暂停的触觉事件的名称。

示例

import Tact from "tact-js";

const playAndPauseExample = async () => {
await Tact.play({ eventKey: "dash" });
await new Promise(resolve => setTimeout(resolve, 1000));
await Tact.pause("dash");
}

resume

resume(eventKey: string): Promise<void>

恢复之前暂停的触觉事件。

参数

  • eventKey:要恢复的触觉事件的名称。

示例

import Tact from "tact-js";

const playPauseAndResumeExample = async () => {
await Tact.play({ eventKey: "dash" });
await new Promise(resolve => setTimeout(resolve, 1000));
await Tact.pause("dash");
await new Promise(resolve => setTimeout(resolve, 1000));
await Tact.resume("dash");
}

stop

stop(eventKey: string): Promise<void>

完全停止特定的触觉事件。

参数

  • eventKey:要停止的触觉事件的名称。

示例

import Tact from "tact-js";

const stopExample = async () => {
await Tact.play({ eventKey: "dash" });
await new Promise(resolve => setTimeout(resolve, 1000));
await Tact.stop("dash");
}

stopAll

stopAll(): Promise<void>

停止当前正在播放的所有触觉。

示例

import Tact from "tact-js";

const stopAllExample = async () => {
await Tact.play({ eventKey: "dash" });
await Tact.play({ eventKey: "heartbeat" });
await Tact.play({ eventKey: "hit" });
await Tact.play({ eventKey: "slash" });
await new Promise(resolve => setTimeout(resolve, 500));

await Tact.stopAll();
}

生命周期

init

init({ appId, apiKey }: InitParams): Promise<boolean>;

type InitParams = {
appId: string; // Your bHaptics App ID
apiKey: string; // Your bHaptics API Key
};

初始化 bHaptics SDK。在使用 SDK 中的任何其他函数之前,必须调用此函数。它会初始化 SDK 并建立与 bHaptics Player 的连接。

参数

  • appId:来自 bHaptics Developer Portal 的 bHaptics 应用程序 ID
  • apiKey:来自 bHaptics Developer Portal 的 bHaptics API 密钥

返回值

初始化成功时返回 true,否则返回 false

示例

import Tact from "tact-js";

const initTact = async () => {
const result = await Tact.init({
appId: "your-app-id",
apiKey: "your-api-key",
});

console.log(result ? "Connection Success!" : "Connection Failed...");
}

状态检查

getConnectedDevices

getConnectedDevices(): Promise<any[]>

获取所有已连接触觉设备的列表。

返回值

已连接设备对象的数组。当没有设备连接时返回空数组([])。每个对象具有以下字段:

FieldTypeDescription
positionnumber设备的数字位置:0 Vest、1 ForearmL、2 ForearmR、3 Head、4 HandL、5 HandR、6 FootL、7 FootR、8 GloveL、9 GloveR。使用 PositionUtils.positionToType(position) 可将其转换为 PositionType
deviceNamestring设备的显示名称(例如 "TactGlove (L)")。
addressstring设备的 MAC 地址。与 ping 一起使用。
connectedboolean设备当前是否已连接。
pairedboolean设备是否已在 bHaptics Player 中配对。
batterynumber电池电量(百分比)。
audioJackInboolean是否插入了音频插头(音频配件设备)。
vsmnumber在 bHaptics Player 中配置的振动强度设置。

返回值的示例如下:

[
{
"position": 8,
"deviceName": "TactGlove (L)",
"address": "F418EB165E99",
"connected": true,
"paired": true,
"battery": 91,
"audioJackIn": false,
"vsm": 20
},
{
"position": 9,
"deviceName": "TactGlove (R)",
"address": "DF8B33412EC5",
"connected": true,
"paired": true,
"battery": 84,
"audioJackIn": false,
"vsm": 20
}
]

示例

import Tact from "tact-js";

const showDevicesExample = async () => {
const devices = await Tact.getConnectedDevices();
console.log("Connected devices:", devices);
}

getHapticMappings

getHapticMappings(): Promise<any[]>

获取当前触觉应用程序中注册的所有触觉事件(从 bHaptics Developer Portal 部署)的列表。

返回值

触觉映射对象的数组。每个对象具有以下字段:

FieldTypeDescription
eventNamestring事件键。与 play 及其他基于事件的函数一起使用。
eventTimenumber事件的 Duration(以毫秒为单位)。

返回值的示例如下:

[
{
"eventName": "punch-recoil",
"eventTime": 180
},
{
"eventName": "dash",
"eventTime": 3260
},
{
"eventName": "teleport",
"eventTime": 460
}
]

示例

import Tact from "tact-js";

const showMappingsExample = async () => {
const mappings = await Tact.getHapticMappings();

for (const mapping of mappings) {
console.log(`${mapping.eventName}: ${mapping.eventTime}ms`);
}
}

getEvent

getEvent(eventKey: string): Promise<number>

获取已注册触觉事件的 Duration。

参数

  • eventKey:要查询的触觉事件的名称。

返回值

事件的 Duration(以毫秒为单位)。如果事件键未注册,则返回 0——您可以用它在调用 play 之前检查事件键是否存在。

示例

import Tact from "tact-js";

const getEventExample = async () => {
const duration = await Tact.getEvent("dash");

if (duration > 0) {
console.log(`dash is ${duration}ms long`);
} else {
console.log("dash is not registered");
}
}

isDeviceConnected

isDeviceConnected(position: PositionType): Promise<boolean>

检查特定设备类型是否已连接。

参数

返回值

如果该设备类型已连接则返回 true,否则返回 false

示例

import Tact, { PositionType } from "tact-js";

const isDeviceConnectedExample = async () => {
const isGloveConnected = await Tact.isDeviceConnected(PositionType.GloveR);
console.log("Right TactGlove connected:", isGloveConnected);
}

isConnected

isConnected(): Promise<boolean>

检查与 bHaptics Player 的连接状态。

返回值

如果已连接到 bHaptics Player 则返回 true,否则返回 false

isPlaying

isPlaying(): Promise<boolean>

检查当前是否有任何触觉反馈正在播放。

返回值

如果有任何触觉正在播放则返回 true,否则返回 false

isPlayingByEventKey

isPlayingByEventKey(eventKey: string): Promise<boolean>

检查特定触觉事件当前是否正在播放。

参数

  • eventKey:要检查的触觉事件的名称

返回值

如果指定的触觉事件正在播放则返回 true,否则返回 false

设备控制

ping

ping(address: string): Promise<void>

向特定设备发送 ping 信号以测试连接。

参数

  • address:触觉设备的 MAC 地址。您可以通过 getConnectedDevices() 获取该地址

示例

import Tact from "tact-js";

const pingFirstDeviceExample = async () => {
const devices = await Tact.getConnectedDevices();

if (devices.length > 0) {
await Tact.ping(devices[0].address);
}
}

pingAll

pingAll(): Promise<void>

向所有已连接的设备发送 ping 信号。

motorTest

motorTest(): Promise<void>

在 TactSuit Pro(Vest)上运行马达测试序列:32 个马达位置中的每一个都会以最大 Intensity 依次触发一秒钟。整个序列大约需要 32 秒;返回的 promise 会在序列结束时 resolve。

请注意,此测试仅涵盖 Vest 位置——它不会测试其他设备类型。

通用 Enum

PositionType

enum PositionType {
Vest = "Vest",
ForearmL = "ForearmL",
ForearmR = "ForearmR",
Head = "Head",
HandL = "HandL",
HandR = "HandR",
FootL = "FootL",
FootR = "FootR",
GloveL = "GloveL",
GloveR = "GloveR"
}

字符串 enum。用它来确定触觉设备的类型。

ValueDeviceMotors Count
VestTactSuit Pro32
ForearmLTactSleeve(Left)3
ForearmRTactSleeve(Right)3
HeadTactVisor4
HandLTactosy for Hands(Left)3
HandRTactosy for Hands(Right)3
FootLTactosy for Feet(Left)3
FootRTactosy for Feet(Right)3
GloveLTactGlove(Left)8
GloveRTactGlove(Right)8

tact-js 还导出了一个 PositionUtils 类,其中包含用于在 getConnectedDevices 使用的数字位置与 PositionType enum 之间进行转换的静态辅助方法:

import { PositionType, PositionUtils } from "tact-js";

PositionUtils.positionToType(9); // PositionType.GloveR
PositionUtils.enumToPosition(PositionType.Vest); // 0