@shadowdara/webgameengine 1.0.0 → 1.2.0
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/README.md +8 -21
- package/dist/build/tools/devserver/cli.js +54 -16
- package/dist/build/tools/devserver/new.d.ts +1 -0
- package/dist/build/tools/devserver/new.js +156 -0
- package/dist/renderer.d.ts +1 -1
- package/dist/texture.js +1 -1
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.js +9 -2
- package/dist/types/rectangle.d.ts +2 -2
- package/dist/types/vector2d.d.ts +1 -0
- package/dist/types/vector2d.js +8 -1
- package/dist/types/vector3d.d.ts +1 -0
- package/dist/types/vector3d.js +11 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
# WebGameEngine 🎮
|
|
2
2
|
|
|
3
|
-
**(Currently trying to make this into a lib)**
|
|
4
|
-
|
|
5
|
-
**Use `bun tools/build.ts`**
|
|
6
|
-
|
|
7
3
|
A lightweight, TypeScript-first web game engine framework for building 2D games.
|
|
8
4
|
|
|
9
5
|
## Features
|
|
@@ -19,14 +15,7 @@ A lightweight, TypeScript-first web game engine framework for building 2D games.
|
|
|
19
15
|
## Installation
|
|
20
16
|
|
|
21
17
|
```bash
|
|
22
|
-
npm install @
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Or use directly from source:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
bun install
|
|
29
|
-
bun run dev
|
|
18
|
+
npm install @shadowdara/webgameengine
|
|
30
19
|
```
|
|
31
20
|
|
|
32
21
|
## Quick Start
|
|
@@ -34,7 +23,7 @@ bun run dev
|
|
|
34
23
|
### Basic Game Loop
|
|
35
24
|
|
|
36
25
|
```typescript
|
|
37
|
-
import { startEngine, setupInput, dlog, renderText } from '@
|
|
26
|
+
import { startEngine, setupInput, dlog, renderText } from '@shadowdara/webgameengine';
|
|
38
27
|
|
|
39
28
|
const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;
|
|
40
29
|
const ctx = canvas.getContext('2d')!;
|
|
@@ -62,19 +51,17 @@ startEngine(init, gameLoop);
|
|
|
62
51
|
### Using Bun (local development)
|
|
63
52
|
|
|
64
53
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
54
|
+
npx webgameengine # Start Dev Server
|
|
55
|
+
npx webgameengine --release # Production build
|
|
56
|
+
npx webgameengine --new # Create a new project with a simple Snake Clone as Template
|
|
70
57
|
```
|
|
71
58
|
|
|
72
59
|
### Configuration
|
|
73
60
|
|
|
74
|
-
Edit `
|
|
61
|
+
Edit `webgameengine.config.ts` to configure your game:
|
|
75
62
|
|
|
76
63
|
```typescript
|
|
77
|
-
import { defineConfig } from '
|
|
64
|
+
import { defineConfig } from '@shadowdara/webgameengine/build';
|
|
78
65
|
|
|
79
66
|
export function defineConfig() {
|
|
80
67
|
return {
|
|
@@ -90,7 +77,7 @@ or
|
|
|
90
77
|
```typescript
|
|
91
78
|
// Project File for the Game
|
|
92
79
|
|
|
93
|
-
import { type buildconfig, new_buildconfig } from "
|
|
80
|
+
import { type buildconfig, new_buildconfig } from "@shadowdara/webgameengine/build";
|
|
94
81
|
|
|
95
82
|
export function defineConfig(): buildconfig {
|
|
96
83
|
let config: buildconfig = new_buildconfig();
|
|
@@ -1,28 +1,66 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Shebang
|
|
3
2
|
import { build as esbuild } from "esbuild";
|
|
4
|
-
import { copyFolder, flog, getContentType } from "../../buildhelper.js";
|
|
5
|
-
import { GetDefaultHTML } from "../../exporthtml.js";
|
|
6
3
|
import { createServer } from "http";
|
|
7
4
|
import { readFile, writeFile } from "fs/promises";
|
|
8
5
|
import { watch } from "fs";
|
|
9
6
|
import path from "path";
|
|
10
7
|
import { WebSocketServer } from "ws";
|
|
8
|
+
import { createProject } from "./new.js";
|
|
9
|
+
import { copyFolder, flog, getContentType } from "../../buildhelper.js";
|
|
10
|
+
import { GetDefaultHTML } from "../../exporthtml.js";
|
|
11
11
|
import { loadUserConfig } from "./config.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
12
|
+
// ================= ARG PARSING =================
|
|
13
|
+
function parseArgs() {
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
const options = {
|
|
16
|
+
release: false,
|
|
17
|
+
port: 3000,
|
|
18
|
+
newProject: null,
|
|
19
|
+
};
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
switch (arg) {
|
|
23
|
+
case "--release":
|
|
24
|
+
case "-r":
|
|
25
|
+
options.release = true;
|
|
26
|
+
break;
|
|
27
|
+
case "--port":
|
|
28
|
+
case "-p":
|
|
29
|
+
options.port = Number(args[i + 1]);
|
|
30
|
+
i++;
|
|
31
|
+
break;
|
|
32
|
+
case "--new":
|
|
33
|
+
case "-n":
|
|
34
|
+
options.newProject = args[i + 1];
|
|
35
|
+
i++;
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
console.warn(`⚠️ Unbekanntes Argument: ${arg}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return options;
|
|
42
|
+
}
|
|
43
|
+
const args = parseArgs();
|
|
44
|
+
// Falls --new → sofort ausführen und beenden
|
|
45
|
+
if (args.newProject) {
|
|
46
|
+
await createProject(args.newProject);
|
|
47
|
+
// and make exit afterwards
|
|
48
|
+
}
|
|
49
|
+
// ================= FLAGS =================
|
|
50
|
+
const isRelease = args.release;
|
|
16
51
|
const isDev = !isRelease;
|
|
52
|
+
// ================= CONFIG =================
|
|
53
|
+
const config = await loadUserConfig();
|
|
17
54
|
// ================= BUILD =================
|
|
18
|
-
|
|
55
|
+
let isBuilding = false;
|
|
56
|
+
async function build() {
|
|
19
57
|
if (isBuilding)
|
|
20
58
|
return;
|
|
21
59
|
isBuilding = true;
|
|
22
60
|
flog("🔄 Baue neu...");
|
|
23
61
|
await esbuild({
|
|
24
|
-
entryPoints: [
|
|
25
|
-
outdir:
|
|
62
|
+
entryPoints: [`./game/${config.entryname}`],
|
|
63
|
+
outdir: `./${config.outdir}`,
|
|
26
64
|
bundle: true,
|
|
27
65
|
platform: "browser",
|
|
28
66
|
minify: isRelease,
|
|
@@ -41,8 +79,8 @@ async function build(config) {
|
|
|
41
79
|
let sockets = new Set();
|
|
42
80
|
function startServer() {
|
|
43
81
|
const server = createServer(async (req, res) => {
|
|
44
|
-
|
|
45
|
-
|
|
82
|
+
const url = req.url || "/";
|
|
83
|
+
const filePath = url === "/" ? "/index.html" : url;
|
|
46
84
|
try {
|
|
47
85
|
const fullPath = path.join(process.cwd(), "dist", filePath);
|
|
48
86
|
const file = await readFile(fullPath);
|
|
@@ -61,8 +99,8 @@ function startServer() {
|
|
|
61
99
|
sockets.add(ws);
|
|
62
100
|
ws.on("close", () => sockets.delete(ws));
|
|
63
101
|
});
|
|
64
|
-
server.listen(
|
|
65
|
-
flog(
|
|
102
|
+
server.listen(args.port, () => {
|
|
103
|
+
flog(`🚀 Dev Server läuft auf http://localhost:${args.port}`);
|
|
66
104
|
});
|
|
67
105
|
return server;
|
|
68
106
|
}
|
|
@@ -85,13 +123,13 @@ async function restart() {
|
|
|
85
123
|
do {
|
|
86
124
|
pendingRestart = false;
|
|
87
125
|
flog("♻️ Restart...");
|
|
88
|
-
await build(
|
|
126
|
+
await build();
|
|
89
127
|
reloadClients();
|
|
90
128
|
} while (pendingRestart);
|
|
91
129
|
restarting = false;
|
|
92
130
|
}
|
|
93
131
|
// ================= START =================
|
|
94
|
-
await build(
|
|
132
|
+
await build();
|
|
95
133
|
if (isDev) {
|
|
96
134
|
startServer();
|
|
97
135
|
["resources", "game"].forEach((dir) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createProject(name: string): Promise<void>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { writeFile, mkdir } from "fs/promises";
|
|
3
|
+
import { flog } from "../../buildhelper.js";
|
|
4
|
+
// ================= NEW PROJECT =================
|
|
5
|
+
export async function createProject(name) {
|
|
6
|
+
const base = path.resolve(name);
|
|
7
|
+
flog(`📦 Erstelle neues Projekt: ${name}`);
|
|
8
|
+
await mkdir(base, { recursive: true });
|
|
9
|
+
await mkdir(path.join(base, "game"), { recursive: true });
|
|
10
|
+
await mkdir(path.join(base, "resources"), { recursive: true });
|
|
11
|
+
await mkdir(path.join(base, "dist"), { recursive: true });
|
|
12
|
+
// Basic game entry
|
|
13
|
+
await writeFile(path.join(base, "game", "main.ts"), `
|
|
14
|
+
// A mini Snake Clone with my Webframework
|
|
15
|
+
|
|
16
|
+
import { createCanvas } from "@shadowdara/webgameengine";
|
|
17
|
+
import { setupInput, isKeyJustPressed, resetInput } from "@shadowdara/webgameengine";
|
|
18
|
+
import { startEngine } from "@shadowdara/webgameengine";
|
|
19
|
+
import { renderText } from "@shadowdara/webgameengine";
|
|
20
|
+
import { Vector2d } from "@shadowdara/webgameengine/types";
|
|
21
|
+
import { dlog } from "@shadowdara/webgameengine";
|
|
22
|
+
import { Key } from "@shadowdara/webgameengine";
|
|
23
|
+
|
|
24
|
+
const { canvas, ctx } = createCanvas({fullscreen: true, scaling: "fit", virtualWidth: window.innerWidth, virtualHeight: window.innerHeight});
|
|
25
|
+
setupInput(canvas);
|
|
26
|
+
|
|
27
|
+
let snake: Vector2d[] = [{ x: 10, y: 10 }];
|
|
28
|
+
let dir: Vector2d = { x: 1, y: 0 };
|
|
29
|
+
let food: Vector2d = { x: 15, y: 10 };
|
|
30
|
+
let gridSize = 20;
|
|
31
|
+
let lastMove = 0;
|
|
32
|
+
let speed = 0.2; // seconds per cell
|
|
33
|
+
let start = false;
|
|
34
|
+
|
|
35
|
+
function gameStart() {
|
|
36
|
+
dlog("Snake gestartet");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function gameLoop(dt: number) {
|
|
40
|
+
if (isKeyJustPressed(Key.Escape)) {
|
|
41
|
+
start = !start
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!start) {
|
|
45
|
+
ctx.fillStyle = "white";
|
|
46
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
47
|
+
|
|
48
|
+
renderText(ctx, "Snake", 10, 10, "black", "24px Arial");
|
|
49
|
+
renderText(ctx, "Press ESC to start or Pause the Game!", 10, 50, "black", "24px Arial");
|
|
50
|
+
|
|
51
|
+
// return;
|
|
52
|
+
} else {
|
|
53
|
+
|
|
54
|
+
// Input
|
|
55
|
+
if (isKeyJustPressed(Key.ArrowUp) && dir.y === 0) dir = { x: 0, y: -1 };
|
|
56
|
+
if (isKeyJustPressed(Key.ArrowDown) && dir.y === 0) dir = { x: 0, y: 1 };
|
|
57
|
+
if (isKeyJustPressed(Key.ArrowLeft) && dir.x === 0) dir = { x: -1, y: 0 };
|
|
58
|
+
if (isKeyJustPressed(Key.ArrowRight) && dir.x === 0) dir = { x: 1, y: 0 };
|
|
59
|
+
|
|
60
|
+
lastMove += dt;
|
|
61
|
+
|
|
62
|
+
if (lastMove >= speed) {
|
|
63
|
+
lastMove = 0;
|
|
64
|
+
const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
|
|
65
|
+
|
|
66
|
+
// Kollision mit Walls
|
|
67
|
+
if (head.x < 0 || head.y < 0 || head.x >= canvas.width / gridSize || head.y >= canvas.height / gridSize) {
|
|
68
|
+
snake = [{ x: 10, y: 10 }];
|
|
69
|
+
dir = { x: 1, y: 0 };
|
|
70
|
+
dlog("Game Over");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Kollision mit sich selbst
|
|
75
|
+
if (snake.some(s => s.x === head.x && s.y === head.y)) {
|
|
76
|
+
snake = [{ x: 10, y: 10 }];
|
|
77
|
+
dir = { x: 1, y: 0 };
|
|
78
|
+
dlog(\`Game Over! Highscore: \${snake.length - 1}\`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
snake.unshift(head);
|
|
83
|
+
|
|
84
|
+
// Food Check
|
|
85
|
+
if (head.x === food.x && head.y === food.y) {
|
|
86
|
+
food = { x: Math.floor(Math.random() * (canvas.width / gridSize)), y: Math.floor(Math.random() * (canvas.height / gridSize)) };
|
|
87
|
+
} else {
|
|
88
|
+
snake.pop();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Zeichnen
|
|
93
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
94
|
+
|
|
95
|
+
ctx.fillStyle = "black";
|
|
96
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
97
|
+
|
|
98
|
+
ctx.fillStyle = "green";
|
|
99
|
+
snake.forEach(s => ctx.fillRect(s.x * gridSize, s.y * gridSize, gridSize, gridSize));
|
|
100
|
+
|
|
101
|
+
ctx.fillStyle = "red";
|
|
102
|
+
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize);
|
|
103
|
+
|
|
104
|
+
renderText(ctx, "Score: " + (snake.length - 1), 10, 10, "yellow", "24px Arial");
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Reset Input
|
|
109
|
+
resetInput();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
startEngine(gameStart, gameLoop);
|
|
113
|
+
`);
|
|
114
|
+
// Config
|
|
115
|
+
await writeFile(path.join(base, "webgameengine.config.js"), `
|
|
116
|
+
// Project File for the Game
|
|
117
|
+
|
|
118
|
+
import type { buildconfig } from "@shadowdara/webgameengine/build";
|
|
119
|
+
import { new_buildconfig } from "@shadowdara/webgameengine/build";
|
|
120
|
+
|
|
121
|
+
export default function defineConfig(): buildconfig {
|
|
122
|
+
let config: buildconfig = new_buildconfig();
|
|
123
|
+
return config;
|
|
124
|
+
}
|
|
125
|
+
`);
|
|
126
|
+
// package.json
|
|
127
|
+
// await writeFile(
|
|
128
|
+
// path.join(base, "package.json"),
|
|
129
|
+
// JSON.stringify(
|
|
130
|
+
// {
|
|
131
|
+
// name,
|
|
132
|
+
// version: "1.0.0",
|
|
133
|
+
// type: "module",
|
|
134
|
+
// scripts: {
|
|
135
|
+
// dev: "mycli",
|
|
136
|
+
// build: "mycli --release",
|
|
137
|
+
// },
|
|
138
|
+
// },
|
|
139
|
+
// null,
|
|
140
|
+
// 2
|
|
141
|
+
// )
|
|
142
|
+
// );
|
|
143
|
+
flog("✅ Projekt created!");
|
|
144
|
+
// flog(`👉 cd ${name}`);
|
|
145
|
+
// flog(`👉 npm install`);
|
|
146
|
+
// flog(`👉 npm run dev`);
|
|
147
|
+
console.log(`Add to your package.json file:
|
|
148
|
+
"scripts": {
|
|
149
|
+
"dev": "npx webgameengine",
|
|
150
|
+
"build": "npx webgameengine --release"
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
Run "npm run dev" to start the Dev Server and play a little Snake Clone
|
|
154
|
+
`);
|
|
155
|
+
process.exit(0);
|
|
156
|
+
}
|
package/dist/renderer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Rect } from "./types/rectangle";
|
|
1
|
+
import { type Rect } from "./types/rectangle.js";
|
|
2
2
|
export declare function renderText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, color?: string, font?: string): void;
|
|
3
3
|
type CharMap = Record<string, Rect>;
|
|
4
4
|
export declare function renderBitmapText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, sprite: HTMLImageElement, charMap: CharMap, scale?: number): void;
|
package/dist/texture.js
CHANGED
package/dist/types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
5
|
-
export {
|
|
1
|
+
export { type Vector2d, normalize2d, clamp2d, lerp2d, map2d } from "./vector2d.js";
|
|
2
|
+
export { type Vector3d, normalize3d, clamp3d, lerp3d, map3d } from "./vector3d.js";
|
|
3
|
+
export { type Color, invertcolor, invertHexColor } from "./color.js";
|
|
4
|
+
export { type Rect, centerRectX, centerRectY, centerRect, isPointInRect, isMouseInRect, isRectClicked } from "./rectangle.js";
|
|
5
|
+
export { clamp, lerp, map } from "./math-utils.js";
|
package/dist/types/index.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
// Types Export
|
|
2
|
-
|
|
2
|
+
// Vector 2D
|
|
3
|
+
export { normalize2d, clamp2d, lerp2d, map2d } from "./vector2d.js";
|
|
4
|
+
// Vector 3D
|
|
5
|
+
export { normalize3d, clamp3d, lerp3d, map3d } from "./vector3d.js";
|
|
6
|
+
// Color Type
|
|
7
|
+
export { invertcolor, invertHexColor } from "./color.js";
|
|
8
|
+
// Retangle Type
|
|
9
|
+
export { centerRectX, centerRectY, centerRect, isPointInRect, isMouseInRect, isRectClicked } from "./rectangle.js";
|
|
3
10
|
// Math Utilities
|
|
4
|
-
|
|
11
|
+
export { clamp, lerp, map } from "./math-utils.js";
|
package/dist/types/vector2d.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export type Vector2d = {
|
|
|
5
5
|
export declare function normalize2d(vector: Vector2d): Vector2d;
|
|
6
6
|
export declare function clamp2d(vector: Vector2d, min: Vector2d, max: Vector2d): Vector2d;
|
|
7
7
|
export declare function lerp2d(start: Vector2d, end: Vector2d, t: Vector2d): Vector2d;
|
|
8
|
+
export declare function map2d(value: Vector2d, inMin: Vector2d, inMax: Vector2d, outMin: Vector2d, outMax: Vector2d): Vector2d;
|
package/dist/types/vector2d.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// 2 Dimensional Vector Type
|
|
2
|
-
import { clamp, lerp } from "./math-utils";
|
|
2
|
+
import { clamp, lerp, map } from "./math-utils.js";
|
|
3
3
|
// Function to normalize a Vector 2d
|
|
4
4
|
export function normalize2d(vector) {
|
|
5
5
|
// Check if the Vector is zero because then you dont need to
|
|
@@ -27,3 +27,10 @@ export function lerp2d(start, end, t) {
|
|
|
27
27
|
y: lerp(start.y, end.y, t.y),
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
// Map Function for a 2d Vector
|
|
31
|
+
export function map2d(value, inMin, inMax, outMin, outMax) {
|
|
32
|
+
return {
|
|
33
|
+
x: map(value.x, inMin.x, inMax.x, outMin.x, outMax.x),
|
|
34
|
+
y: map(value.y, inMin.y, inMax.y, outMin.y, outMax.y),
|
|
35
|
+
};
|
|
36
|
+
}
|
package/dist/types/vector3d.d.ts
CHANGED
|
@@ -6,3 +6,4 @@ export type Vector3d = {
|
|
|
6
6
|
export declare function normalize3d(vector: Vector3d): Vector3d;
|
|
7
7
|
export declare function clamp3d(vector: Vector3d, min: Vector3d, max: Vector3d): Vector3d;
|
|
8
8
|
export declare function lerp3d(start: Vector3d, end: Vector3d, t: Vector3d): Vector3d;
|
|
9
|
+
export declare function map3d(value: Vector3d, inMin: Vector3d, inMax: Vector3d, outMin: Vector3d, outMax: Vector3d): Vector3d;
|
package/dist/types/vector3d.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// 3d Vector
|
|
2
|
-
import { clamp, lerp } from "./math-utils";
|
|
2
|
+
import { clamp, lerp, map } from "./math-utils.js";
|
|
3
3
|
// Function to normalize a Vector 2d
|
|
4
4
|
export function normalize3d(vector) {
|
|
5
5
|
// Check if the Vector is zero because then you dont need to
|
|
@@ -14,7 +14,7 @@ export function normalize3d(vector) {
|
|
|
14
14
|
vector.z = vector.z / root;
|
|
15
15
|
return vector;
|
|
16
16
|
}
|
|
17
|
-
// Function to clamp a Vector
|
|
17
|
+
// Function to clamp a Vector 3d
|
|
18
18
|
export function clamp3d(vector, min, max) {
|
|
19
19
|
return {
|
|
20
20
|
x: clamp(vector.x, min.x, max.x),
|
|
@@ -22,7 +22,7 @@ export function clamp3d(vector, min, max) {
|
|
|
22
22
|
z: clamp(vector.y, min.y, max.y),
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
-
// Lerp for a
|
|
25
|
+
// Lerp for a 3d Vector
|
|
26
26
|
export function lerp3d(start, end, t) {
|
|
27
27
|
return {
|
|
28
28
|
x: lerp(start.x, end.x, t.x),
|
|
@@ -30,3 +30,11 @@ export function lerp3d(start, end, t) {
|
|
|
30
30
|
z: lerp(start.y, end.y, t.y),
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
// Map Function for a 3d Vector
|
|
34
|
+
export function map3d(value, inMin, inMax, outMin, outMax) {
|
|
35
|
+
return {
|
|
36
|
+
x: map(value.x, inMin.x, inMax.x, outMin.x, outMax.x),
|
|
37
|
+
y: map(value.y, inMin.y, inMax.y, outMin.y, outMax.y),
|
|
38
|
+
z: map(value.z, inMin.z, inMax.z, outMin.z, outMax.z),
|
|
39
|
+
};
|
|
40
|
+
}
|