Skip to content

Commit 8d0bc05

Browse files
committed
v1.2.22 - allow ssl local server, remove crosshair on mobile, move some touch functionality, add alpha offset on mobile gyro controls
1 parent 3e9ce55 commit 8d0bc05

File tree

7 files changed

+135
-36
lines changed

7 files changed

+135
-36
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@ yarn-error.log*
3434

3535
staging
3636
dist
37-
*.tgz
37+
*.tgz
38+
*.key
39+
*.crt

examples/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
},
1818
"scripts": {
1919
"start": "react-app-rewired start",
20+
"start-ssl": "HTTPS=true SSL_CRT_FILE=cert.crt SSL_KEY_FILE=cert.key react-app-rewired start",
2021
"build": "react-app-rewired build",
2122
"eject": "react-app-rewired eject"
2223
},

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "spacesvr",
3-
"version": "1.2.21",
3+
"version": "1.2.22",
44
"private": true,
55
"description": "An Environment for WebXR Spaces",
66
"keywords": [

src/core/controls/GyroControls.tsx

+84-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
import { DeviceOrientationControls } from "three/examples/jsm/controls/DeviceOrientationControls";
2-
import { MutableRefObject, ReactNode, useEffect, useState } from "react";
2+
import {
3+
MutableRefObject,
4+
ReactNode,
5+
useEffect,
6+
useRef,
7+
useState,
8+
} from "react";
39
import { useFrame, useThree } from "react-three-fiber";
4-
import { Quaternion, Vector3 } from "three";
10+
import { Quaternion, Vector2, Vector3 } from "three";
11+
import { config, useSpring } from "react-spring";
12+
import {
13+
Touch,
14+
DefaultTouch,
15+
getCurrentTouch,
16+
tappedNipple,
17+
} from "../utils/touch";
18+
import { getSpringValues } from "../utils/spring";
19+
20+
const ALPHA_SENSITIVITY = 0.008;
521

622
type GyroControlsProps = {
723
quaternion: MutableRefObject<Quaternion>;
@@ -15,6 +31,8 @@ type GyroControlsProps = {
1531
* A required fallback component will be used in the place of the gyroscope
1632
* controls until they are accepted and in use.
1733
*
34+
* Some code sampled from TouchFPSCamera.ts
35+
*
1836
* @param props
1937
* @constructor
2038
*/
@@ -26,6 +44,14 @@ export const GyroControls = (props: GyroControlsProps) => {
2644
const [controls, setControls] = useState<DeviceOrientationControls>();
2745
const [enableGyro, setEnableGyro] = useState(false);
2846

47+
// dragging for y axis offset
48+
const touchStartPos = useRef<Touch>(DefaultTouch);
49+
const currentOffset = useRef(0);
50+
const [spring, setSpring] = useSpring(() => ({
51+
a: [0],
52+
config: { ...config.default, precision: 0.001 },
53+
}));
54+
2955
// try to prompt user for device controls
3056
useEffect(() => {
3157
if (!controls) {
@@ -52,6 +78,8 @@ export const GyroControls = (props: GyroControlsProps) => {
5278
}
5379

5480
if (controls) {
81+
const [a] = getSpringValues(spring);
82+
controls.alphaOffset = -a * ALPHA_SENSITIVITY;
5583
controls.update();
5684
quaternion.current = camera.quaternion;
5785
}
@@ -62,6 +90,60 @@ export const GyroControls = (props: GyroControlsProps) => {
6290
}
6391
});
6492

93+
// touch move scripts
94+
const onTouchStart = (ev: TouchEvent) => {
95+
if (touchStartPos.current.id !== -1) {
96+
return;
97+
}
98+
99+
if (tappedNipple(ev)) {
100+
touchStartPos.current = DefaultTouch;
101+
return;
102+
}
103+
104+
// get last in list (most recent touch) to not confuse with movement
105+
const touchIndex = ev.touches.length - 1;
106+
const { clientX, clientY, identifier: id } = ev.touches[touchIndex];
107+
108+
touchStartPos.current = { pos: new Vector2(clientX, clientY), id };
109+
};
110+
111+
const onTouchMove = (ev: TouchEvent) => {
112+
const touch = getCurrentTouch(touchStartPos.current.id, ev.touches);
113+
114+
if (!touch) {
115+
return;
116+
}
117+
118+
const extraOffset = touch.clientX - touchStartPos.current.pos.x;
119+
setSpring({ a: [currentOffset.current + extraOffset] });
120+
};
121+
const onTouchEnd = (ev: TouchEvent) => {
122+
const touch = getCurrentTouch(touchStartPos.current.id, ev.changedTouches);
123+
124+
if (!touch) {
125+
return;
126+
}
127+
128+
const finalOffset = touch.clientX - touchStartPos.current.pos.x;
129+
setSpring({ a: [currentOffset.current + finalOffset] });
130+
currentOffset.current += finalOffset;
131+
touchStartPos.current.id = -1;
132+
};
133+
134+
// register touch events
135+
useEffect(() => {
136+
document.addEventListener("touchstart", onTouchStart);
137+
document.addEventListener("touchmove", onTouchMove);
138+
document.addEventListener("touchend", onTouchEnd);
139+
140+
return () => {
141+
document.removeEventListener("touchstart", onTouchStart);
142+
document.removeEventListener("touchmove", onTouchMove);
143+
document.removeEventListener("touchend", onTouchEnd);
144+
};
145+
}, []);
146+
65147
if (!enableGyro) {
66148
return <>{fallback}</>;
67149
}

src/core/controls/TouchFPSCamera.tsx

+8-32
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import { useRef, useEffect, MutableRefObject } from "react";
22
import { useFrame, useThree } from "react-three-fiber";
33
import { Quaternion, Vector3, Vector2, Euler } from "three";
4+
import {
5+
Touch,
6+
DefaultTouch,
7+
getCurrentTouch,
8+
tappedNipple,
9+
} from "../utils/touch";
410

511
type DragFPSCameraProps = {
612
quaternion: MutableRefObject<Quaternion>;
713
position: MutableRefObject<Vector3>;
814
};
915

10-
type Touch = {
11-
pos: Vector2;
12-
id: number;
13-
};
14-
15-
const DefaultTouch = {
16-
pos: new Vector2(0, 0),
17-
id: -1,
18-
};
19-
2016
const DRAG_SENSITIVITY = new Vector2(0.7, 0.7);
2117

2218
/**
@@ -54,26 +50,6 @@ const TouchFPSCamera = (props: DragFPSCameraProps) => {
5450
return newEuler;
5551
};
5652

57-
const tappedNipple = (ev: TouchEvent) => {
58-
// get the relevant touched element (casted as an Element)
59-
const ele = ev.touches[ev.touches.length - 1].target as Element;
60-
return (
61-
ele.classList.contains("nipple-container") ||
62-
ele.classList.contains("front") ||
63-
ele.classList.contains("back")
64-
);
65-
};
66-
67-
const getCurrentTouch = (touches: TouchList) => {
68-
const len = touches.length;
69-
for (let i = 0; i < len; i++) {
70-
if (touchStartPos.current.id === touches[i].identifier) {
71-
return touches[i];
72-
}
73-
}
74-
return undefined;
75-
};
76-
7753
// touch move scripts
7854
const onTouchStart = (ev: TouchEvent) => {
7955
if (touchStartPos.current.id !== -1) {
@@ -93,7 +69,7 @@ const TouchFPSCamera = (props: DragFPSCameraProps) => {
9369
};
9470

9571
const onTouchMove = (ev: TouchEvent) => {
96-
const touch = getCurrentTouch(ev.touches);
72+
const touch = getCurrentTouch(touchStartPos.current.id, ev.touches);
9773

9874
if (!touch) {
9975
return;
@@ -105,7 +81,7 @@ const TouchFPSCamera = (props: DragFPSCameraProps) => {
10581
quaternion.current = camera.quaternion;
10682
};
10783
const onTouchEnd = (ev: TouchEvent) => {
108-
const touch = getCurrentTouch(ev.changedTouches);
84+
const touch = getCurrentTouch(touchStartPos.current.id, ev.changedTouches);
10985

11086
if (!touch) {
11187
return;

src/core/ui/Crosshair.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import styled from "@emotion/styled";
2+
import { isMobile } from "react-device-detect";
23

34
const Element = styled.div`
45
position: fixed;
@@ -25,6 +26,10 @@ const Element = styled.div`
2526
`;
2627

2728
const Crosshair = () => {
29+
if (isMobile) {
30+
return null;
31+
}
32+
2833
return <Element />;
2934
};
3035

src/core/utils/touch.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Vector2 } from "three";
2+
3+
export type Touch = {
4+
pos: Vector2;
5+
id: number;
6+
};
7+
8+
export const DefaultTouch = {
9+
pos: new Vector2(0, 0),
10+
id: -1,
11+
};
12+
13+
// get the current touch from touch array
14+
export const getCurrentTouch = (curTouchId: number, touches: TouchList) => {
15+
const len = touches.length;
16+
for (let i = 0; i < len; i++) {
17+
if (curTouchId === touches[i].identifier) {
18+
return touches[i];
19+
}
20+
}
21+
return undefined;
22+
};
23+
24+
// check whether given touch tapped nipple
25+
export const tappedNipple = (ev: TouchEvent) => {
26+
// get the relevant touched element (casted as an Element)
27+
const ele = ev.touches[ev.touches.length - 1].target as Element;
28+
return (
29+
ele.classList.contains("nipple-container") ||
30+
ele.classList.contains("front") ||
31+
ele.classList.contains("back")
32+
);
33+
};

0 commit comments

Comments
 (0)