Skip to content

Commit 0590bda

Browse files
author
Sascha Braun
committed
ADD input manager (untested) and behaviours
1 parent bae3513 commit 0590bda

File tree

9 files changed

+364
-4
lines changed

9 files changed

+364
-4
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
"test:unit": "vue-cli-service test:unit"
1010
},
1111
"dependencies": {
12+
"@types/events": "^1.2.0",
1213
"@types/three": "^0.92.24",
14+
"events": "^3.0.0",
1315
"three": "^0.97.0",
1416
"vue": "^2.5.17",
1517
"vue-class-component": "^6.0.0",
@@ -27,8 +29,8 @@
2729
"babel-core": "7.0.0-bridge.0",
2830
"lint-staged": "^7.2.2",
2931
"ts-jest": "^23.0.0",
30-
"typescript": "^3.0.0",
3132
"tslint-config-prettier": "^1.15.0",
33+
"typescript": "^3.0.0",
3234
"vue-template-compiler": "^2.5.17"
3335
},
3436
"browserslist": [

src/views/About.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Component, Vue } from "vue-property-decorator";
33

44
import { components, GeometryFactory, LightFactory, MaterialFactory } from "@/vue-three";
55

6+
import { MyBehaviour } from "./MyBehaviour";
7+
68
console.log(components);
79

