Skip to content

Commit d4564c6

Browse files
committed
Add xr-active-switch.ts
1 parent 615fa1b commit d4564c6

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

xr-active-switch.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import {Component, Object3D} from '@wonderlandengine/api';
2+
import {property} from '@wonderlandengine/api/decorators.js';
3+
4+
const SCOPE_OPTIONS = ['this object', 'children only', 'this object & children'];
5+
const ACTION_OPTIONS = ['activate', 'deactivate', 'toggle', 'keep'];
6+
7+
/**
8+
* XR Active Switch Component for controlling component activation states
9+
* based on XR session status.
10+
*
11+
* This component allows toggling, activating, deactivating, or keeping the
12+
* current state of components when entering or exiting XR sessions.
13+
*
14+
* The scope of affected components can be limited to the current object,
15+
* its children, or both.
16+
*
17+
* Use this component to manage visibility, interactivity, or other properties
18+
* that depend on XR session states.
19+
*
20+
*/
21+
22+
export class XrActiveSwitch extends Component {
23+
static TypeName = 'xr-active-switch';
24+
25+
/** Action to perform when XR session starts */
26+
@property.enum(ACTION_OPTIONS)
27+
ifInXR: number = 0;
28+
29+
/** Action to perform when XR session ends */
30+
@property.enum(ACTION_OPTIONS)
31+
ifNotInXR: number = 1;
32+
33+
/** Scope of elements to affect */
34+
@property.enum(SCOPE_OPTIONS)
35+
scope: number = 2;
36+
37+
private components: Component[] = [];
38+
39+
start() {
40+
// Initial state setup
41+
this.applyAction(this.engine.xr?.session ? this.ifInXR : this.ifNotInXR);
42+
43+
// Bind event handlers
44+
this.engine.onXRSessionStart.add(this.onSessionStart);
45+
this.engine.onXRSessionEnd.add(this.onSessionEnd);
46+
}
47+
48+
onActivate() {
49+
this.engine.onXRSessionStart.add(this.onSessionStart);
50+
this.engine.onXRSessionEnd.add(this.onSessionEnd);
51+
}
52+
53+
onDeactivate() {
54+
this.engine.onXRSessionStart.remove(this.onSessionStart);
55+
this.engine.onXRSessionEnd.remove(this.onSessionEnd);
56+
}
57+
58+
private collectComponents() {
59+
const mode = this.scope;
60+
61+
// Handle current object
62+
if (mode === 0 || mode === 2) {
63+
this.object
64+
.getComponents()
65+
.filter((c) => c.type !== XrActiveSwitch.TypeName)
66+
.forEach((c) => this.components.push(c));
67+
}
68+
69+
// Handle children
70+
if (mode === 1 || mode === 2) {
71+
this.processChildren(this.object);
72+
}
73+
}
74+
75+
private processChildren(obj: Object3D) {
76+
for (const child of obj.children) {
77+
child
78+
.getComponents()
79+
.filter((c) => c.type !== XrActiveSwitch.TypeName)
80+
.forEach((c) => this.components.push(c));
81+
this.processChildren(child); // Recurse through all descendants
82+
}
83+
}
84+
85+
private applyAction(action: number) {
86+
this.components = [];
87+
this.collectComponents();
88+
for (const comp of this.components) {
89+
if (action === 0) {
90+
comp.active = true;
91+
} else if (action === 1) {
92+
comp.active = false;
93+
} else if (action === 2) {
94+
comp.active = !comp.active;
95+
}
96+
}
97+
}
98+
99+
private onSessionStart = () => {
100+
this.applyAction(this.ifInXR);
101+
};
102+
103+
private onSessionEnd = () => {
104+
this.applyAction(this.ifNotInXR);
105+
};
106+
}

0 commit comments

Comments
 (0)