UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

313 lines (312 loc) 10.6 kB
"use strict"; import { TypedCameraControlsEventNode } from "./_BaseCameraControls"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { EventConnectionPoint, EventConnectionPointType } from "../utils/io/connections/Event"; import { MobileJoystickControls, DEFAULT_PARAMS } from "../../../modules/core/controls/MobileJoystickControls"; import { CameraControlsNodeType, NodeContext } from "../../poly/NodeContext"; import { CorePlayer } from "../../../core/player/Player"; import { isBooleanTrue } from "../../../core/Type"; import { CollisionController } from "./collision/CollisionController"; import { CapsuleSopOperation } from "../../operations/sop/Capsule"; const EVENT_START = "start"; const EVENT_CHANGE = "change"; const EVENT_END = "end"; function updatePlayerParamsCallbackOption() { return { cook: false, callback: (node) => { MobileJoystickControlsEventNode.PARAM_CALLBACK_updatePlayerParams(node); } }; } class MobileJoystickEventParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); this.main = ParamConfig.FOLDER(); /** @param collider object */ this.colliderObject = ParamConfig.NODE_PATH("", { nodeSelection: { context: NodeContext.SOP }, // if the node is dependent, // the MobileJoystickControlsEventNode will be re-created when this node changes // which we do not want, as it will act like a hard reset // when all we want is to update the collider dependentOnFoundNode: false, callback: (node) => { MobileJoystickControlsEventNode.PARAM_CALLBACK_updateCollider(node); } }); /** @param collision Capsule Radius */ this.capsuleRadius = ParamConfig.FLOAT(CapsuleSopOperation.DEFAULT_PARAMS.radius, { range: [0, 1], rangeLocked: [true, false], ...updatePlayerParamsCallbackOption() }); /** @param collision Capsule Height */ this.capsuleHeight = ParamConfig.FLOAT(CapsuleSopOperation.DEFAULT_PARAMS.height, { range: [0, 2], rangeLocked: [true, false], ...updatePlayerParamsCallbackOption() }); this.physics = ParamConfig.FOLDER(); /** @param physics Steps */ this.physicsSteps = ParamConfig.INTEGER(5, { range: [1, 10], rangeLocked: [true, false], ...updatePlayerParamsCallbackOption() }); /** @param gravity */ this.gravity = ParamConfig.VECTOR3([0, -30, 0], { ...updatePlayerParamsCallbackOption() }); /** @param translation speed */ this.translateSpeed = ParamConfig.FLOAT(1); /** @param rotation speed */ this.rotateSpeed = ParamConfig.FLOAT(DEFAULT_PARAMS.rotateSpeed); /** @param specify a custom HTML element */ this.customTranslateElement = ParamConfig.BOOLEAN(false, { separatorBefore: true }); /** @param jump HTML element selector */ this.translateElementSelector = ParamConfig.STRING("#translate-element", { visibleIf: { customTranslateElement: true } }); /** @param jump Allowed */ this.jumpAllowed = ParamConfig.BOOLEAN(true, { separatorBefore: true, ...updatePlayerParamsCallbackOption() }); /** @param jump Force */ this.jumpStrength = ParamConfig.FLOAT(10, { range: [0, 100], rangeLocked: [true, false], ...updatePlayerParamsCallbackOption() }); /** @param specify a custom HTML element */ this.customJumpElement = ParamConfig.BOOLEAN(false, { visibleIf: { jumpAllowed: true } }); /** @param jump HTML element selector */ this.jumpElementSelector = ParamConfig.STRING("#jump-element", { visibleIf: { jumpAllowed: true, customJumpElement: true } }); /** @param run Allowed */ this.runAllowed = ParamConfig.BOOLEAN(true, { separatorBefore: true, ...updatePlayerParamsCallbackOption() }); /** @param run speed mult */ this.runSpeedMult = ParamConfig.FLOAT(2, { range: [0, 10], rangeLocked: [true, false], ...updatePlayerParamsCallbackOption() }); /** @param specify a custom HTML element */ this.customRunElement = ParamConfig.BOOLEAN(false, { visibleIf: { runAllowed: true } }); /** @param jump HTML element selector */ this.runElementSelector = ParamConfig.STRING("#run-element", { visibleIf: { runAllowed: true, customRunElement: true } }); /** @param recompute colliding geo */ this.updateCollider = ParamConfig.BUTTON(null, { separatorBefore: true, callback: (node) => { MobileJoystickControlsEventNode.PARAM_CALLBACK_updateCollider(node); } }); this.init = ParamConfig.FOLDER(); /** @param start Position */ this.startPosition = ParamConfig.VECTOR3([0, 2, 0], { ...updatePlayerParamsCallbackOption() }); /** @param start Position */ this.startRotation = ParamConfig.VECTOR3([0, 0, 0], { ...updatePlayerParamsCallbackOption() }); /** @param reset */ this.reset = ParamConfig.BUTTON(null, { callback: (node) => { MobileJoystickControlsEventNode.PARAM_CALLBACK_resetPlayer(node); } }); /** @param min polar angle */ this.minPolarAngle = ParamConfig.FLOAT("-$PI*0.5", { range: [-Math.PI, Math.PI], rangeLocked: [true, true] }); /** @param max polar angle */ this.maxPolarAngle = ParamConfig.FLOAT("$PI*0.5", { range: [-Math.PI, Math.PI], rangeLocked: [true, true] }); } } const ParamsConfig = new MobileJoystickEventParamsConfig(); const _MobileJoystickControlsEventNode = class extends TypedCameraControlsEventNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; this._controls_by_element_id = /* @__PURE__ */ new Map(); } static type() { return CameraControlsNodeType.MOBILE_JOYSTICK; } endEventName() { return "end"; } collisionController() { return this._collisionController = this._collisionController || new CollisionController(this); } initializeNode() { this.io.inputs.setNamedInputConnectionPoints([ new EventConnectionPoint( _MobileJoystickControlsEventNode.INPUT_UPDATE_COLLIDER, EventConnectionPointType.BASE, this._updateCollider.bind(this) ) ]); this.io.outputs.setNamedOutputConnectionPoints([ new EventConnectionPoint(EVENT_START, EventConnectionPointType.BASE), new EventConnectionPoint(EVENT_CHANGE, EventConnectionPointType.BASE), new EventConnectionPoint(EVENT_END, EventConnectionPointType.BASE) ]); } async createControlsInstance(camera, element) { await this._initPlayer(camera); function _getElement(options2) { if (!options2.actionAllowed) { return; } if (!options2.customElement) { return; } return document.querySelector(options2.selector) || void 0; } const translateDomElement = _getElement({ actionAllowed: true, customElement: this.pv.customTranslateElement, selector: this.pv.translateElementSelector }); const runDomElement = _getElement({ actionAllowed: this.pv.runAllowed, customElement: this.pv.customRunElement, selector: this.pv.runElementSelector }); const jumpDomElement = _getElement({ actionAllowed: this.pv.jumpAllowed, customElement: this.pv.customJumpElement, selector: this.pv.jumpElementSelector }); const options = { translateDomElement, runDomElement, jumpDomElement }; const controls = new MobileJoystickControls(camera, element, options, this._player); this._controls_by_element_id.set(element.id, controls); this._bind_listeners_to_controls_instance(controls); return controls; } async _initPlayer(camera) { const options = await this._playerOptions(camera); if (!options) { return; } this._player = this._player || new CorePlayer(options); this._player.setOptions(options); this._updatePlayerParams(); this._player.reset(); } async _playerOptions(camera) { const collider = await this.collisionController().getCollider(); if (!collider) { this.states.error.set("invalid collider"); return; } return { object: camera, collider }; } player() { return this._player; } async _updatePlayerParams() { if (!this._player) { return; } this._player.startPosition.copy(this.pv.startPosition); this._player.physicsSteps = this.pv.physicsSteps; this._player.jumpAllowed = isBooleanTrue(this.pv.jumpAllowed); this._player.jumpStrength = this.pv.jumpStrength; this._player.runAllowed = isBooleanTrue(this.pv.runAllowed); this._player.runSpeedMult = this.pv.runSpeedMult; this._player.gravity.copy(this.pv.gravity); this._player.speed = this.pv.translateSpeed; this._player.setCapsule({ radius: this.pv.capsuleRadius, height: this.pv.capsuleHeight, divisions: 5, center: CapsuleSopOperation.DEFAULT_PARAMS.center }); this._controls_by_element_id.forEach((controls) => controls.updateElements()); } _resetPlayer() { var _a; (_a = this._player) == null ? void 0 : _a.reset(); } async _updateCollider() { await this.collisionController().updateCollider(); } _bind_listeners_to_controls_instance(controls) { controls.addEventListener(EVENT_START, () => { this.dispatchEventToOutput(EVENT_START, {}); }); controls.addEventListener(EVENT_CHANGE, () => { this.dispatchEventToOutput(EVENT_CHANGE, {}); }); controls.addEventListener(EVENT_END, () => { this.dispatchEventToOutput(EVENT_END, {}); }); } updateRequired() { return true; } setupControls(controls) { controls.setRotationSpeed(this.pv.rotateSpeed); controls.setRotationRange({ min: this.pv.minPolarAngle, max: this.pv.maxPolarAngle }); controls.updateElements(); } disposeControlsForHtmlElementId(html_element_id) { const controls = this._controls_by_element_id.get(html_element_id); if (controls) { this._controls_by_element_id.delete(html_element_id); } } static PARAM_CALLBACK_updateCollider(node) { node._updateCollider(); } static PARAM_CALLBACK_updatePlayerParams(node) { node._updatePlayerParams(); } static PARAM_CALLBACK_resetPlayer(node) { node._resetPlayer(); } }; export let MobileJoystickControlsEventNode = _MobileJoystickControlsEventNode; MobileJoystickControlsEventNode.INPUT_UPDATE_COLLIDER = "updateCollider";