@soonspacejs/plugin-first-person-controls 2.13.17 → 2.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -4
- package/dist/index.esm.js +463 -1
- package/dist/tools.d.ts +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Vector3, Vector2, Intersection, Sphere, Object3D, Box3, Camera } from 'three';
|
|
2
|
-
import SoonSpace,
|
|
2
|
+
import { default as SoonSpace, Position, Rotation } from 'soonspacejs';
|
|
3
3
|
export type ClashCheckAxis = 'front' | 'back' | 'left' | 'right' | 'up' | 'down';
|
|
4
4
|
/**
|
|
5
5
|
* 碰撞对象过滤器
|
|
@@ -193,7 +193,7 @@ export default class FirstPersonControlsPlugin {
|
|
|
193
193
|
*/
|
|
194
194
|
searchRadiusFactor: number;
|
|
195
195
|
checkedSphere: Sphere;
|
|
196
|
-
getCheckedObjects(origin: Vector3): Object3D<import(
|
|
196
|
+
getCheckedObjects(origin: Vector3): Object3D<import('three').Object3DEventMap>[];
|
|
197
197
|
/**
|
|
198
198
|
* 重力搜索系数
|
|
199
199
|
* @remarks
|
|
@@ -202,8 +202,8 @@ export default class FirstPersonControlsPlugin {
|
|
|
202
202
|
gravitySearchFactor: number;
|
|
203
203
|
gravityCheckedObjects: Object3D[] | null;
|
|
204
204
|
gravityCheckedBox: Box3;
|
|
205
|
-
getGravityCheckedObjects(origin: Vector3, dropY: number): Object3D<import(
|
|
206
|
-
gravityClashCheck(origin: Vector3, dropY: number): Intersection<Object3D<import(
|
|
205
|
+
getGravityCheckedObjects(origin: Vector3, dropY: number): Object3D<import('three').Object3DEventMap>[];
|
|
206
|
+
gravityClashCheck(origin: Vector3, dropY: number): Intersection<Object3D<import('three').Object3DEventMap>>;
|
|
207
207
|
setOptions(options: StartOptions): void;
|
|
208
208
|
start(options: StartOptions): void;
|
|
209
209
|
stop(): void;
|
package/dist/index.esm.js
CHANGED
|
@@ -1 +1,463 @@
|
|
|
1
|
-
import{Vector2 as t,Vector3 as e,Sphere as s,Box3 as i,Raycaster as o,Matrix4 as n,Euler as a,Quaternion as r}from"three";import h from"soonspacejs";const{utils:{isObjectVisible:c}}=h;function l(t,e){const s=h.utils.getBoundingBox(e);return t.intersectsBox(s)}function d(t,e){t.disableAll();for(const s of e)t.enable(s)}function p(t,e){return t.intersectObjects(e).filter(({object:t})=>c(t))}const{EPSILON:v,approxEquals:m}=h.utils,{utils:y}=h;class u{get rotate(){return this._rotate&&(this.horizontalRotate||this.verticalRotate)}set rotate(t){this._rotate=t}constructor(o){this.enabled=!1,this.keyCodeMap={moveForward:["ArrowUp","KeyW"],moveBackward:["ArrowDown","KeyS"],moveLeft:["ArrowLeft","KeyA"],moveRight:["ArrowRight","KeyD"],moveUp:["KeyQ"],moveDown:["KeyE"],rotateUp:["KeyI"],rotateDown:["KeyK"],rotateLeft:["KeyJ"],rotateRight:["KeyL"],jump:["Space"]},this.state={moveForward:!1,moveBackward:!1,moveLeft:!1,moveRight:!1,moveUp:!1,moveDown:!1,canJump:!1,canRotate:!1},this.moveSpeed=10,this.gravitySpeed=10,this.jumpOffset=0,this.clashCheckDistance=200,this.clashDistance=50,this.eyeHeight=160,this.kneeHeight=50,this.jumpHeight=110,this.enableClash=!0,this.enableGravity=!0,this.reverseRotate=!1,this._rotate=!0,this.rotateSpeed=1,this.horizontalRotate=!0,this.verticalRotate=!0,this.dblClickForward=!1,this.movement=new t,this._dblVector=new e,this._dblDeltaVector=new e,this._pointerId=null,this.lastDirection=new e,this.searchRadiusFactor=3,this.checkedSphere=new s,this.gravitySearchFactor=3,this.gravityCheckedObjects=null,this.gravityCheckedBox=new i,this.gravityInterObject=null,this.kneeInterObject=null,this.eyeInterObject=null,this.ssp=o,this.viewport=o.viewport,this.controls=o.controls,this.camera=o.controls.camera,this.container=o.viewport.container,this.onKeyDown=this.onKeyDown.bind(this),this.onKeyUp=this.onKeyUp.bind(this),this.onDblClick=this.onDblClick.bind(this),this.onPointerDown=this.onPointerDown.bind(this),this.onPointerMove=this.onPointerMove.bind(this),this.onPointerUp=this.onPointerUp.bind(this)}onKeyDown(t){if(!1!==this.enabled){t:for(const[e,s]of Object.entries(this.keyCodeMap))if(s.includes(t.code))switch(e){case"moveForward":this.state.moveForward=!0;break t;case"moveBackward":this.state.moveBackward=!0;break t;case"moveLeft":this.state.moveLeft=!0;break t;case"moveRight":this.state.moveRight=!0;break t;case"moveUp":this.state.moveUp=!0;break t;case"moveDown":this.state.moveDown=!0;break t;case"rotateUp":this.state.canRotate=!0,this.movement.x=0,this.movement.y=-10;break t;case"rotateDown":this.state.canRotate=!0,this.movement.x=0,this.movement.y=10;break t;case"rotateLeft":this.state.canRotate=!0,this.movement.x=-10,this.movement.y=0;break t;case"rotateRight":this.state.canRotate=!0,this.movement.x=10,this.movement.y=0;break t;case"jump":!0===this.state.canJump&&!1===t.repeat&&(this.jumpOffset=this.jumpHeight),this.state.canJump=!1;break t}(this.jumpOffset>0||Object.values(this.state).some(t=>t))&&this.ssp.render()}}onKeyUp(t){t:for(const[e,s]of Object.entries(this.keyCodeMap))if(s.includes(t.code))switch(e){case"moveForward":this.state.moveForward=!1;break t;case"moveBackward":this.state.moveBackward=!1;break t;case"moveLeft":this.state.moveLeft=!1;break t;case"moveRight":this.state.moveRight=!1;break t;case"moveUp":this.state.moveUp=!1;break t;case"moveDown":this.state.moveDown=!1;break t;case"rotateUp":case"rotateDown":case"rotateLeft":case"rotateRight":this.state.canRotate=!1;break t}}onDblClick(t){if(!0===this.dblClickForward){const[e]=this.ssp.viewport.getIntersects(t);if(e){const{point:t}=e;t.y+=this.eyeHeight,t.sub(this.camera.position),this._dblVector.copy(t),this._dblDeltaVector.set(0,0,0),this.ssp.render()}}}onPointerDown(t){null===this._pointerId&&0===t.button&&(this.container.setPointerCapture(t.pointerId),this._pointerId=t.pointerId,this.state.canRotate=!0)}onPointerMove(t){if(t.preventDefault(),this.enabled&&this.state.canRotate){let e=t.movementY,s=t.movementX;this.reverseRotate&&(s=-s,e=-e),this.movement.x=s,this.movement.y=e,this.ssp.render()}}onPointerUp(t){null!==this._pointerId&&(this.container.releasePointerCapture(t.pointerId),this._pointerId=null,this.state.canRotate=!1)}clearClashCache(){this.kneeInterObject=null,this.eyeInterObject=null}onClashCheck(t,e){const s=e.length(),i=e.clone().divideScalar(s);i.distanceToSquared(this.lastDirection)>1e-9&&this.clearClashCache(),this.lastDirection=i;const{eyeHeight:n,kneeHeight:a,camera:r,clashCheckDistance:h,clashDistance:c,clashLayers:l}=this;let{kneeInterObject:v,eyeInterObject:m}=this;if(!v){const e=t.clone().setY(t.y-n+a),s=new o(e,i,0,h);s.firstHitOnly=!0,null!=l&&d(s.layers,l),s.camera=r;const c=p(s,this.getCheckedObjects(e));this.kneeInterObject=v=c[0]}let y=-s;if(v&&(y+=v.distance,y<c))return!0;if(!m){const e=new o(t,i,0,h);e.firstHitOnly=!0,null!=l&&d(e.layers,l),e.camera=r;const s=p(e,this.getCheckedObjects(t));this.eyeInterObject=m=s[0]}let u=-s;if(m){if(u+=m.distance,u<c)return!0;m.distance=u}return v&&(v.distance=y),!1}getCheckedObjects(t){const{clashDistance:e,clashCheckDistance:s,searchRadiusFactor:i,clashFilter:o}=this,n=s*i,a=this.checkedSphere,r=n+e;a.set(t,r);const h=null!=o?o:function(){return!0};return this.viewport.scener.intersectsList.getAll().filter(t=>!!h(t)&&l(a,t))}getGravityCheckedObjects(t,s){const i=this.gravityCheckedBox;let o=this.gravityCheckedObjects;if(o){const e=t.clone();e.y=s,i.containsPoint(t)&&i.containsPoint(e)||(o=null)}if(!o){const{eyeHeight:s,clashCheckDistance:n,gravitySearchFactor:a,clashDistance:r,clashFilter:h}=this,c=n+r,d=new e(c,c,0),p=t.clone().add(d),v=t.clone().sub(d);v.y-=s*a,i.set(v,p);const m=this.viewport.scener.intersectsList.getAll(),y=null!=h?h:function(){return!0};o=m.filter(t=>!!y(t)&&l(i,t))}return o}gravityClashCheck(t,s){var i;let a=this.gravityInterObject;if(a){const{object:s,face:o,instanceId:r}=a,h=null===(i=s.geometry)||void 0===i?void 0:i.getAttribute("position");if(h&&o){let i=a.facePoints;if(!i){let t=s.matrixWorld;if(null!=r){const e=new n;s.getMatrixAt(r,e),t=e.premultiply(t)}const{a:c,b:l,c:d}=o,p=new e(h.getX(c),h.getY(c),h.getZ(c));p.applyMatrix4(t),p.setY(0);const v=new e(h.getX(l),h.getY(l),h.getZ(l));v.applyMatrix4(t),v.setY(0);const m=new e(h.getX(d),h.getY(d),h.getZ(d));m.applyMatrix4(t),m.setY(0),a.facePoints=i=[p,v,m]}let c=i[2],l=null;const d=t.clone();d.y=0;i.every(t=>{const e=t.clone();e.sub(c);const s=d.clone();if(s.sub(c),e.cross(s),l){if(e.dot(l)<=0)return!1}return l=e,c=t,!0})||(this.gravityInterObject=a=null)}}if(!a){const i=new o(t,new e(0,-1,0));i.firstHitOnly=!0;const n=this.clashLayers;null!=n&&d(i.layers,n),i.camera=this.camera;const r=p(i,this.getGravityCheckedObjects(t,s));this.gravityInterObject=a=r[0]}return a}setOptions(t){const{position:s=new e,rotation:i=new a,moveSpeed:o,eyeHeight:n,kneeHeight:r,jumpHeight:h,enableClash:c,enableGravity:l,searchRadiusFactor:d,clashDistance:p,clashCheckDistance:m,gravitySpeed:u,gravitySearchFactor:b,reverseRotate:g,rotate:w,rotateSpeed:f,horizontalRotate:k,verticalRotate:C,dblClickForward:D,clashFilter:j,clashLayers:R}=t;if(n&&(this.eyeHeight=n),r&&(this.kneeHeight=r),h&&(this.jumpHeight=h),d&&(this.searchRadiusFactor=d),p&&(this.clashDistance=p),m&&(this.clashCheckDistance=m),u&&(this.gravitySpeed=u),b&&(this.gravitySearchFactor=b),null!=g&&(this.reverseRotate=g),null!=w&&(this.rotate=w),null!=k&&(this.horizontalRotate=k),null!=C&&(this.verticalRotate=C),y.isBoolean(D)&&(this.dblClickForward=D),y.isNumber(f)&&(this.rotateSpeed=f),null!=c&&(this.enableClash=c),null!=l&&(this.enableGravity=l),null!=j&&(this.clashFilter=j),null!=R&&(this.clashLayers=R),s&&(this.controls.setPosition(s.x,s.y+this.eyeHeight,s.z),this.gravityInterObject=null,this.clearClashCache()),i){const t=y.computeTargetByRotation(this.controls.getPosition(new e),i,v);this.controls.setTarget(t.x,t.y,t.z)}o&&(this.moveSpeed=o)}start(t){this.viewport.controls.saveState(),this.viewport.controls.enabled=!1,this.enabled=!0,this.setOptions(t),this.viewport.postRender.set("FirstPersonControls",this.update.bind(this)),this.ssp.signals.dblClick.add(this.onDblClick),this.ssp.signals.keyDown.add(this.onKeyDown),this.ssp.signals.keyUp.add(this.onKeyUp);const e=this.container;e.addEventListener("pointerdown",this.onPointerDown),e.addEventListener("pointermove",this.onPointerMove),e.addEventListener("pointerup",this.onPointerUp),e.style.touchAction="none",e.style.userSelect="none"}stop(){this.viewport.controls.reset(),this.viewport.controls.enabled=!0,this.enabled=!1,this.viewport.postRender.delete("FirstPersonControls"),this.ssp.signals.dblClick.remove(this.onDblClick),this.ssp.signals.keyDown.remove(this.onKeyDown),this.ssp.signals.keyUp.remove(this.onKeyUp);const t=this.container;t.removeEventListener("pointerdown",this.onPointerDown),t.removeEventListener("pointermove",this.onPointerMove),t.removeEventListener("pointerup",this.onPointerUp),t.style.touchAction="auto",t.style.userSelect="auto",this.ssp.render()}update(){if(!this.enabled)return;const{delta:t}=this.viewport.state,s=new e,{controls:i,state:o,camera:n,eyeHeight:h,kneeHeight:c}=this,l=i.getPosition(new e),d=20*this.moveSpeed,p=20*this.gravitySpeed;o.moveForward&&(s.z-=d),o.moveBackward&&(s.z+=d),o.moveLeft&&(s.x-=d),o.moveRight&&(s.x+=d),o.moveUp&&(s.y+=2*p),o.moveDown&&(s.y-=2*p),s.multiplyScalar(t);const{x:y,y:u}=this.movement,b=this.horizontalRotate&&0!==y,g=this.verticalRotate&&0!==u;if(this.rotate&&o.canRotate&&(b||g)){let{azimuthAngle:t,polarAngle:e}=i;g&&(e-=.003*u*this.rotateSpeed),b&&(t-=.003*y*this.rotateSpeed),i.rotateTo(t,e)}const w=new a(0,0,0,"YXZ");if(w.setFromQuaternion(n.quaternion),0!==w.y&&!s.equals(new e)){const t=new r;t.setFromAxisAngle(new e(0,1,0),w.y),s.applyQuaternion(t)}if(!this._dblVector.equals(new e)){const e=this._dblVector.clone().multiplyScalar(t);this._dblDeltaVector.add(e),this._dblDeltaVector.length()>this._dblVector.length()?(this._dblVector.set(0,0,0),this._dblDeltaVector.set(0,0,0)):s.add(e)}const f=l.clone();if((!this.enableClash||!this.onClashCheck(l,s))&&(f.add(s),this.gravityInterObject)){const t=this.gravityInterObject.point.clone().sub(f);t.y=0,t.length()>c&&(this.gravityInterObject=null)}let k=f.y;if(this.enableGravity){const e=k;this.jumpOffset>0&&(this.jumpOffset-=p*t,k+=2*p*t),k-=p*t,o.canJump=!1;const s=this.gravityClashCheck(f,k);if(s){const t=s.point.y+h;k<t&&(k=t,this.jumpOffset=0,o.canJump=!0)}e!==k&&this.clearClashCache()}f.y=k,m(l.x,f.x)&&m(l.y,f.y)&&m(l.z,f.z)||(i.moveTo(f.x,f.y,f.z),i.dollyTo(v))}}export{u as default};
|
|
1
|
+
import { Vector2 as K, Vector3 as g, Raycaster as O, Sphere as _, Box3 as H, Matrix4 as V, Euler as F, Quaternion as A } from "three";
|
|
2
|
+
import D from "soonspacejs";
|
|
3
|
+
const { utils: { isObjectVisible: B } } = D;
|
|
4
|
+
function L(w, e) {
|
|
5
|
+
const t = D.utils.getBoundingBox(e);
|
|
6
|
+
return w.intersectsBox(t);
|
|
7
|
+
}
|
|
8
|
+
function R(w, e) {
|
|
9
|
+
w.disableAll();
|
|
10
|
+
for (const t of e)
|
|
11
|
+
w.enable(t);
|
|
12
|
+
}
|
|
13
|
+
function I(w, e) {
|
|
14
|
+
return w.intersectObjects(e).filter(({ object: s }) => B(s));
|
|
15
|
+
}
|
|
16
|
+
const { EPSILON: U, approxEquals: P } = D.utils, { utils: S } = D;
|
|
17
|
+
class M {
|
|
18
|
+
ssp;
|
|
19
|
+
viewport;
|
|
20
|
+
controls;
|
|
21
|
+
camera;
|
|
22
|
+
container;
|
|
23
|
+
enabled = !1;
|
|
24
|
+
keyCodeMap = {
|
|
25
|
+
moveForward: ["ArrowUp", "KeyW"],
|
|
26
|
+
moveBackward: ["ArrowDown", "KeyS"],
|
|
27
|
+
moveLeft: ["ArrowLeft", "KeyA"],
|
|
28
|
+
moveRight: ["ArrowRight", "KeyD"],
|
|
29
|
+
moveUp: ["KeyQ"],
|
|
30
|
+
moveDown: ["KeyE"],
|
|
31
|
+
rotateUp: ["KeyI"],
|
|
32
|
+
rotateDown: ["KeyK"],
|
|
33
|
+
rotateLeft: ["KeyJ"],
|
|
34
|
+
rotateRight: ["KeyL"],
|
|
35
|
+
jump: ["Space"]
|
|
36
|
+
};
|
|
37
|
+
state = {
|
|
38
|
+
moveForward: !1,
|
|
39
|
+
moveBackward: !1,
|
|
40
|
+
moveLeft: !1,
|
|
41
|
+
moveRight: !1,
|
|
42
|
+
moveUp: !1,
|
|
43
|
+
moveDown: !1,
|
|
44
|
+
canJump: !1,
|
|
45
|
+
canRotate: !1
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* 移动速度
|
|
49
|
+
*/
|
|
50
|
+
moveSpeed = 10;
|
|
51
|
+
/**
|
|
52
|
+
* 重力速度
|
|
53
|
+
*/
|
|
54
|
+
gravitySpeed = 10;
|
|
55
|
+
jumpOffset = 0;
|
|
56
|
+
/**
|
|
57
|
+
* 碰撞检测距离
|
|
58
|
+
*/
|
|
59
|
+
clashCheckDistance = 200;
|
|
60
|
+
/**
|
|
61
|
+
* 碰撞距离
|
|
62
|
+
*/
|
|
63
|
+
clashDistance = 50;
|
|
64
|
+
eyeHeight = 160;
|
|
65
|
+
kneeHeight = 50;
|
|
66
|
+
jumpHeight = 110;
|
|
67
|
+
enableClash = !0;
|
|
68
|
+
enableGravity = !0;
|
|
69
|
+
/**
|
|
70
|
+
* 反向旋转
|
|
71
|
+
*/
|
|
72
|
+
reverseRotate = !1;
|
|
73
|
+
_rotate = !0;
|
|
74
|
+
/**
|
|
75
|
+
* 是否能旋转
|
|
76
|
+
*/
|
|
77
|
+
get rotate() {
|
|
78
|
+
return this._rotate && (this.horizontalRotate || this.verticalRotate);
|
|
79
|
+
}
|
|
80
|
+
set rotate(e) {
|
|
81
|
+
this._rotate = e;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 旋转速度
|
|
85
|
+
*/
|
|
86
|
+
rotateSpeed = 1;
|
|
87
|
+
/**
|
|
88
|
+
* 是否开启水平方向的旋转
|
|
89
|
+
*/
|
|
90
|
+
horizontalRotate = !0;
|
|
91
|
+
/**
|
|
92
|
+
* 是否开启垂直方向旋转
|
|
93
|
+
*/
|
|
94
|
+
verticalRotate = !0;
|
|
95
|
+
/**
|
|
96
|
+
* 开启双击前进
|
|
97
|
+
*/
|
|
98
|
+
dblClickForward = !1;
|
|
99
|
+
movement = new K();
|
|
100
|
+
/**
|
|
101
|
+
* 碰撞对象过滤器
|
|
102
|
+
* @remarks
|
|
103
|
+
* 会在遍历对象时逐个调用该方法
|
|
104
|
+
*
|
|
105
|
+
* @param obj - Object3D 对象
|
|
106
|
+
* @returns true:表示检测该对象的碰撞;false | null | undefined | void:表示不检测该对象的碰撞;
|
|
107
|
+
*/
|
|
108
|
+
clashFilter;
|
|
109
|
+
/**
|
|
110
|
+
* 碰撞检测的层级
|
|
111
|
+
*/
|
|
112
|
+
clashLayers;
|
|
113
|
+
/**
|
|
114
|
+
*
|
|
115
|
+
* @param ssp
|
|
116
|
+
* @param camera - 自定义的摄像机,默认会自动生成一个新的摄像机
|
|
117
|
+
*/
|
|
118
|
+
constructor(e) {
|
|
119
|
+
this.ssp = e, this.viewport = e.viewport, this.controls = e.controls, this.camera = e.controls.camera, this.container = e.viewport.container, this.onKeyDown = this.onKeyDown.bind(this), this.onKeyUp = this.onKeyUp.bind(this), this.onDblClick = this.onDblClick.bind(this), this.onPointerDown = this.onPointerDown.bind(this), this.onPointerMove = this.onPointerMove.bind(this), this.onPointerUp = this.onPointerUp.bind(this);
|
|
120
|
+
}
|
|
121
|
+
onKeyDown(e) {
|
|
122
|
+
if (this.enabled !== !1) {
|
|
123
|
+
e: for (const [t, s] of Object.entries(this.keyCodeMap))
|
|
124
|
+
if (s.includes(e.code))
|
|
125
|
+
switch (t) {
|
|
126
|
+
case "moveForward":
|
|
127
|
+
this.state.moveForward = !0;
|
|
128
|
+
break e;
|
|
129
|
+
case "moveBackward":
|
|
130
|
+
this.state.moveBackward = !0;
|
|
131
|
+
break e;
|
|
132
|
+
case "moveLeft":
|
|
133
|
+
this.state.moveLeft = !0;
|
|
134
|
+
break e;
|
|
135
|
+
case "moveRight":
|
|
136
|
+
this.state.moveRight = !0;
|
|
137
|
+
break e;
|
|
138
|
+
case "moveUp":
|
|
139
|
+
this.state.moveUp = !0;
|
|
140
|
+
break e;
|
|
141
|
+
case "moveDown":
|
|
142
|
+
this.state.moveDown = !0;
|
|
143
|
+
break e;
|
|
144
|
+
case "rotateUp":
|
|
145
|
+
this.state.canRotate = !0, this.movement.x = 0, this.movement.y = -10;
|
|
146
|
+
break e;
|
|
147
|
+
case "rotateDown":
|
|
148
|
+
this.state.canRotate = !0, this.movement.x = 0, this.movement.y = 10;
|
|
149
|
+
break e;
|
|
150
|
+
case "rotateLeft":
|
|
151
|
+
this.state.canRotate = !0, this.movement.x = -10, this.movement.y = 0;
|
|
152
|
+
break e;
|
|
153
|
+
case "rotateRight":
|
|
154
|
+
this.state.canRotate = !0, this.movement.x = 10, this.movement.y = 0;
|
|
155
|
+
break e;
|
|
156
|
+
case "jump":
|
|
157
|
+
this.state.canJump === !0 && e.repeat === !1 && (this.jumpOffset = this.jumpHeight), this.state.canJump = !1;
|
|
158
|
+
break e;
|
|
159
|
+
}
|
|
160
|
+
(this.jumpOffset > 0 || Object.values(this.state).some((t) => t)) && this.ssp.render();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
onKeyUp(e) {
|
|
164
|
+
e: for (const [t, s] of Object.entries(this.keyCodeMap))
|
|
165
|
+
if (s.includes(e.code))
|
|
166
|
+
switch (t) {
|
|
167
|
+
case "moveForward":
|
|
168
|
+
this.state.moveForward = !1;
|
|
169
|
+
break e;
|
|
170
|
+
case "moveBackward":
|
|
171
|
+
this.state.moveBackward = !1;
|
|
172
|
+
break e;
|
|
173
|
+
case "moveLeft":
|
|
174
|
+
this.state.moveLeft = !1;
|
|
175
|
+
break e;
|
|
176
|
+
case "moveRight":
|
|
177
|
+
this.state.moveRight = !1;
|
|
178
|
+
break e;
|
|
179
|
+
case "moveUp":
|
|
180
|
+
this.state.moveUp = !1;
|
|
181
|
+
break e;
|
|
182
|
+
case "moveDown":
|
|
183
|
+
this.state.moveDown = !1;
|
|
184
|
+
break e;
|
|
185
|
+
case "rotateUp":
|
|
186
|
+
case "rotateDown":
|
|
187
|
+
case "rotateLeft":
|
|
188
|
+
case "rotateRight":
|
|
189
|
+
this.state.canRotate = !1;
|
|
190
|
+
break e;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
_dblVector = new g();
|
|
194
|
+
_dblDeltaVector = new g();
|
|
195
|
+
onDblClick(e) {
|
|
196
|
+
if (this.dblClickForward === !0) {
|
|
197
|
+
const [t] = this.ssp.viewport.getIntersects(e);
|
|
198
|
+
if (t) {
|
|
199
|
+
const { point: s } = t;
|
|
200
|
+
s.y += this.eyeHeight, s.sub(this.camera.position), this._dblVector.copy(s), this._dblDeltaVector.set(0, 0, 0), this.ssp.render();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
_pointerId = null;
|
|
205
|
+
onPointerDown(e) {
|
|
206
|
+
this._pointerId === null && // 左键
|
|
207
|
+
e.button === 0 && (this.container.setPointerCapture(e.pointerId), this._pointerId = e.pointerId, this.state.canRotate = !0);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* events handler for pointer movement
|
|
211
|
+
*/
|
|
212
|
+
onPointerMove(e) {
|
|
213
|
+
if (e.preventDefault(), this.enabled && this.state.canRotate) {
|
|
214
|
+
let t = e.movementY, s = e.movementX;
|
|
215
|
+
this.reverseRotate && (s = -s, t = -t), this.movement.x = s, this.movement.y = t, this.ssp.render();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
onPointerUp(e) {
|
|
219
|
+
this._pointerId !== null && (this.container.releasePointerCapture(e.pointerId), this._pointerId = null, this.state.canRotate = !1);
|
|
220
|
+
}
|
|
221
|
+
clearClashCache() {
|
|
222
|
+
this.kneeInterObject = null, this.eyeInterObject = null;
|
|
223
|
+
}
|
|
224
|
+
lastDirection = new g();
|
|
225
|
+
onClashCheck(e, t) {
|
|
226
|
+
const s = t.length(), i = t.clone().divideScalar(s);
|
|
227
|
+
i.distanceToSquared(this.lastDirection) > 1e-9 && this.clearClashCache(), this.lastDirection = i;
|
|
228
|
+
const {
|
|
229
|
+
eyeHeight: v,
|
|
230
|
+
kneeHeight: p,
|
|
231
|
+
camera: n,
|
|
232
|
+
clashCheckDistance: h,
|
|
233
|
+
clashDistance: m,
|
|
234
|
+
clashLayers: r
|
|
235
|
+
} = this;
|
|
236
|
+
let { kneeInterObject: c, eyeInterObject: y } = this;
|
|
237
|
+
if (!c) {
|
|
238
|
+
const a = e.clone().setY(e.y - v + p), o = new O(
|
|
239
|
+
a,
|
|
240
|
+
i,
|
|
241
|
+
0,
|
|
242
|
+
h
|
|
243
|
+
);
|
|
244
|
+
o.firstHitOnly = !0, r != null && R(o.layers, r), o.camera = n;
|
|
245
|
+
const u = this.getCheckedObjects(a), d = I(o, u);
|
|
246
|
+
this.kneeInterObject = c = d[0];
|
|
247
|
+
}
|
|
248
|
+
let l = -s;
|
|
249
|
+
if (c && (l += c.distance, l < m))
|
|
250
|
+
return !0;
|
|
251
|
+
if (!y) {
|
|
252
|
+
const a = new O(
|
|
253
|
+
e,
|
|
254
|
+
i,
|
|
255
|
+
0,
|
|
256
|
+
h
|
|
257
|
+
);
|
|
258
|
+
a.firstHitOnly = !0, r != null && R(a.layers, r), a.camera = n;
|
|
259
|
+
const o = this.getCheckedObjects(e), u = I(a, o);
|
|
260
|
+
this.eyeInterObject = y = u[0];
|
|
261
|
+
}
|
|
262
|
+
let f = -s;
|
|
263
|
+
if (y) {
|
|
264
|
+
if (f += y.distance, f < m) return !0;
|
|
265
|
+
y.distance = f;
|
|
266
|
+
}
|
|
267
|
+
return c && (c.distance = l), !1;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* 模型对象的搜索半径的系数
|
|
271
|
+
* @remarks
|
|
272
|
+
* 搜索半径是 clashCheckDistance 的多少倍
|
|
273
|
+
*/
|
|
274
|
+
searchRadiusFactor = 3;
|
|
275
|
+
checkedSphere = new _();
|
|
276
|
+
getCheckedObjects(e) {
|
|
277
|
+
const {
|
|
278
|
+
clashDistance: t,
|
|
279
|
+
clashCheckDistance: s,
|
|
280
|
+
searchRadiusFactor: i,
|
|
281
|
+
clashFilter: v
|
|
282
|
+
} = this, p = s * i, n = this.checkedSphere, h = p + t;
|
|
283
|
+
n.set(e, h);
|
|
284
|
+
const m = v ?? function() {
|
|
285
|
+
return !0;
|
|
286
|
+
};
|
|
287
|
+
return this.viewport.scener.intersectsList.getAll().filter((c) => m(c) ? L(n, c) : !1);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* 重力搜索系数
|
|
291
|
+
* @remarks
|
|
292
|
+
* 重力搜索系数 表示 向下搜索多少个 eyeHeight 的深度
|
|
293
|
+
*/
|
|
294
|
+
gravitySearchFactor = 3;
|
|
295
|
+
gravityCheckedObjects = null;
|
|
296
|
+
gravityCheckedBox = new H();
|
|
297
|
+
getGravityCheckedObjects(e, t) {
|
|
298
|
+
const s = this.gravityCheckedBox;
|
|
299
|
+
let i = this.gravityCheckedObjects;
|
|
300
|
+
if (i) {
|
|
301
|
+
const v = e.clone();
|
|
302
|
+
v.y = t, s.containsPoint(e) && s.containsPoint(v) || (i = null);
|
|
303
|
+
}
|
|
304
|
+
if (!i) {
|
|
305
|
+
const {
|
|
306
|
+
eyeHeight: v,
|
|
307
|
+
clashCheckDistance: p,
|
|
308
|
+
gravitySearchFactor: n,
|
|
309
|
+
clashDistance: h,
|
|
310
|
+
clashFilter: m
|
|
311
|
+
} = this, r = p + h, c = new g(r, r, 0), y = e.clone().add(c), l = e.clone().sub(c);
|
|
312
|
+
l.y -= v * n, s.set(l, y);
|
|
313
|
+
const f = this.viewport.scener.intersectsList.getAll(), a = m ?? function() {
|
|
314
|
+
return !0;
|
|
315
|
+
};
|
|
316
|
+
i = f.filter((o) => a(o) ? L(s, o) : !1);
|
|
317
|
+
}
|
|
318
|
+
return i;
|
|
319
|
+
}
|
|
320
|
+
gravityClashCheck(e, t) {
|
|
321
|
+
let s = this.gravityInterObject;
|
|
322
|
+
if (s) {
|
|
323
|
+
const { object: i, face: v, instanceId: p } = s, n = i.geometry?.getAttribute(
|
|
324
|
+
"position"
|
|
325
|
+
);
|
|
326
|
+
if (n && v) {
|
|
327
|
+
let h = s.facePoints;
|
|
328
|
+
if (!h) {
|
|
329
|
+
let l = i.matrixWorld;
|
|
330
|
+
if (p != null) {
|
|
331
|
+
const k = new V();
|
|
332
|
+
i.getMatrixAt(p, k), l = k.premultiply(l);
|
|
333
|
+
}
|
|
334
|
+
const { a: f, b: a, c: o } = v, u = new g(
|
|
335
|
+
n.getX(f),
|
|
336
|
+
n.getY(f),
|
|
337
|
+
n.getZ(f)
|
|
338
|
+
);
|
|
339
|
+
u.applyMatrix4(l), u.setY(0);
|
|
340
|
+
const d = new g(
|
|
341
|
+
n.getX(a),
|
|
342
|
+
n.getY(a),
|
|
343
|
+
n.getZ(a)
|
|
344
|
+
);
|
|
345
|
+
d.applyMatrix4(l), d.setY(0);
|
|
346
|
+
const b = new g(
|
|
347
|
+
n.getX(o),
|
|
348
|
+
n.getY(o),
|
|
349
|
+
n.getZ(o)
|
|
350
|
+
);
|
|
351
|
+
b.applyMatrix4(l), b.setY(0), s.facePoints = h = [
|
|
352
|
+
u,
|
|
353
|
+
d,
|
|
354
|
+
b
|
|
355
|
+
];
|
|
356
|
+
}
|
|
357
|
+
let m = h[2], r = null;
|
|
358
|
+
const c = e.clone();
|
|
359
|
+
c.y = 0, h.every((l) => {
|
|
360
|
+
const f = l.clone();
|
|
361
|
+
f.sub(m);
|
|
362
|
+
const a = c.clone();
|
|
363
|
+
return a.sub(m), f.cross(a), r && f.dot(r) <= 0 ? !1 : (r = f, m = l, !0);
|
|
364
|
+
}) || (this.gravityInterObject = s = null);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (!s) {
|
|
368
|
+
const i = new O(e, new g(0, -1, 0));
|
|
369
|
+
i.firstHitOnly = !0;
|
|
370
|
+
const v = this.clashLayers;
|
|
371
|
+
v != null && R(i.layers, v), i.camera = this.camera;
|
|
372
|
+
const p = this.getGravityCheckedObjects(e, t), n = I(i, p);
|
|
373
|
+
this.gravityInterObject = s = n[0];
|
|
374
|
+
}
|
|
375
|
+
return s;
|
|
376
|
+
}
|
|
377
|
+
setOptions(e) {
|
|
378
|
+
const {
|
|
379
|
+
position: t = new g(),
|
|
380
|
+
rotation: s = new F(),
|
|
381
|
+
moveSpeed: i,
|
|
382
|
+
eyeHeight: v,
|
|
383
|
+
kneeHeight: p,
|
|
384
|
+
jumpHeight: n,
|
|
385
|
+
enableClash: h,
|
|
386
|
+
enableGravity: m,
|
|
387
|
+
searchRadiusFactor: r,
|
|
388
|
+
clashDistance: c,
|
|
389
|
+
clashCheckDistance: y,
|
|
390
|
+
gravitySpeed: l,
|
|
391
|
+
gravitySearchFactor: f,
|
|
392
|
+
reverseRotate: a,
|
|
393
|
+
rotate: o,
|
|
394
|
+
rotateSpeed: u,
|
|
395
|
+
horizontalRotate: d,
|
|
396
|
+
verticalRotate: b,
|
|
397
|
+
dblClickForward: k,
|
|
398
|
+
clashFilter: C,
|
|
399
|
+
clashLayers: x
|
|
400
|
+
} = e;
|
|
401
|
+
if (v && (this.eyeHeight = v), p && (this.kneeHeight = p), n && (this.jumpHeight = n), r && (this.searchRadiusFactor = r), c && (this.clashDistance = c), y && (this.clashCheckDistance = y), l && (this.gravitySpeed = l), f && (this.gravitySearchFactor = f), a != null && (this.reverseRotate = a), o != null && (this.rotate = o), d != null && (this.horizontalRotate = d), b != null && (this.verticalRotate = b), S.isBoolean(k) && (this.dblClickForward = k), S.isNumber(u) && (this.rotateSpeed = u), h != null && (this.enableClash = h), m != null && (this.enableGravity = m), C != null && (this.clashFilter = C), x != null && (this.clashLayers = x), t && (this.controls.setPosition(
|
|
402
|
+
t.x,
|
|
403
|
+
t.y + this.eyeHeight,
|
|
404
|
+
t.z
|
|
405
|
+
), this.gravityInterObject = null, this.clearClashCache()), s) {
|
|
406
|
+
const j = S.computeTargetByRotation(this.controls.getPosition(new g()), s, U);
|
|
407
|
+
this.controls.setTarget(j.x, j.y, j.z);
|
|
408
|
+
}
|
|
409
|
+
i && (this.moveSpeed = i);
|
|
410
|
+
}
|
|
411
|
+
start(e) {
|
|
412
|
+
this.viewport.controls.saveState(), this.viewport.controls.enabled = !1, this.enabled = !0, this.setOptions(e), this.viewport.postRender.set("FirstPersonControls", this.update.bind(this)), this.ssp.signals.dblClick.add(this.onDblClick), this.ssp.signals.keyDown.add(this.onKeyDown), this.ssp.signals.keyUp.add(this.onKeyUp);
|
|
413
|
+
const t = this.container;
|
|
414
|
+
t.addEventListener("pointerdown", this.onPointerDown), t.addEventListener("pointermove", this.onPointerMove), t.addEventListener("pointerup", this.onPointerUp), t.style.touchAction = "none", t.style.userSelect = "none";
|
|
415
|
+
}
|
|
416
|
+
stop() {
|
|
417
|
+
this.viewport.controls.reset(), this.viewport.controls.enabled = !0, this.enabled = !1, this.viewport.postRender.delete("FirstPersonControls"), this.ssp.signals.dblClick.remove(this.onDblClick), this.ssp.signals.keyDown.remove(this.onKeyDown), this.ssp.signals.keyUp.remove(this.onKeyUp);
|
|
418
|
+
const e = this.container;
|
|
419
|
+
e.removeEventListener("pointerdown", this.onPointerDown), e.removeEventListener("pointermove", this.onPointerMove), e.removeEventListener("pointerup", this.onPointerUp), e.style.touchAction = "auto", e.style.userSelect = "auto", this.ssp.render();
|
|
420
|
+
}
|
|
421
|
+
gravityInterObject = null;
|
|
422
|
+
kneeInterObject = null;
|
|
423
|
+
eyeInterObject = null;
|
|
424
|
+
update() {
|
|
425
|
+
if (!this.enabled) return;
|
|
426
|
+
const { delta: e } = this.viewport.state, t = new g(), { controls: s, state: i, camera: v, eyeHeight: p, kneeHeight: n } = this, h = s.getPosition(new g()), m = this.moveSpeed * 20, r = this.gravitySpeed * 20;
|
|
427
|
+
i.moveForward && (t.z -= m), i.moveBackward && (t.z += m), i.moveLeft && (t.x -= m), i.moveRight && (t.x += m), i.moveUp && (t.y += r * 2), i.moveDown && (t.y -= r * 2), t.multiplyScalar(e);
|
|
428
|
+
const { x: c, y } = this.movement, l = this.horizontalRotate && c !== 0, f = this.verticalRotate && y !== 0;
|
|
429
|
+
if (this.rotate && i.canRotate && (l || f)) {
|
|
430
|
+
let { azimuthAngle: d, polarAngle: b } = s;
|
|
431
|
+
f && (b -= y * 3e-3 * this.rotateSpeed), l && (d -= c * 3e-3 * this.rotateSpeed), s.rotateTo(d, b);
|
|
432
|
+
}
|
|
433
|
+
const a = new F(0, 0, 0, "YXZ");
|
|
434
|
+
if (a.setFromQuaternion(v.quaternion), !(a.y === 0 || t.equals(new g()))) {
|
|
435
|
+
const d = new A();
|
|
436
|
+
d.setFromAxisAngle(new g(0, 1, 0), a.y), t.applyQuaternion(d);
|
|
437
|
+
}
|
|
438
|
+
if (!this._dblVector.equals(new g())) {
|
|
439
|
+
const d = this._dblVector.clone().multiplyScalar(e);
|
|
440
|
+
this._dblDeltaVector.add(d), this._dblDeltaVector.length() > this._dblVector.length() ? (this._dblVector.set(0, 0, 0), this._dblDeltaVector.set(0, 0, 0)) : t.add(d);
|
|
441
|
+
}
|
|
442
|
+
const o = h.clone();
|
|
443
|
+
if ((!this.enableClash || !this.onClashCheck(h, t)) && (o.add(t), this.gravityInterObject)) {
|
|
444
|
+
const b = this.gravityInterObject.point.clone().sub(o);
|
|
445
|
+
b.y = 0, b.length() > n && (this.gravityInterObject = null);
|
|
446
|
+
}
|
|
447
|
+
let u = o.y;
|
|
448
|
+
if (this.enableGravity) {
|
|
449
|
+
const d = u;
|
|
450
|
+
this.jumpOffset > 0 && (this.jumpOffset -= r * e, u += r * 2 * e), u -= r * e, i.canJump = !1;
|
|
451
|
+
const b = this.gravityClashCheck(o, u);
|
|
452
|
+
if (b) {
|
|
453
|
+
const C = b.point.y + p;
|
|
454
|
+
u < C && (u = C, this.jumpOffset = 0, i.canJump = !0);
|
|
455
|
+
}
|
|
456
|
+
d !== u && this.clearClashCache();
|
|
457
|
+
}
|
|
458
|
+
o.y = u, (!P(h.x, o.x) || !P(h.y, o.y) || !P(h.z, o.z)) && (s.moveTo(o.x, o.y, o.z), s.dollyTo(U));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
export {
|
|
462
|
+
M as default
|
|
463
|
+
};
|
package/dist/tools.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ import { Box3, Object3D, Sphere, Layers, Raycaster } from 'three';
|
|
|
4
4
|
*/
|
|
5
5
|
export declare function boundingIsIntersected(target: Box3 | Sphere, obj: Object3D): boolean;
|
|
6
6
|
export declare function setLayers(layer: Layers, layerNums: number[]): void;
|
|
7
|
-
export declare function raycasterFilter(raycaster: Raycaster, objs: Object3D[]): import(
|
|
7
|
+
export declare function raycasterFilter(raycaster: Raycaster, objs: Object3D[]): import('three').Intersection<Object3D<import('three').Object3DEventMap>>[];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soonspacejs/plugin-first-person-controls",
|
|
3
3
|
"pluginName": "FirstPersonControlsPlugin",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.14.1",
|
|
5
5
|
"description": "FirstPersonControls plugin for SoonSpace.js",
|
|
6
6
|
"main": "dist/index.esm.js",
|
|
7
7
|
"module": "dist/index.esm.js",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
],
|
|
14
14
|
"author": "xunwei",
|
|
15
15
|
"license": "UNLICENSED",
|
|
16
|
-
"gitHead": "
|
|
16
|
+
"gitHead": "27d5e0bcd79ff71c8e2943a8420c39624ae6f8e6",
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"soonspacejs": "2.
|
|
18
|
+
"soonspacejs": "2.14.1"
|
|
19
19
|
}
|
|
20
20
|
}
|