810
@Component({
@@ -18,6 +20,8 @@ export default class About extends Vue {
1820

1921
public lightFactory: LightFactory | null = null;
2022

23+
public behaviour = MyBehaviour;
24+
2125
public canvas: HTMLCanvasElement | null = null;
2226

2327
public scene1 = {

src/views/About.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@
2121
<geometry name="plane" :factory="planeFactory"/>
2222
</template>
2323

24+
<behaviour :value="behaviour" :data="{}"/>
25+
2426
<camera name="mainCamera">
2527
<position :value="{x: 0, y: 10, z: 0}"/>
28+
<behaviour :value="behaviour"/>
2629
</camera>
2730

2831
<light name="light" :factory="lightFactory">

src/views/MyBehaviour.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ThreeApplication } from "@/vue-three/core";
2+
import { BehaviourScript } from "@/vue-three/core/BehaviourScript";
3+
4+
export class MyBehaviour extends BehaviourScript {
5+
public onInitialize(app: ThreeApplication, data: any) {
6+
console.log("my behaviour props", app, data);
7+
}
8+
9+
public onUpdate() {
10+
// console.log("my behaviour update");
11+
}
12+
13+
public onDestroy() {
14+
console.log("my behaviour destroy");
15+
}
16+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Component, Inject, Prop, Vue } from "vue-property-decorator";
2+
3+
import { ThreeApplication } from "../../core";
4+
import { BehaviourScript } from "../../core/BehaviourScript";
5+
6+
@Component
7+
export class Behaviour extends Vue {
8+
@Inject()
9+
private app!: () => ThreeApplication;
10+
11+
@Prop({
12+
required: true,
13+
type: Function
14+
})
15+
private value!: { new (): BehaviourScript };
16+
17+
@Prop()
18+
private data!: any;
19+
20+
private m_instance!: BehaviourScript;
21+
22+
public created() {
23+
this.m_instance = new this.value();
24+
const isBehaviourScript = this.m_instance instanceof BehaviourScript;
25+
if (!isBehaviourScript) {
26+
throw new Error(
27+
"Invalid value passed to Behaviour: instance of value is not of type BehaviourScript"
28+
);
29+
}
30+
31+
this.m_instance.onInitialize(this.app(), this.data);
32+
this.app().on("update", this.onUpdate);
33+
}
34+
35+
public onUpdate(deltaTime: number) {
36+
this.m_instance.onUpdate(deltaTime);
37+
}
38+
39+
public beforeDestroy() {
40+
this.app().off("update", this.onUpdate);
41+
this.m_instance.onDestroy();
42+
}
43+
44+
public render(h: any) {
45+
return <div className="behaviour">Behaviour</div>;
46+
}
47+
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export * from "./Position";
22
export * from "./Rotation";
33
export * from "./Scale";
4-
54
export * from "./Shadows";
6-
75
export * from "./Property";
6+
export * from "./Behaviour";

src/vue-three/core/BehaviourScript.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ThreeApplication } from "./ThreeApplication";
2+
3+
export abstract class BehaviourScript {
4+
public onInitialize(app: ThreeApplication, data: any) {}
5+
public onUpdate(deltaTime: number) {}
6+
public onDestroy() {}
7+
}

src/vue-three/core/InputManager.ts

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
const NAVIGATOR_FIREFOX =
2+
navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
3+
4+
export class InputManager {
5+
// creates arrays to store information about the state of
6+
// each of the keys. true if pressed, false otherwise. the
7+
// *previousKeyStates* array is used to store the state of
8+
// the keys during the previous update cycle.
9+
10+
private keyStates: boolean[] = new Array(256);
11+
private previousKeyStates: boolean[] = new Array(256);
12+
private realKeyStates: boolean[] = new Array(256);
13+
14+
// analogous to *keyStates* and *previousKeyStates*
15+
private mouseStates: boolean[] = new Array(3);
16+
private previousMouseStates: boolean[] = new Array(3);
17+
private realMouseStates: boolean[] = new Array(3);
18+
19+
// mouse position
20+
private mousePosition = {
21+
x: 0,
22+
y: 0
23+
};
24+
25+
private lastMousePosition = {
26+
x: 0,
27+
y: 0
28+
};
29+
30+
private realMousePosition = {
31+
x: 0,
32+
y: 0
33+
};
34+
35+
constructor() {
36+
// initializes all the keyStates to their resting
37+
// position - not pressed
38+
for (let i = 0; i < this.keyStates.length; i++) {
39+
this.keyStates[i] = false;
40+
this.previousKeyStates[i] = false;
41+
this.realKeyStates[i] = false;
42+
}
43+
// same as *keyStates* initialization
44+
for (let i = 0; i < this.mouseStates.length; i++) {
45+
this.mouseStates[i] = false;
46+
this.previousMouseStates[i] = false;
47+
this.realMouseStates[i] = false;
48+
}
49+
50+
window.addEventListener("keydown", this.onKeyDown);
51+
window.addEventListener("keyup", this.onKeyUp);
52+
window.addEventListener("mousedown", this.onMouseDown);
53+
window.addEventListener("mouseup", this.onMouseUp);
54+
window.addEventListener("mousemove", this.onMouseMove);
55+
}
56+
57+
private onKeyDown = (e: KeyboardEvent) => {
58+
if (e.which === 18) e.preventDefault();
59+
this.realKeyStates[e.which] = true;
60+
};
61+
private onKeyUp = (e: KeyboardEvent) => {
62+
this.realKeyStates[e.which] = false;
63+
};
64+
private onMouseDown = (e: MouseEvent) => {
65+
this.realMouseStates[e.button] = true;
66+
};
67+
private onMouseUp = (e: MouseEvent) => {
68+
this.realMouseStates[e.button] = false;
69+
};
70+
private onMouseMove = (e: MouseEvent) => {
71+
this.realMousePosition.x = e.clientX;
72+
this.realMousePosition.y = e.clientY;
73+
};
74+
75+
public dispose() {
76+
window.removeEventListener("keydown", this.onKeyDown);
77+
window.removeEventListener("keyup", this.onKeyUp);
78+
window.removeEventListener("mousedown", this.onMouseDown);
79+
window.removeEventListener("mouseup", this.onMouseUp);
80+
window.removeEventListener("mousemove", this.onMouseMove);
81+
}
82+
83+
public isReleased(combo: string) {
84+
return (
85+
!this.checkCombo(combo, this.mouseStates, this.keyStates) &&
86+
this.checkCombo(combo, this.previousMouseStates, this.previousKeyStates)
87+
);
88+
}
89+
90+
public isPressed(combo: string) {
91+
return (
92+
this.checkCombo(combo, this.mouseStates, this.keyStates) &&
93+
!this.checkCombo(combo, this.previousMouseStates, this.previousKeyStates)
94+
);
95+
}
96+
97+
public isDown(combo: string) {
98+
return this.checkCombo(combo, this.mouseStates, this.keyStates);
99+
}
100+
101+
// updates the key and mouse states of the current *pinput* instance.
102+
// the previous key and mouse states are set to the current ones, and
103+
// the current ones are set to reflect the actual state of the keyboard
104+
// and mouse.
105+
public update() {
106+
// set previous keyStates to current keyStates
107+
const tmpKeys = this.previousKeyStates;
108+
this.previousKeyStates = this.keyStates;
109+
this.keyStates = tmpKeys;
110+
111+
// set previous mouseStates to current keyStates
112+
const tmpMouses = this.previousMouseStates;
113+
this.previousMouseStates = this.mouseStates;
114+
this.keyStates = tmpMouses;
115+
116+
// update mouse positions
117+
this.lastMousePosition.x = this.mousePosition.x;
118+
this.lastMousePosition.y = this.mousePosition.y;
119+
this.mousePosition.x = this.realMousePosition.x;
120+
this.mousePosition.y = this.realMousePosition.y;
121+
122+
// update current keyStates
123+
for (let i = 0; i < this.keyStates.length; i++) {
124+
this.keyStates[i] = this.realKeyStates[i];
125+
}
126+
127+
// update current mouseStates
128+
for (let i = 0; i < this.keyStates.length; i++) {
129+
this.mouseStates[i] = this.realMouseStates[i];
130+
}
131+
}
132+
133+
private checkCombo(
134+
combination: string,
135+
mouseStates: boolean[],
136+
keyStates: boolean[]
137+
) {
138+
const combos = this.convertStringToCombo(combination);
139+
140+
for (const combo of combos) {
141+
if (combo[0] === "mouse") {
142+
if (!mouseStates[combo[1]]) {
143+
return false;
144+
}
145+
} else {
146+
if (!keyStates[combo[1]]) {
147+
return false;
148+
}
149+
}
150+
}
151+
return true;
152+
}
153+
154+
// converts a string to a keycode
155+
private convertStringToKeyCode(pKey: string): [string, number] | null {
156+
const key = this.removeWhiteSpace(pKey).toUpperCase();
157+
158+
switch (key) {
159+
case "BACKSPACE":
160+
return ["key", 8];
161+
case "SPACEBAR":
162+
return ["key", 32];
163+
case "TAB":
164+
return ["key", 9];
165+
case "ENTER":
166+
return ["key", 13];
167+
case "SHIFT":
168+
return ["key", 16];
169+
case "CONTROL":
170+
return ["key", 17];
171+
case "ALT":
172+
return ["key", 18];
173+
case "CAPSLOCK":
174+
return ["key", 20];
175+
case "ESCAPE":
176+
return ["key", 27];
177+
case "PAGEUP":
178+
return ["key", 33];
179+
case "PAGEDOWN":
180+
return ["key", 34];
181+
case "ARROWLEFT":
182+
return ["key", 37];
183+
case "ARROWUP":
184+
return ["key", 38];
185+
case "ARROWRIGHT":
186+
return ["key", 38];
187+
case "ARROWDOWN":
188+
return ["key", 40];
189+
case "INSERT":
190+
return ["key", 45];
191+
case "DELETE":
192+
return ["key", 46];
193+
case "+":
194+
return ["key", NAVIGATOR_FIREFOX ? 61 : 187];
195+
case "=":
196+
return ["key", NAVIGATOR_FIREFOX ? 61 : 187];
197+
case "-":
198+
return ["key", NAVIGATOR_FIREFOX ? 173 : 189];
199+
case "[":
200+
return ["key", 219];
201+
case "]":
202+
return ["key", 221];
203+
case "/":
204+
return ["key", 191];
205+
case "\\":
206+
return ["key", 220];
207+
default:
208+
return ["key", key.charCodeAt(0)];
209+
}
210+
}
211+
212+
// same as *convertStringToKeyCombo* but with mouse buttons
213+
private convertStringToButtonCode(
214+
buttonCode: string
215+
): [string, number] | null {
216+
const code = this.removeWhiteSpace(buttonCode).toUpperCase();
217+
switch (code) {
218+
case "MOUSELEFT":
219+
return ["mouse", 0];
220+
case "MOUSEMIDDLE":
221+
return ["mouse", 1];
222+
case "MOUSERIGHT":
223+
return ["mouse", 2];
224+
default:
225+
return null;
226+
}
227+
}
228+
229+
private convertStringToCombo(pCombo: string) {
230+
const combo = this.stripWhiteSpace(pCombo);
231+
const tokens = combo.split(" ");
232+
const keysAndButtons = [];
233+
234+
for (const token of tokens) {
235+
const code = this.convertStringToButtonCode(token);
236+
237+
if (code != null) {
238+
keysAndButtons.push(code);
239+
} else {
240+
const keyCode = this.convertStringToKeyCode(token);
241+
if (!keyCode) {
242+
throw new Error(
243+
`Invalid combo "${pCombo}" specified: "${token}" not found`
244+
);
245+
}
246+
keysAndButtons.push(keyCode);
247+
}
248+
}
249+
250+
return keysAndButtons;
251+
}
252+
253+
// removes all whitespace from a given string.
254+
private removeWhiteSpace(input: string) {
255+
return input.replace(/\s+/, "");
256+
}
257+
258+
// replaces all consecutive instances of whitespace in a given string with one space.
259+
private stripWhiteSpace(input: string) {
260+
return input.replace(/\s+/, " ");
261+
}
262+
}

0 commit comments

Comments
 (0)