playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
227 lines (226 loc) • 5.58 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { EventHandler } from "../../core/event-handler.js";
import { Pose } from "./pose.js";
class InputDelta {
/**
* @param {number | number[]} arg - The size of the delta or an array of initial values.
*/
constructor(arg) {
/**
* @type {number[]}
* @private
*/
__publicField(this, "_value");
if (Array.isArray(arg)) {
this._value = arg.slice();
} else {
this._value = new Array(+arg).fill(0);
}
}
/**
* Adds another InputDelta instance to this one.
*
* @param {InputDelta} other - The other InputDelta instance to add.
* @returns {InputDelta} Self for chaining.
*/
add(other) {
for (let i = 0; i < this._value.length; i++) {
this._value[i] += other._value[i] || 0;
}
return this;
}
/**
* Appends offsets to the current delta values.
*
* @param {number[]} offsets - The offsets.
* @returns {InputDelta} Self for chaining.
*/
append(offsets) {
for (let i = 0; i < this._value.length; i++) {
this._value[i] += offsets[i] || 0;
}
return this;
}
/**
* Copies the values from another InputDelta instance to this one.
*
* @param {InputDelta} other - The other InputDelta instance to copy from.
* @returns {InputDelta} Self for chaining.
*/
copy(other) {
for (let i = 0; i < this._value.length; i++) {
this._value[i] = other._value[i] || 0;
}
return this;
}
/**
* The magnitude of the delta, calculated as the square root of the sum of squares
* of the values.
*
* @returns {number} - The magnitude of the delta.
*/
length() {
let sum = 0;
for (const value of this._value) {
sum += value * value;
}
return Math.sqrt(sum);
}
/**
* Returns the current value of the delta and resets it to zero.
*
* @returns {number[]} - The current value of the delta.
*/
read() {
const value = this._value.slice();
this._value.fill(0);
return value;
}
}
class InputFrame {
/**
* @param {T} data - The input frame data, where each key corresponds to an input delta.
*/
constructor(data) {
/**
* @type {{ [K in keyof T]: InputDelta }}
*/
__publicField(
this,
"deltas",
/** @type {{ [K in keyof T]: InputDelta }} */
{}
);
for (const name in data) {
this.deltas[name] = new InputDelta(data[name]);
}
}
/**
* Returns the current frame state and resets the deltas to zero.
*
* @returns {{ [K in keyof T]: number[] }} - The flushed input frame with current deltas.
*/
read() {
const frame = (
/** @type {{ [K in keyof T]: number[] }} */
{}
);
for (const name in this.deltas) {
frame[name] = this.deltas[name].read();
}
return frame;
}
}
class InputSource extends InputFrame {
constructor() {
super(...arguments);
/**
* @type {HTMLElement | null}
* @protected
*/
__publicField(this, "_element", null);
/**
* @type {EventHandler}
* @private
*/
__publicField(this, "_events", new EventHandler());
}
/**
* Adds an event listener for the specified event.
*
* @param {string} event - The event name to listen for.
* @param {HandleEventCallback} callback - The callback function to execute when the event is
* triggered.
*/
on(event, callback) {
this._events.on(event, callback);
}
/**
* Removes an event listener for the specified event.
*
* @param {string} event - The event name to stop listening for.
* @param {HandleEventCallback} callback - The callback function to remove.
*/
off(event, callback) {
this._events.off(event, callback);
}
/**
* Fires an event with the given name and arguments.
*
* @param {string} event - The event name to fire.
* @param {...any} args - The arguments to pass to the event listeners.
*/
fire(event, ...args) {
this._events.fire(event, ...args);
}
/**
* @param {HTMLElement} element - The element.
*/
attach(element) {
if (this._element) {
this.detach();
}
this._element = element;
}
detach() {
if (!this._element) {
return;
}
this._element = null;
this.read();
}
destroy() {
this.detach();
this._events.off();
}
}
class InputConsumer {
/**
* @param {InputFrame} frame - The input frame.
* @param {number} dt - The delta time.
* @returns {any} - The controller pose.
*/
update(frame, dt) {
frame.read();
}
}
class InputController extends InputConsumer {
constructor() {
super(...arguments);
/**
* @type {Pose}
* @protected
*/
__publicField(this, "_pose", new Pose());
}
/**
* @param {Pose} pose - The initial pose of the controller.
* @param {boolean} [smooth] - Whether to smooth the transition.
*/
attach(pose, smooth = true) {
}
detach() {
}
/**
* @param {InputFrame} frame - The input frame.
* @param {number} dt - The delta time.
* @returns {Pose} - The controller pose.
* @override
*/
update(frame, dt) {
super.update(frame, dt);
return this._pose;
}
destroy() {
this.detach();
}
}
export {
InputConsumer,
InputController,
InputDelta,
InputFrame,
InputSource
};