import { Utils } from '@uino/base-thing';
import { MathUtils, EventType, CodeType, KeyCodeType } from '@uino/thing';
import { InteractType } from '../const';
import { CameraAttachedComponent } from './CameraAttachedComponent'
const cPickerGroupName = 'flycontrol-lockpointer';
const cPickerPriority = 101 * 101;
const __ = {
private: Symbol('private'),
}
function _initPrivateMembers(that) {
that[__.private] = {};
const _private = that[__.private];
const _protected = that[that._protected];
// that.setMinPitch(-45);
// that.setMaxPitch(60);
_private._moveSpeed = 1.0;
_private._triggerMoveForward = false;
_private._triggerMoveBack = false;
_private._triggerMoveUp = false;
_private._triggerMoveDown = false;
_private._triggerMoveLeft = false;
_private._triggerMoveRight = false;
_private._triggerTurnLeft = false;
_private._triggerTurnRight = false;
_private._triggerJump = false;
_private._triggerFly = false;
_private._raycaster = { origin: [], direction: [0, -1, 0] };
_private._focus = true;
_private._mouseDownEnable = true;
_private._mouseMoveEnable = true;
_private._clearInteractWhenFocusOut = true;
_private._eyeHeight = 1.0;
_private._isFirstPersonView = true;
_private._thirdPersonCameraDis = 2.5;
_private._playerTurning = 0;
_private._playerState = InteractType.Idle;
_private._curJumpSpeed = 0;
_private._gravity = 9.8;
_private._useLocalUp = false;
_private._center = [0, 0];
_private._shiftDown = false;
_private._ctrlDown = false;
_private._altDown = false;
_private._interactInfo = {
Idle: { actionName: "Idle", actionSpeed: 1.0 },
MoveLeft: { actionName: "MoveLeft", actionSpeed: 1.0 },
MoveRight: { actionName: "MoveRight", actionSpeed: 1.0 },
MoveUp: { actionName: "MoveUp", actionSpeed: 1.0 },
MoveDown: { actionName: "MoveDown", actionSpeed: 1.0 },
Walk: { actionName: "Walk", actionSpeed: 1.0, speed: 1.0 },
Run: { actionName: "Run", actionSpeed: 1.0, speed: 5.0 },
Jump: { actionName: "Jump", actionSpeed: 1.0, speed: 5.0 },
FlyUp: { actionName: "FlyUp", actionSpeed: 1.0, speed: 10.0 },
Fly: { actionName: "Fly", actionSpeed: 1.0, speed: 5.0 },
FlyDown: { actionName: "FlyDown", actionSpeed: 1.0, speed: 10.0 }
};
_private._hotKeyMap = {
ForwardKey: CodeType.KeyW,
BackwardKey: CodeType.KeyS,
LeftwardKey: CodeType.KeyA,
RightwardKey: CodeType.KeyD,
UpwardKey: CodeType.KeyR,
DownwardKey: CodeType.KeyT,
TurnLeftKey: CodeType.KeyQ,
TurnRightKey: CodeType.KeyE,
FlyKey: CodeType.KeyF,
JumpKey: CodeType.Space
}
// for jump
_private._oriPlayerPos = [0,0,0]
_private.JumpHeight = 0;
// for fly
_private.ZeroHeight = 0;
_private.MinFlyHeight = 5;
_private.MaxFlyHeight = 15;
// pointer lock
_private.focusUI = null;
_private.pickedObject = null;
_private.pointerLockEnable = true;
_private.pointerLockState = "Unlock";
_private._documentDelegate = Utils.createObject("DocumentDelegate");
_private.checkCollison = (pos) => {
_private._raycaster.origin = pos;
for(let i = 0; i < _private._floorobj.length; i++){
let floorobj = _private._floorobj[i]
const tempArr = floorobj.raycast(_private._raycaster);
if (tempArr.length > 0) {
return false;
}
}
return true;
}
_private.move = (offset) => {
var object_pos = MathUtils.addVector(that.object.position, offset);
if (_private._playerState == InteractType.Fly) {
that.object.position = object_pos;
let height = that.object.position[1];
if (height > _private.MaxFlyHeight) {
that.object.position = [that.object.position[0], _private.MaxFlyHeight, that.object.position[2]];
}
else if (height < _private.MinFlyHeight) {
that.object.position = [that.object.position[0], _private.MinFlyHeight, that.object.position[2]];
}
}
else if (!_private.checkCollison(object_pos)) {
that.object.position = object_pos;
}
}
_private.clearInteractEffect = () => {
_private._triggerMoveForward = false;
_private._triggerMoveBack = false;
_private._triggerMoveUp = false;
_private._triggerMoveDown = false;
_private._triggerMoveLeft = false;
_private._triggerMoveRight = false;
_private._triggerTurnLeft = false;
_private._triggerTurnRight = false;
_private._triggerJump = false;
_private._triggerFly = false;
}
_private.bindFocusEvent = () => {
that.app.on('FocusIn', function (ev) {
_private._focus = true;
}, 'onFocusIn');
that.app.on('FocusOut', function (ev) {
_private._focus = false;
if (!!_private._clearInteractWhenFocusOut) {
_private.clearInteractEffect();
}
}, 'onFocusOut');
}
_private.unbindFocusEvent = () => {
that.app.off('FocusIn', 'onFocusIn');
that.app.off('FocusOut', 'onFocusOut');
}
_private.bindKeyEvent = () => {
that.object.on('KeyDown', function (ev) {
if (!_private._focus) {
return;
}
if (ev.code === _private._hotKeyMap.ForwardKey) {
_private._triggerMoveForward = true;
}
else if (ev.code === _private._hotKeyMap.BackwardKey) {
_private._triggerMoveBack = true;
}
else if (ev.code === _private._hotKeyMap.UpwardKey) {
_private._triggerMoveUp = true;
}
else if (ev.code === _private._hotKeyMap.DownwardKey) {
_private._triggerMoveDown = true;
}
else if (ev.code === _private._hotKeyMap.LeftwardKey) {
_private._triggerMoveLeft = true;
}
else if (ev.code === _private._hotKeyMap.RightwardKey) {
_private._triggerMoveRight = true;
}
else if (ev.code === _private._hotKeyMap.TurnLeftKey) {
_private._triggerTurnLeft = true;
}
else if (ev.code === _private._hotKeyMap.TurnRightKey) {
_private._triggerTurnRight = true;
}
else if (ev.code === _private._hotKeyMap.FlyKey) {
if (_private.checkCollison(that.object.position)) {
Utils.log('this place is invalid');
return;
}
if(THING.EARTH){
Utils.log('can not fly on earth');
return;
}
_private._triggerFly = true;
}
else if (ev.code === _private._hotKeyMap.JumpKey) {
if (_private._playerState !== InteractType.Jump) {
_private._curJumpSpeed = _private._interactInfo[InteractType.Jump].speed;
_private._triggerJump = true;
}
}
// the function key has left and right code;for example leftshift and rightshift
// we do not care left and right,so we choose charge the keycodetype
if (ev.keyCode === KeyCodeType.Shift) {
_private._shiftDown = true;
}
else if (ev.keyCode === KeyCodeType.Ctrl) {
_private._ctrlDown = true;
}
else if (ev.keyCode === KeyCodeType.Alt) {
_private._altDown = true;
}
}, 'onKeyDown');
that.object.on('KeyUp', function (ev) {
if (!_private._focus) {
return;
}
if (ev.code === _private._hotKeyMap.ForwardKey) {
_private._triggerMoveForward = false;
}
else if (ev.code === _private._hotKeyMap.BackwardKey) {
_private._triggerMoveBack = false;
}
else if (ev.code === _private._hotKeyMap.UpwardKey) {
_private._triggerMoveUp = false;
}
else if (ev.code === _private._hotKeyMap.DownwardKey) {
_private._triggerMoveDown = false;
}
else if (ev.code === _private._hotKeyMap.LeftwardKey) {
_private._triggerMoveLeft = false;
}
else if (ev.code === _private._hotKeyMap.RightwardKey) {
_private._triggerMoveRight = false;
}
else if (ev.code === _private._hotKeyMap.TurnLeftKey) {
_private._triggerTurnLeft = false;
}
else if (ev.code === _private._hotKeyMap.TurnRightKey) {
_private._triggerTurnRight = false;
}
else if (ev.code === _private._hotKeyMap.FlyKey) {
_private._triggerFly = false;
}
else if (ev.code === _private._hotKeyMap.JumpKey) {
_private._triggerJump = false;
}
// the function key has left and right code;for example leftshift and rightshift
// we do not care left and right,so we choose charge the keycodetype
if (ev.keyCode === KeyCodeType.Shift) {
_private._shiftDown = false;
}
else if (ev.keyCode === KeyCodeType.Ctrl) {
_private._ctrlDown = false;
}
else if (ev.keyCode === KeyCodeType.Alt) {
_private._altDown = false;
}
}, 'onKeyUp');
}
_private.unbindKeyEvent = () => {
that.object.off('KeyDown', 'onKeyDown');
that.object.off('KeyUp', 'onKeyUp');
}
_private.bindMouseEvent = () => {
that.app.on('mousedown', function (ev) {
if (!_private._focus) {
return;
}
if (_private.pointerLockState == "Unlock") {
if (!_private._mouseDownEnable) {
return;
}
var container = that.object.app.view.getContainer();
_private._documentDelegate.requestPointerLock(container);
}
}, 'FlyControlMouseDown');
that.app.on('click', function (ev) {
_private.triggerMouseEvent(EventType.Click, ev);
}, 'FlyControlClick');
that.app.on('DBLClick', function (ev) {
_private.triggerMouseEvent(EventType.DBLClick, ev);
}, 'FlyControlDBLClick');
}
_private.unbindMouseEvent = () => {
that.app.off('mousedown', 'FlyControlMouseDown');
that.app.off('click', 'FlyControlClick');
that.app.off('DBLClick', 'FlyControlDBLClick');
}
_private.triggerMouseEvent = (event_type, ev) => {
if (!_private._focus) {
return;
}
if (_private.pointerLockState == "Locked") {
if (!_private.pickedObject || _private.pickedObject == ev.object) {
return;
}
let custom_ev = _private.buildMouseEvent(ev);
_private.pickedObject.trigger(event_type, custom_ev);
}
}
_private.buildMouseEvent = (ev) => {
return {
"type": ev.type,
"object": _private.pickedObject,
"x": _private._center[0],
"y": _private._center[1],
"clientX": _private._center[0],
"clientY": _private._center[1],
"button": ev.button || 0,
"buttons": ev.buttons || 0,
"altKey": ev.altKey,
"ctrlKey": ev.ctrlKey,
"shiftKey": ev.shiftKey,
"stopPropagation": function stopPropagation() {
ev.stopPropagation();
}
};
}
_private.bindPointerLock = () => {
_private._documentDelegate.addEventListener('pointerlockchange', _private._onPointerLockChange);
}
_private.unbindPointerLock = () => {
_private._documentDelegate.removeEventListener('pointerlockchange', _private._onPointerLockChange);
}
_private._onPointerLockChange = (event) => {
if (_private.pointerLockState == "Unlock") {
_private._documentDelegate.addEventListener("mousemove", _private._onMouseMove);
_private.pointerLockState = "Locked";
that.app.picker.stateGroup.enable(false, cPickerGroupName, cPickerPriority);
}
else {
_private._documentDelegate.removeEventListener("mousemove", _private._onMouseMove);
that.app.picker.stateGroup.enable(true, cPickerGroupName, -cPickerPriority);
// becasue exit lock is a procedure, and we can not know when it completed
// even pointlockchange be called, the exit procedure may not complete
// so we give a time out
setTimeout(() => {
_private.pointerLockState = "Unlock";
}, 2000);
}
};
_private._onMouseMove = (event) => {
if (_private._mouseMoveEnable) {
_protected._mouseMoveX = event.movementX / 360;
_protected._mouseMoveY = event.movementY / 360;
_protected.resetYaw();
_protected.resetPitch();
}
};
_private.updateFocusUI = () => {
if (_private.focusUI && _private.focusUI.style.display == 'block') {
// place the div to the center pos
let container = that.app.view.getContainer();
_private._center = _private._documentDelegate.placeToCenter(_private.focusUI, container);
// get the object picked by the center point
let result = _protected._attachCamera.pick(_private._center[0], _private._center[1]);
let obj = !!result ? result.object : null;
let ev = {
// target: null,
class: 'mouse',
x: _private._center[0],
y: _private._center[1],
altKey: _private._altDown,
ctrlKey: _private._ctrlDown,
shiftKey: _private._shiftDown
};
// if the picked object changed,then trigger event
if (_private.pickedObject != obj) {
if (_private.pickedObject) {
ev.type = 'mouseleave';
ev.object = _private.pickedObject;
_private.pickedObject.trigger(EventType.MouseLeave, ev);
}
if (obj) {
ev.type = 'mouseenter';
ev.object = obj;
obj.trigger(EventType.MouseEnter, ev);
}
_private.pickedObject = obj;
}
}
}
_private.playerInSpecialState = () => {
if (_private._playerState == InteractType.FlyUp ||
_private._playerState == InteractType.Fly ||
_private._playerState == InteractType.FlyDown ||
_private._playerState == InteractType.Jump) {
return true;
}
return false;
}
// bad code
_private.updatePlayerState = () => {
if (_private._playerState == InteractType.Fly && _private._triggerFly) {
_private._playerState = InteractType.FlyDown;
}
if (_private.playerInSpecialState()) {
return;
}
if (_private._triggerFly) {
_private._playerState = InteractType.FlyUp;
return;
}
if (_private._triggerJump) {
_private._playerState = InteractType.Jump;
_private.JumpHeight = 0;
_private._oriPlayerPos = that.object.position;
return;
}
if (_private._triggerMoveLeft) {
_private._playerState = InteractType.MoveLeft;
return;
}
if (_private._triggerMoveRight) {
_private._playerState = InteractType.MoveRight;
return;
}
if (_private._triggerMoveUp) {
_private._playerState = InteractType.MoveUp;
return;
}
if (_private._triggerMoveDown) {
_private._playerState = InteractType.MoveDown;
return;
}
if (_private._triggerMoveForward || _private._triggerMoveBack) {
if (_private._shiftDown) {
_private._playerState = InteractType.Run;
}
else {
_private._playerState = InteractType.Walk;
}
return;
}
_private._playerState = InteractType.Idle;
}
_private.checkAnimationValid = function (actionName) {
if (!that.object.animations || that.object.animations.length == 0) {
return false;
}
if (actionName && !that.object.getAnimation(actionName)) {
return false;
}
return true;
}
_private.updatePlayerAnimation = () => {
let actionName = _private._interactInfo[_private._playerState].actionName;
let actionSpeed = _private._interactInfo[_private._playerState].actionSpeed;
if (_private.checkAnimationValid(actionName) && !that.object.isAnimationPlaying(actionName)) {
that.object.playAnimation({ name: actionName, loopType: "Repeat", speed: actionSpeed });
}
}
_private.updatePlayerFly = (deltaTime) => {
let speed = _private._interactInfo[_private._playerState].speed;
if (_private._playerState == InteractType.FlyUp) {
let height = that.object.position[1];
height = height + speed * deltaTime;
let middle = (_private.MinFlyHeight + _private.MaxFlyHeight) / 2;
if (height > middle) {
height = middle;
_private._playerState = InteractType.Fly;
}
that.object.position = [that.object.position[0], height, that.object.position[2]];
}
else if (_private._playerState == InteractType.FlyDown) {
var height = that.object.position[1];
height = height - speed * deltaTime;
if (height < _private.ZeroHeight) {
height = _private.ZeroHeight;
_private._playerState = InteractType.Idle;
}
that.object.position = [that.object.position[0], height, that.object.position[2]];
}
}
_private.updatePlayerJump = (deltaTime) => {
if (_private._playerState !== InteractType.Jump) {
return;
}
_private._curJumpSpeed = _private._curJumpSpeed - deltaTime * _private._gravity;
_private.JumpHeight = _private.JumpHeight + _private._curJumpSpeed * deltaTime;
if (_private.JumpHeight < 0) {
_private.JumpHeight = 0;
_private._curJumpSpeed = 0;
_private._playerState = InteractType.Idle;
}
let up = MathUtils.normalizeVector(that.object.up);
let delta = MathUtils.scaleVector(up, _private.JumpHeight);
that.object.position = MathUtils.addVector(_private._oriPlayerPos, delta);
}
_private.updatePlayerTurn = (deltaTime) => {
if (!!_private._triggerTurnLeft || !!_private._triggerTurnRight) {
var radianX = 0;
if (!!_private._triggerTurnLeft) {
radianX = radianX + deltaTime * _protected._yawSpeed;
}
if (!!_private._triggerTurnRight) {
radianX = radianX - deltaTime * _protected._yawSpeed;
}
_protected._yaw = _protected._yaw + radianX;
_protected._dirty = true;
}
}
_private.updatePlayerDirect = (deltaTime) => {
if (!!_protected._dirty) {
var theta = (_protected._yaw + _private._playerTurning) / 2;
var quat = [0, Math.sin(theta), 0, Math.cos(theta)];
var localQuat = [0, 0, 0, 0];
MathUtils.quat.multiply(localQuat, _private._objectOriLocalQuat, quat);
that.object.localQuaternion = localQuat;
}
}
_private.updatePlayerMove = (deltaTime) => {
if (_private._playerState === InteractType.Idle ||
_private._playerState === InteractType.FlyUp ||
_private._playerState === InteractType.FlyDown) {
return;
}
var speed = _private._shiftDown ? _private._interactInfo[InteractType.Run].speed : _private._interactInfo[InteractType.Walk].speed;
speed = _private._playerState == InteractType.Fly ? _private._interactInfo[InteractType.Fly].speed : speed;
var distance = deltaTime * speed;
var forward = _private._playerState === InteractType.Fly ? _protected._attachCamera.forward : that.object.forward;
MathUtils.normalizeVector(forward);
if (_private._triggerMoveForward === true) {
var offset = MathUtils.scaleVector(forward, distance);
_private.move(offset);
}
if (_private._triggerMoveBack === true) {
var offset = MathUtils.scaleVector(forward, distance);
offset = MathUtils.negVector(offset);
_private.move(offset);
}
var yaxis = [0, 1, 0];
if (_private._useLocalUp) {
yaxis = that.object.up;
}
MathUtils.normalizeVector(yaxis);
if(_private._triggerMoveUp === true){
var offset = MathUtils.scaleVector(yaxis, distance);
_private.move(offset);
}
if (_private._triggerMoveDown === true) {
var offset = MathUtils.scaleVector(yaxis, distance);
offset = MathUtils.negVector(offset);
_private.move(offset);
}
var right = MathUtils.crossVector(forward, yaxis);
MathUtils.normalizeVector(right);
if (_private._triggerMoveLeft === true) {
var offset = MathUtils.scaleVector(right, distance);
offset = MathUtils.negVector(offset);
_private.move(offset);
}
if (_private._triggerMoveRight === true) {
var offset = MathUtils.scaleVector(right, distance);
_private.move(offset);
}
}
_private.updateCameraDirect = (deltaTime) => {
if (!!_protected._dirty) {
// plus PI,means camera face to the z direct of the player by default
var theta = Math.PI / 2;
var quatY = [0, Math.sin(theta), 0, Math.cos(theta)];
theta = _protected._pitch / 2;
var quatX = [Math.sin(theta), 0, 0, Math.cos(theta)];
var quat = [0, 0, 0, 0];
MathUtils.quat.multiply(quat, quatY, quatX);
MathUtils.quat.multiply(quat, that.object.quaternion, quat);
_protected._attachCamera.quaternion = quat;
}
}
_private.updateCameraPos = (deltaTime) => {
var pos = that.object.position;
if(_private._useLocalUp){
let delta = THING.MathUtils.scaleVector(that.object.up, _private._eyeHeight);
pos = MathUtils.addVector(pos, delta);
}
else{
pos = [pos[0], pos[1] + _private._eyeHeight, pos[2]];
}
if (!!_private._isFirstPersonView) {
_protected._attachCamera.position = pos;
}
else {
var dis_vec = MathUtils.scaleVector(that.object.forward, _private._thirdPersonCameraDis);
var camera_pos = MathUtils.subVector(pos, dis_vec);
var temp_vec = [0, 0, 0];
// Bad Code
while (_private.checkCollison(camera_pos) && _private._playerState != InteractType.Fly) {
var delta_vec = MathUtils.scaleVector(_protected._attachCamera.forward, deltaTime * _protected._yawSpeed);
camera_pos = MathUtils.addVector(camera_pos, delta_vec);
temp_vec = MathUtils.addVector(temp_vec, delta_vec);
if (MathUtils.getVectorLength(temp_vec) > MathUtils.getVectorLength(dis_vec)) {
// Utils.log("the camera is step beyond the player,then the camera's pos will seted by player's pos");
camera_pos = pos;
break;
}
}
_protected._attachCamera.position = camera_pos;
}
}
}
/**
* @class FlyControlComponent
* @summary 第一人称/第三人称飞行控制器组件,为场景中的角色对象提供 W/A/S/D/Q/E/R/T 键+鼠标的完整控制能力。
* 支持第一人称和第三人称视角切换,包含行走、奔跑、跳跃、飞行四种运动模式,
* 通过 Pointer Lock API 实现鼠标视角控制,支持碰撞检测、重力模拟和自定义热键映射。
* 还提供打击点检测(focusUI)、动画状态自动切换和地板碰撞检测功能。
* 适用于游戏角色控制、虚拟漫游、建筑内部浏览等场景。
* @memberof THING
* @extends THING.CameraAttachedComponent
* @public
* @example
* // 为玩家角色添加飞行控制器
let component = new THING.FlyControlComponent();
person.addComponent(component, 'objControl');
person.objControl.setFloorObject(floorObj); //floorObj是一个Object3D,第一人称行走的平面
person.objControl.setEyeHeight(1.8);
person.objControl.setAttachCamera(app.camera);
person.objControl.setFirstPersonView(true);
person.objControl.setPlayerTurning(0);
person.objControl.setMouseOppositeMode(true);
person.objControl.setPointerLockEnable(false);
person.objControl.enableChangeDirecetionByMouseMove(false);
// 切换到第三人称
person.objControl.setFirstPersonView(false);
person.objControl.setThirdPersonCameraDis(3.0);
*/
class FlyControlComponent extends CameraAttachedComponent {
// region ---------------deprecated------------------
/**
* set the idle action name
* @param {string} name the idle action name
* @deprecated will be removed in comming version
*/
setIdleActionName(name) {
this.setInteractActionName(InteractType.Idle, name);
Utils.warn("this function is deprecated,please use setInteractSpeed instead");
Utils.warn("this function is deprecated,please use setJumpActionName instead");
}
/**
* set the walk action name
* @param {string} name the walk action name
* @deprecated will be removed in comming version
*/
setWalkActionName(name) {
this.setInteractActionName(InteractType.Walk, name);
Utils.warn("this function is deprecated,please use setJumpActionName instead");
}
/**
* set the move left action name
* @param {string} name the move left action name
* @deprecated will be removed in comming version
*/
setMoveLeftActionName(name) {
this.setInteractActionName(InteractType.MoveLeft, name);
Utils.warn("this function is deprecated,please use setJumpActionName instead");
}
/**
* set the move right action name
* @param {string} name the move right action name
* @deprecated will be removed in comming version
*/
setMoveRightActionName(name) {
this.setInteractActionName(InteractType.MoveRight, name);
Utils.warn("this function is deprecated,please use setJumpActionName instead");
}
/**
* set the jump action name
* @param {string} name the jump action name
* @deprecated will be removed in comming version
*/
setJumpActionName(name) {
this.setInteractActionName(InteractType.Jump, name);
Utils.warn("this function is deprecated,please use setJumpActionName instead");
}
/**
* set the idle action speed
* @param {number} speed the idle action speed
* @deprecated will be removed in comming version
*/
setIdleActionSpeed(speed) {
this.setInteractActionSpeed(InteractType.Idle, speed);
Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
}
/**
* set the walk action speed
* @param {number} speed the walk action speed
* @deprecated will be removed in comming version
*/
setWalkActionSpeed(speed) {
this.setInteractActionSpeed(InteractType.Walk, speed);
Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
}
/**
* set the move left action speed
* @param {number} speed the move left action speed
* @deprecated will be removed in comming version
*/
setMoveLeftActionSpeed(speed) {
this.setInteractActionSpeed(InteractType.MoveLeft, speed);
Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
}
/**
* set the move right action speed
* @param {number} speed the move right action speed
* @deprecated will be removed in comming version
*/
setMoveRightActionSpeed(speed) {
this.setInteractActionSpeed(InteractType.MoveRight, speed);
Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
}
/**
* set the jump action speed
* @param {number} speed the jump action speed
* @deprecated will be removed in comming version
*/
setJumpActionSpeed(speed) {
this.setInteractActionSpeed(InteractType.Jump, speed);
Utils.warn("this function is deprecated,please use setInteractActionSpeed instead");
}
/**
* set the jump speed
* @param {number} speed the jump speed
* @deprecated will be removed in comming version
*/
setJumpSpeed(speed) {
this.setInteractSpeed(InteractType.Jump, speed);
Utils.warn("this function is deprecated,please use setInteractSpeed instead");
}
/**
* set the move speed
* @param {number} speed the camera move speed
* @deprecated will be removed in comming version
*/
setMoveSpeed(speed) {
this.setInteractSpeed(InteractType.Walk, speed);
Utils.warn("this function is deprecated,please use setInteractSpeed instead");
}
// ---------------------------
/**
* 第一人称/第三人称飞行控制器组件构造函数
* @public
* @constructor
*/
constructor(param = {}) {
super(param);
_initPrivateMembers(this);
}
/**
* 设置热键
* @param {THING.FlyControlKeyType} type 键类型;表示该键的用途
* @param {THING.CodeType} code 键码;表示键盘上的实际按键
* @public
*/
setHotKey(type, code) {
var _private = this[__.private];
_private._hotKeyMap[type] = code;
}
/**
* 获取热键
* @param {THING.FlyControlKeyType} type 键类型;表示该键的用途
* @returns {THING.CodeType} 键码;表示键盘上的实际按键
* @public
*/
getHotKey(type) {
var _private = this[__.private];
return _private._hotKeyMap[type];
}
/**
* 设置是否可以通过鼠标按下锁定指针,仅在指针锁定模式下有效
* @param {boolean} enable 设置是否可以通过鼠标按下锁定指针
* @public
*/
enableLockPointerByMouseDown(enable) {
var _private = this[__.private];
_private._mouseDownEnable = enable;
}
/**
* 设置是否可以通过鼠标移动改变方向
* @param {boolean} enable 设置是否可以通过鼠标移动改变方向
* @public
*/
enableChangeDirecetionByMouseMove(enable) {
var _private = this[__.private];
_private._mouseMoveEnable = enable;
}
/**
* 设置指针锁定模式是否启用
* @param {boolean} enable 是否启用指针锁定模式
* @public
*/
setPointerLockEnable(enable) {
var _private = this[__.private];
if (_private.pointerLockEnable == enable) {
return;
}
_private.pointerLockEnable = enable;
if (enable) {
_private.pointerLockState = "Unlock";
_private.bindMouseEvent();
_private.bindPointerLock();
if (_private.focusUI) {
_private.focusUI.style.display = 'block';
}
_private._documentDelegate.removeEventListener("mousemove", _private._onMouseMove);
this.app.picker.stateGroup.enable(true, cPickerGroupName, cPickerPriority);
}
else {
if (_private.pointerLockState == 'Locked') {
_private._documentDelegate.exitPointerLock();
}
_private.unbindMouseEvent();
_private.unbindPointerLock();
if (_private.focusUI) {
_private.focusUI.style.display = 'none';
}
_private._documentDelegate.addEventListener("mousemove", _private._onMouseMove);
this.app.picker.stateGroup.enable(true, cPickerGroupName, -cPickerPriority);
}
}
/**
* 获取当前被拾取的对象
* @returns {object} 返回被focusUI拾取的对象
* @public
*/
getPickedObject() {
var _private = this[__.private];
return _private.pickedObject;
}
/**
* 设置交互动作名称
* @param {string} type 交互类型,可能是InteractType中的一个元素
* @param {string} actionName 交互动作名称
* @public
*/
setInteractActionName(type, actionName) {
var _private = this[__.private];
if (!_private.checkAnimationValid(actionName)) {
Utils.error("the object do not has the animation:", actionName);
return;
}
if (_private._interactInfo[type]) {
_private._interactInfo[type].actionName = actionName;
}
else {
Utils.error('can not get the interaction,the type param maybe invalid!!!');
}
}
/**
* 设置交互动作速度
* @param {string} type 交互类型,可能是InteractType中的一个元素
* @param {number} actionSpeed 交互动作动画速度
* @public
*/
setInteractActionSpeed(type, actionSpeed) {
var _private = this[__.private];
if (_private._interactInfo[type]) {
_private._interactInfo[type].actionSpeed = actionSpeed;
let actionName = _private._interactInfo[type].actionName;
if (!_private.checkAnimationValid(actionName)) {
Utils.error("the object do not has the animation:", actionName);
return;
}
if (this.object.isAnimationPlaying(actionName)) {
this.object.setAnimationSpeed(actionName, actionSpeed);
}
}
else {
Utils.error('can not get the interaction,the type param maybe invalid!!!');
}
}
/**
* 设置交互速度
* @param {string} type 交互类型,可能是InteractType中的一个元素
* 但只有walk\run\jump\fly\flyup\flydown有意义
* @param {number} speed 交互速度,如行走速度
* @public
*/
setInteractSpeed(type, speed) {
var _private = this[__.private];
if (_private._interactInfo[type]) {
_private._interactInfo[type].speed = speed;
}
else {
Utils.error('can not get the interaction,the type param maybe invalid!!!');
}
}
/**
* 设置焦点UI
* @param {HTMLElement} focus_ui 焦点UI的div元素
* @public
*/
setFocusUI(focus_ui) {
var _private = this[__.private];
_private.focusUI = focus_ui;
}
/**
* 设置当失去3D窗口焦点时是否清除交互效果
* 目前效果包括移动和转向,但不包括重力
* @param {boolean} clear true表示当失去3D窗口焦点时清除交互效果
* @public
*/
setClearInteractWhenFocusOut(clear) {
var _private = this[__.private];
_private._clearInteractWhenFocusOut = clear;
}
/**
* 设置玩家转向
* @param {number} turning 玩家Y轴转向角度
* @public
*/
setPlayerTurning(turning) {
var _private = this[__.private];
var _protected = this[this._protected];
turning = turning * Math.PI / 180;
_private._playerTurning = turning;
_protected._dirty = true;
}
/**
* 设置对象和相机之间的距离
* @param {number} dis 第三人称视角下对象和相机之间的距离
* @public
*/
setThirdPersonCameraDis(dis) {
var _private = this[__.private];
_private._thirdPersonCameraDis = dis;
}
/**
* 设置视角,true表示第一人称视角,false表示第三人称视角
* @param {boolean} firstPersonView 是否为第一人称视角
*/
setFirstPersonView(firstPersonView) {
var _private = this[__.private];
_private._isFirstPersonView = firstPersonView;
this.object.visible = !_private._isFirstPersonView;
}
/**
* 设置附加相机
* @param {Thing.Camera} attachCamera 附加的相机
* @param {number} cameraNear 附加相机的近平面距离
* @public
*/
setAttachCamera(attachCamera, cameraNear = 0.1) {
super.setAttachCamera(attachCamera);
var _private = this[__.private];
var _protected = this[this._protected];
_private._oriCameraAjustNear = _protected._attachCamera.enableAdjustNear;
_private._oriCameraAjustTargetPosition = _protected._attachCamera.enableAdjustTargetPosition;
_protected._attachCamera.enableAdjustNear = false;
_protected._attachCamera.enableAdjustTargetPosition = false;
_protected._attachCamera.near = cameraNear;
// flycontrol camera's yaw follow object,should be 0
_protected._yaw = 0;
_protected._pitch = 0;
}
/**
* 设置地板对象
* @param {object} floorobj 我们必须站立的地板
* @public
*/
setFloorObject(floorobj) {
var _private = this[__.private];
if(!floorobj){
Utils.error("the param floorobj can not be null or undefined");
return;
}
if(Array.isArray(floorobj)){
_private._floorobj = floorobj
}
else if(floorobj.isSelector){
_private._floorobj = floorobj.objects
}
else if(floorobj.isObject3D){
_private._floorobj = [floorobj];
}
else {
Utils.error("the param floorobj is an invalid type,it only can be Selector、Array or Object3D");
return;
}
if (_private.checkCollison(this.object.position)) {
Utils.error("the player is in an error point,then he can not move");
}
}
/**
* 设置最小俯仰角
* @param {number} pitch 最小俯仰角值
* @public
*/
setMinPitch(pitch) {
if (pitch >= 0 || pitch <= -90) {
return;
}
var _protected = this[this._protected];
_protected._minPitch = pitch * Math.PI / 180;
}
/**
* 设置最大俯仰角
* @param {number} pitch 最大俯仰角值
* @public
*/
setMaxPitch(pitch) {
if (pitch <= 0 || pitch >= 90) {
return;
}
var _protected = this[this._protected];
_protected._maxPitch = pitch * Math.PI / 180;
}
/**
* 设置相机高度
* @param {number} height 相机高于地板的高度
* @public
*/
setEyeHeight(height) {
var _private = this[__.private];
_private._eyeHeight = height;
}
/**
* 设置是否使用对象的up向量
* @param {boolean} use 是否使用对象的up向量
* @public
*/
setUseLocalUp(use) {
var _private = this[__.private];
_private._useLocalUp = use;
}
onAdd(object) {
super.onAdd(object);
var _private = this[__.private];
_private.oriObjectVisible = this.object.visible;
this.object.visible = !_private._isFirstPersonView;
this.app.picker.stateGroup.enable(false, cPickerGroupName, cPickerPriority);
_private._objectOriLocalQuat = this.object.localQuaternion;
_private.bindFocusEvent();
_private.bindKeyEvent();
_private.bindMouseEvent();
_private.bindPointerLock();
this.app.focus();
}
onRemove() {
var _private = this[__.private];
var _protected = this[this._protected];
this.setPointerLockEnable(false)
_private.unbindFocusEvent();
_private.unbindKeyEvent();
_private.unbindMouseEvent();
_private.unbindPointerLock();
if (!!_protected._attachCamera) {
_protected._attachCamera.enable = _protected._oriCameraEnable;
_protected._attachCamera.enableAdjustNear = _private._oriCameraAjustNear;
_protected._attachCamera.enableAdjustTargetPosition = _private._oriCameraAjustTargetPosition;
}
if (this.app && this.app.picker) {
this.app.picker.stateGroup.enable(true, cPickerGroupName, -cPickerPriority);
}
this.object.visible = _private.oriObjectVisible;
super.onRemove();
}
onUpdate(deltaTime) {
var _private = this[__.private];
var _protected = this[this._protected];
if (!_protected._attachCamera) {
return;
}
_private.updatePlayerState();
_private.updatePlayerAnimation();
_private.updatePlayerFly(deltaTime);
_private.updatePlayerJump(deltaTime);
_private.updatePlayerTurn(deltaTime);
_private.updatePlayerDirect(deltaTime);
_private.updatePlayerMove(deltaTime);
_private.updateCameraDirect(deltaTime);
_private.updateCameraPos(deltaTime);
_private.updateFocusUI();
super.onUpdate(deltaTime);
}
onResize(width, height) {
}
onRefresh() {
}
onVisibleChange(value) {
}
onActiveChange(value) {
}
}
export { FlyControlComponent }