forked from carzygod/ISAAC-CLONE
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.ts
More file actions
128 lines (103 loc) · 3.19 KB
/
utils.ts
File metadata and controls
128 lines (103 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { Vector2, Rect, KeyMap } from './types';
import { DEFAULT_KEYMAP } from './constants';
export const uuid = () => Math.random().toString(36).substr(2, 9);
export const checkAABB = (r1: Rect, r2: Rect): boolean => {
return (
r1.x < r2.x + r2.w &&
r1.x + r1.w > r2.x &&
r1.y < r2.y + r2.h &&
r1.y + r1.h > r2.y
);
};
export const normalizeVector = (v: Vector2): Vector2 => {
const mag = Math.sqrt(v.x * v.x + v.y * v.y);
if (mag === 0) return { x: 0, y: 0 };
return { x: v.x / mag, y: v.y / mag };
};
export const distance = (a: Vector2, b: Vector2): number => {
return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
};
export class SeededRNG {
seed: number;
constructor(seed: number) {
this.seed = seed;
}
// Simple Linear Congruential Generator
next(): number {
this.seed = (this.seed * 9301 + 49297) % 233280;
return this.seed / 233280;
}
// Range inclusive [min, max]
range(min: number, max: number): number {
return min + this.next() * (max - min);
}
// Integer Range inclusive [min, max]
rangeInt(min: number, max: number): number {
return Math.floor(this.range(min, max + 1));
}
// Generic Weighted Random Selection
weightedChoice<T extends { weight: number }>(items: T[]): T | null {
if (items.length === 0) return null;
const totalWeight = items.reduce((sum, item) => sum + item.weight, 0);
let randomVal = this.next() * totalWeight;
for (const item of items) {
if (randomVal < item.weight) {
return item;
}
randomVal -= item.weight;
}
return items[items.length - 1];
}
}
export class InputManager {
keys: { [key: string]: boolean } = {};
keyMap: KeyMap;
constructor(initialKeyMap?: KeyMap) {
this.keyMap = initialKeyMap || DEFAULT_KEYMAP;
window.addEventListener('keydown', this.onKeyDown);
window.addEventListener('keyup', this.onKeyUp);
}
updateKeyMap(newMap: KeyMap) {
this.keyMap = newMap;
}
destroy() {
window.removeEventListener('keydown', this.onKeyDown);
window.removeEventListener('keyup', this.onKeyUp);
}
onKeyDown = (e: KeyboardEvent) => {
this.keys[e.code] = true;
};
onKeyUp = (e: KeyboardEvent) => {
this.keys[e.code] = false;
};
getMovementVector(): Vector2 {
const v = { x: 0, y: 0 };
if (this.keys[this.keyMap.moveUp]) v.y -= 1;
if (this.keys[this.keyMap.moveDown]) v.y += 1;
if (this.keys[this.keyMap.moveLeft]) v.x -= 1;
if (this.keys[this.keyMap.moveRight]) v.x += 1;
return normalizeVector(v);
}
getShootingDirection(): Vector2 | null {
let x = 0;
let y = 0;
if (this.keys[this.keyMap.shootUp]) y -= 1;
if (this.keys[this.keyMap.shootDown]) y += 1;
if (this.keys[this.keyMap.shootLeft]) x -= 1;
if (this.keys[this.keyMap.shootRight]) x += 1;
if (x === 0 && y === 0) return null;
// Enforce 4-way shooting
if (Math.abs(x) >= Math.abs(y)) {
y = 0;
} else {
x = 0;
}
return normalizeVector({x, y});
}
isRestartPressed(): boolean {
return !!this.keys[this.keyMap.restart];
}
isPausePressed(): boolean {
return !!this.keys[this.keyMap.pause];
}
}