import { ScriptBase } from '@ud-viz/game_browser';
import { constant } from '@ud-viz/game_shared_template';
import { Command } from '@ud-viz/game_shared';
import { Vector3 } from 'three';
/**
* @class Manages native commands for controlling object3D with different modes and options.
*/
export class ControllerNativeCommandManager extends ScriptBase {
constructor(context, object3D, variables) {
super(context, object3D, variables);
/** @type {Function} */
this._clickListener = null;
/** @type {string} */
this._currentMode = null;
}
/**
* Add native commands in input manager @see NativeCommandManager of @ud-viz/game_shared_template
*
* @param {string} object3DUUID - uuid of the object3D to contol
* @param {object} mode - which mode to controls object3D @see ControllerNativeCommandManager.MODE
* @param {object} options - options
* @param {boolean} [options.withMap=true] - z is not compute with map
*/
controls(object3DUUID, mode, options = { withMap: true }) {
if (this._currentMode) this.removeControls();
switch (mode.TYPE) {
case ControllerNativeCommandManager.MODE_TYPE.CLASSIC:
mode.KEYS_MAPPING.forEach(({ COMMAND_ID, COMMAND_TYPE, KEYS }) => {
this.context.inputManager.addKeyCommand(COMMAND_ID, KEYS, () => {
return new Command({
type: COMMAND_TYPE,
data: { object3DUUID: object3DUUID, withMap: options.withMap }, // object3D to control
});
});
});
break;
case ControllerNativeCommandManager.MODE_TYPE.START_END_MOUSE:
// keys
mode.KEYS_MAPPING.forEach(
({ COMMAND_ID, KEYS, COMMAND_TYPE_START, COMMAND_TYPE_END }) => {
let start = false;
this.context.inputManager.addKeyCommand(COMMAND_ID, KEYS, () => {
let oneKeyIsPressed = false;
KEYS.forEach((key) => {
oneKeyIsPressed =
oneKeyIsPressed || this.context.inputManager.isPressed(key);
});
if (oneKeyIsPressed && !start) {
start = true;
this.context.inputManager.setPointerLock(true);
return new Command({
type: COMMAND_TYPE_START,
data: {
object3DUUID: object3DUUID,
withMap: options.withMap,
},
});
} else if (!oneKeyIsPressed && start) {
start = false; // reset
return new Command({
type: COMMAND_TYPE_END,
data: {
object3DUUID: object3DUUID,
withMap: options.withMap,
},
});
}
});
}
);
// mouse
this.context.inputManager.addMouseCommand(
mode.MOUSE.MOVE.COMMAND_ID,
'mousemove',
(event) => {
if (
this.context.inputManager.getPointerLock() ||
(this.context.inputManager.mouseState.isDragging() &&
!this.context.inputManager.getPointerLock())
) {
if (event.movementX != 0 || event.movementY != 0) {
let pixelX = -event.movementX;
let pixelY = -event.movementY;
pixelX *= ControllerNativeCommandManager.MOUSE_SENSITIVITY;
pixelY *= ControllerNativeCommandManager.MOUSE_SENSITIVITY;
return new Command({
type: ControllerNativeCommandManager.MODE[2].MOUSE.MOVE
.COMMAND_TYPE,
data: {
object3DUUID: object3DUUID,
vector: new Vector3(pixelY, 0, pixelX),
},
});
}
}
return null;
}
);
// exit pointer lock method
this._clickListener = () => {
this.context.inputManager.setPointerLock(false);
};
this.context.inputManager.addMouseInput(
this.context.inputManager.element,
'click',
this._clickListener
);
break;
default:
throw new Error('Unknown controller type');
}
this._currentMode = mode;
}
/**
* Remove native commands in input manager
*/
removeControls() {
switch (this._currentMode.TYPE) {
case ControllerNativeCommandManager.MODE_TYPE.CLASSIC:
{
this._currentMode.KEYS_MAPPING.forEach(({ COMMAND_ID, KEYS }) => {
this.context.inputManager.removeKeyCommand(COMMAND_ID, KEYS);
});
}
break;
case ControllerNativeCommandManager.MODE_TYPE.START_END_MOUSE:
{
this._currentMode.KEYS_MAPPING.forEach(({ COMMAND_ID, KEYS }) => {
this.context.inputManager.removeKeyCommand(COMMAND_ID, KEYS);
});
this.context.inputManager.removeMouseCommand(
this._currentMode.MOUSE.MOVE.COMMAND_ID,
'mousemove'
);
this.context.inputManager.removeInputListener(this._clickListener);
this.context.inputManager.setPointerLock(false);
}
break;
default:
throw new Error('current controller mode type is corrupted');
}
this._currentMode = null;
}
/**
* Different controller mode to move game object3d @see NativeCommandManager which will receive commands
*
* @returns {object} - different mode of controls
*/
static get MODE() {
return {
/**
* Can move forward and backward and rotateZ left and right
*/
1: {
TYPE: ControllerNativeCommandManager.MODE_TYPE.CLASSIC,
KEYS_MAPPING: [
{
COMMAND_ID: 'controller_mode_1_forward_id',
COMMAND_TYPE: constant.COMMAND.MOVE_FORWARD,
KEYS: ['z', 'ArrowUp'],
},
{
COMMAND_ID: 'controller_mode_1_backward_id',
COMMAND_TYPE: constant.COMMAND.MOVE_BACKWARD,
KEYS: ['s', 'ArrowDown'],
},
{
COMMAND_ID: 'controller_mode_1_rotate_left_id',
COMMAND_TYPE: constant.COMMAND.ROTATE_LEFT,
KEYS: ['q', 'ArrowLeft'],
},
{
COMMAND_ID: 'controller_mode_1_rotate_right_id',
COMMAND_TYPE: constant.COMMAND.ROTATE_RIGHT,
KEYS: ['d', 'ArrowRight'],
},
],
},
/**
* Can move forward and backward left and right and rotate with mouse
*/
2: {
TYPE: ControllerNativeCommandManager.MODE_TYPE.START_END_MOUSE,
MOUSE: {
MOVE: {
COMMAND_ID: 'controller_mode_2_mouse_move',
COMMAND_TYPE: constant.COMMAND.ROTATE,
},
},
KEYS_MAPPING: [
{
COMMAND_ID: 'controller_mode_2_forward_id',
KEYS: ['z', 'ArrowUp'],
COMMAND_TYPE_START: constant.COMMAND.MOVE_FORWARD_START,
COMMAND_TYPE_END: constant.COMMAND.MOVE_FORWARD_END,
},
{
COMMAND_ID: 'controller_mode_2_backward_id',
KEYS: ['s', 'ArrowDown'],
COMMAND_TYPE_START: constant.COMMAND.MOVE_BACKWARD_START,
COMMAND_TYPE_END: constant.COMMAND.MOVE_BACKWARD_END,
},
{
COMMAND_ID: 'controller_mode_2_right_id',
KEYS: ['d', 'ArrowRight'],
COMMAND_TYPE_START: constant.COMMAND.MOVE_RIGHT_START,
COMMAND_TYPE_END: constant.COMMAND.MOVE_RIGHT_END,
},
{
COMMAND_ID: 'controller_mode_2_left_id',
KEYS: ['q', 'ArrowLeft'],
COMMAND_TYPE_START: constant.COMMAND.MOVE_LEFT_START,
COMMAND_TYPE_END: constant.COMMAND.MOVE_LEFT_END,
},
],
},
/**
* Can move forward, backward, up and down. Can rotateZ left and right
*/
3: {
TYPE: ControllerNativeCommandManager.MODE_TYPE.CLASSIC,
KEYS_MAPPING: [
{
COMMAND_ID: 'controller_mode_3_forward_id',
COMMAND_TYPE: constant.COMMAND.MOVE_FORWARD,
KEYS: ['z', 'ArrowUp'],
},
{
COMMAND_ID: 'controller_mode_3_backward_id',
COMMAND_TYPE: constant.COMMAND.MOVE_BACKWARD,
KEYS: ['s', 'ArrowDown'],
},
{
COMMAND_ID: 'controller_mode_3_move_up_id',
COMMAND_TYPE: constant.COMMAND.MOVE_UP,
KEYS: ['Shift'],
},
{
COMMAND_ID: 'controller_mode_3_move_down_id',
COMMAND_TYPE: constant.COMMAND.MOVE_DOWN,
KEYS: ['Control'],
},
{
COMMAND_ID: 'controller_mode_3_rotate_left_id',
COMMAND_TYPE: constant.COMMAND.ROTATE_LEFT,
KEYS: ['q', 'ArrowLeft'],
},
{
COMMAND_ID: 'controller_mode_3_rotate_right_id',
COMMAND_TYPE: constant.COMMAND.ROTATE_RIGHT,
KEYS: ['d', 'ArrowRight'],
},
],
},
};
}
static get ID_SCRIPT() {
return constant.ID_SCRIPT.CONTROLLER_NATIVE_COMMAND_MANAGER;
}
}
ControllerNativeCommandManager.MOUSE_SENSITIVITY = 0.5;
ControllerNativeCommandManager.MODE_TYPE = {
CLASSIC: 'classic',
START_END_MOUSE: 'start_end_mouse',
};