Skip to content

Commit 4b3dcc3

Browse files
feat: touch control and 3D joystick
1 parent 81f4c06 commit 4b3dcc3

File tree

11 files changed

+890
-49
lines changed

11 files changed

+890
-49
lines changed

example/Experience.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default function Experience() {
4040

4141
return (
4242
<>
43-
<Perf position="top-left" />
43+
<Perf position="top-left" minimal />
4444

4545
<Grid
4646
args={[300, 300]}
@@ -93,7 +93,7 @@ export default function Experience() {
9393

9494
{/* Shoting cubes */}
9595
<ShotCube />
96-
</Physics>
96+
</Physics >
9797
</>
9898
);
9999
}

example/ecctrlJoystick.png

465 KB
Loading

example/index.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,33 @@ import ReactDOM from "react-dom/client";
33
import { Canvas } from "@react-three/fiber";
44
import Experience from "../example/Experience";
55
import { Leva } from "leva";
6+
import { EcctrlJoystick } from "../src/EcctrlJoystick";
7+
import { useEffect, useState } from "react";
68

79
const root = ReactDOM.createRoot(document.querySelector("#root"));
810

11+
const EcctrlJoystickControls = () => {
12+
const [isTouchScreen, setIsTouchScreen] = useState(false)
13+
useEffect(() => {
14+
// Check if using a touch control device, show/hide joystick
15+
if (('ontouchstart' in window) ||
16+
(navigator.maxTouchPoints > 0)) {
17+
setIsTouchScreen(true)
18+
} else {
19+
setIsTouchScreen(false)
20+
}
21+
}, [])
22+
return (
23+
<>
24+
{isTouchScreen && <EcctrlJoystick buttonNumber={5} />}
25+
</>
26+
)
27+
}
28+
929
root.render(
1030
<>
1131
<Leva collapsed />
32+
<EcctrlJoystickControls />
1233
<Canvas
1334
shadows
1435
camera={{
@@ -17,7 +38,9 @@ root.render(
1738
far: 1000,
1839
}}
1940
onPointerDown={(e) => {
20-
(e.target as HTMLCanvasElement).requestPointerLock();
41+
if (e.pointerType === 'mouse') {
42+
(e.target as HTMLCanvasElement).requestPointerLock()
43+
}
2144
}}
2245
>
2346
<Experience />

example/style.css

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ body,
1717
.controlKeys {
1818
position: absolute;
1919
width: 20rem;
20-
left: 5%;
20+
left: 50%;
21+
margin-left: -10rem;
2122
bottom: 13%;
2223
user-select: none;
2324
-moz-user-select: none;
@@ -38,3 +39,21 @@ body,
3839
.title > a {
3940
color: rgb(79, 189, 249);
4041
}
42+
43+
@media (max-width: 768px) {
44+
.controlKeys {
45+
display: none;
46+
}
47+
.title {
48+
display: none;
49+
}
50+
}
51+
52+
@media (max-height: 450px) {
53+
.controlKeys {
54+
display: none;
55+
}
56+
.title {
57+
display: none;
58+
}
59+
}

featurelog.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
## New Features
22

3+
### (2023-11-18) EcctrlJoystick:
4+
5+
- Ecctrl now supports touch screen control!
6+
7+
- You can easily import and use the built-in 3D joystick.
8+
(note: place EcctrlJoystick outside of the canvas component)
9+
10+
```js
11+
import Ecctrl, {EcctrlJoystick} from 'ecctrl'
12+
//...
13+
<EcctrlJoystick />
14+
<Canvas>
15+
{/* ... */}
16+
</Canvas>
17+
//...
18+
```
19+
20+
- For more detailed settings, including lights, materials, and textures, please refer to the following sections.
21+
22+
- Additionally, I've prepared a simple [Ecctrl CodeSandbox](https://codesandbox.io/s/ecctrl-w-o-animations-3k3zxt) for online testing and demostration.
23+
24+
- Also, here is another [Ecctrl CodeSandbox](https://codesandbox.io/s/ecctrl-with-animations-nr4493) showcasing character animation functionality.
25+
26+
[![screenshot](example/ecctrlJoystick.png)](https://codesandbox.io/s/ecctrl-w-o-animations-3k3zxt)
27+
328
### (2023-10-02) Pmndrs/ecctrl & npm package:
429

530
- The character controller now integrated with [pmndrs/ecctrl](https://github.com/pmndrs/ecctrl)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ecctrl",
3-
"version": "1.0.42",
3+
"version": "1.0.45",
44
"author": "Erdong Chen",
55
"license": "MIT",
66
"description": "A floating rigibody character controller for R3F",

readme.md

Lines changed: 129 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,30 @@
1313

1414
## New Features
1515

16-
### (2023-10-02) Pmndrs/ecctrl & npm package:
16+
### (2023-11-18) EcctrlJoystick:
1717

18-
- The character controller now integrated with [pmndrs/ecctrl](https://github.com/pmndrs/ecctrl)
18+
- Ecctrl now supports touch screen control!
1919

20-
- You can easily install the npm package using the following command:
21-
22-
```bash
23-
npm install ecctrl
24-
```
25-
26-
To get started, import `Ecctrl` and `EcctrlAnimation`, then wrap your character model within `<Ecctrl>`:
20+
- You can easily import and use the built-in 3D joystick.
21+
(note: place EcctrlJoystick outside of the canvas component)
2722

2823
```js
29-
import Ecctrl, {EcctrlAnimation} from 'ecctrl'
30-
...
31-
<Ecctrl>
32-
<CharacterModel/>
33-
</Ecctrl>
34-
...
24+
import Ecctrl, {EcctrlJoystick} from 'ecctrl'
25+
//...
26+
<EcctrlJoystick />
27+
<Canvas>
28+
{/* ... */}
29+
</Canvas>
30+
//...
3531
```
3632

33+
- For more detailed settings, including lights, materials, and textures, please refer to the following sections.
34+
3735
- Additionally, I've prepared a simple [Ecctrl CodeSandbox](https://codesandbox.io/s/ecctrl-w-o-animations-3k3zxt) for online testing and demostration.
3836

3937
- Also, here is another [Ecctrl CodeSandbox](https://codesandbox.io/s/ecctrl-with-animations-nr4493) showcasing character animation functionality.
4038

41-
[![screenshot](example/PmndrsEcctrl.png)](https://codesandbox.io/s/ecctrl-w-o-animations-3k3zxt)
39+
[![screenshot](example/ecctrlJoystick.png)](https://codesandbox.io/s/ecctrl-w-o-animations-3k3zxt)
4240

4341
Check out the [featurelog.md](/featurelog.md) for details on previous updates and features.
4442

@@ -127,10 +125,12 @@ EcctrlProps: {
127125
camInitDis: -5, // Initial camera distance
128126
camMaxDis: -7, // Maximum camera distance
129127
camMinDis: -0.7, // Minimum camera distance
130-
camInitDir: 0, // Camera initial position direction (in rad)
131-
camMoveSpeed = 1, // Camera moving speed multiplier
132-
camZoomSpeed = 1, // Camera zooming speed multiplier
133-
camCollisionOffset = 0.7, // Camera collision offset
128+
camInitDir: { x: 0, y: 0, z: 0 }, // Camera initial rotation direction (in rad)
129+
camTargetPos: { x: 0, y: 0, z: 0 }, // Camera target position
130+
camMoveSpeed: 1, // Camera moving speed multiplier
131+
camZoomSpeed: 1, // Camera zooming speed multiplier
132+
camCollision: true, // Camera collision active/deactive
133+
camCollisionOffset: 0.7, // Camera collision offset
134134
// Follow light setups
135135
followLightPos: { x: 20, y: 30, z: 10 }, // Follow light position
136136
// Base control setups
@@ -158,7 +158,7 @@ EcctrlProps: {
158158
dampingC: 0.08, // Damping coefficient
159159
// Slope Ray setups
160160
showSlopeRayOrigin: false, // Show slope ray origin
161-
slopeMaxAngle = 1, // in rad, the max walkable slope angle
161+
slopeMaxAngle: 1, // in rad, the max walkable slope angle
162162
slopeRayOriginOffest: capsuleRadius - 0.03, // Slope ray origin offset
163163
slopeRayLength: capsuleRadius + 3, // Slope ray length
164164
slopeRayDir: { x: 0, y: -1, z: 0 }, // Slope ray direction
@@ -306,6 +306,114 @@ const action4Animation = useGame((state) => state.action4);
306306
//const additionalAnimation = useGame((state) => state.triggerFunction);
307307
```
308308

309+
### EcctrlJoystick and Touch buttons
310+
311+
To get start, simply import `EcctrlJoystick` from `ecctrl`
312+
313+
```js
314+
import { EcctrlJoystick } from "ecctrl";
315+
```
316+
317+
Place `<EcctrlJoystick>` outside of your canvas component, and you're done!
318+
319+
```js
320+
//...
321+
<EcctrlJoystick />
322+
<Canvas>
323+
{/* ... */}
324+
</Canvas>
325+
//...
326+
```
327+
328+
You can also add lights or additional meshs like so (note: this will create components twice, once inside the joystick's scene, another inside the buttons' scene, so keep an eye on performance):
329+
330+
```js
331+
//...
332+
<EcctrlJoystick>
333+
<ambientLight />
334+
<mesh>
335+
<boxGeometry args={[1,1,1]} />
336+
</mesh>
337+
</EcctrlJoystick>
338+
<Canvas>
339+
{/* ... */}
340+
</Canvas>
341+
//...
342+
```
343+
344+
Additionally, you can change components' material, geometry, or texture as you like:
345+
346+
```js
347+
//...
348+
<EcctrlJoystick
349+
joystickBaseProps={{
350+
receiveShadow: true,
351+
material: new THREE.MeshStandardMaterial({ color: "grey" })
352+
}}
353+
/>
354+
<Canvas>
355+
{/* ... */}
356+
</Canvas>
357+
//...
358+
```
359+
360+
Here are all the properties you can play with for `<EcctrlJoystick>`:
361+
362+
```js
363+
EcctrlJoystickProps: {
364+
// Joystick props
365+
children?: ReactNode;
366+
joystickPositionLeft?: number; // joystick div container position left
367+
joystickPositionBottom?: number; // joystick div container position bottom
368+
joystickHeightAndWidth?: number; // joystick div container height and width
369+
joystickCamZoom?: number; // camera zoom level for the joystick
370+
joystickCamPosition?: [x: number, y: number, z: number]; // camera position for the joystick
371+
joystickBaseProps?: ThreeElements['mesh']; // custom properties for the joystick's base mesh
372+
joystickStickProps?: ThreeElements['mesh']; // custom properties for the joystick's stick mesh
373+
joystickHandleProps?: ThreeElements['mesh']; // custom properties for the joystick's handle mesh
374+
375+
// Touch buttons props
376+
buttonNumber?: number; // Number of buttons (max 5)
377+
buttonPositionRight?: number; // buttons div container position right
378+
buttonPositionBottom?: number; // buttons div container position bottom
379+
buttonHeightAndWidth?: number; // buttons div container height and width
380+
buttonCamZoom?: number; // camera zoom level for the buttons
381+
buttonCamPosition?: [x: number, y: number, z: number]; // camera position for the buttons
382+
buttonGroup1Position?: [x: number, y: number, z: number]; // button 1 posiiton in 3D scene
383+
buttonGroup2Position?: [x: number, y: number, z: number]; // button 2 posiiton in 3D scene
384+
buttonGroup3Position?: [x: number, y: number, z: number]; // button 3 posiiton in 3D scene
385+
buttonGroup4Position?: [x: number, y: number, z: number]; // button 4 posiiton in 3D scene
386+
buttonGroup5Position?: [x: number, y: number, z: number]; // button 5 posiiton in 3D scene
387+
buttonLargeBaseProps?: ThreeElements['mesh']; // custom properties for the buttons' large base mesh
388+
buttonSmallBaseProps?: ThreeElements['mesh']; // custom properties for the buttons' small base mesh
389+
buttonTop1Props?: ThreeElements['mesh']; // custom properties for the button 1 top mesh (large button)
390+
buttonTop2Props?: ThreeElements['mesh']; // custom properties for the button 2 top mesh (large button)
391+
buttonTop3Props?: ThreeElements['mesh']; // custom properties for the button 3 top mesh (small button)
392+
buttonTop4Props?: ThreeElements['mesh']; // custom properties for the button 4 top mesh (small button)
393+
buttonTop5Props?: ThreeElements['mesh']; // custom properties for the button 5 top mesh (small button)
394+
};
395+
```
396+
397+
### Using your own joystick or buttons
398+
399+
If you prefer to use your custom joystick or buttons, you can leverage the `useJoystickControls` hook from `ecctrl`. Import the hook and call the appropriate functions::
400+
401+
```js
402+
import { useJoystickControls } from "ecctrl";
403+
//...
404+
const setJoystick = useJoystickControls((state) => state.setJoystick);
405+
const resetJoystick = useJoystickControls((state) => state.resetJoystick);
406+
const pressButton1 = useJoystickControls((state) => state.pressButton1);
407+
const releaseAllButtons = useJoystickControls(
408+
(state) => state.releaseAllButtons
409+
);
410+
//...
411+
// call the proper fuctions
412+
setJoystick(joystickDis, joystickAng, runState)
413+
// or
414+
pressButton1();
415+
```
416+
309417
## Contributions
310418

311419
I appreciate your interest in this project! If you have any feedback, suggestions, or resources related to the controller, please feel free to share.

0 commit comments

Comments
 (0)