nova64 0.2.5 → 0.2.7
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 +25 -8
- package/bin/nova64.js +165 -0
- package/dist/assets/console-CY_kygm3.js +14 -0
- package/dist/assets/console-CY_kygm3.js.map +1 -0
- package/dist/assets/main-l0sNRNKZ.js.map +1 -0
- package/dist/assets/sky/studio/nx.png +0 -0
- package/dist/assets/sky/studio/ny.png +0 -0
- package/dist/assets/sky/studio/nz.png +0 -0
- package/dist/assets/sky/studio/px.png +0 -0
- package/dist/assets/sky/studio/py.png +0 -0
- package/dist/assets/sky/studio/pz.png +0 -0
- package/dist/assets/vanilla-Dcuy32gi.js +2 -0
- package/dist/assets/vanilla-Dcuy32gi.js.map +1 -0
- package/dist/console.html +899 -0
- package/dist/docs/BENCHMARK.md +77 -0
- package/dist/docs/CHEATSHEET.md +255 -0
- package/dist/docs/EFFECTS_API_GUIDE.md +577 -0
- package/dist/docs/EFFECTS_QUICK_REFERENCE.md +331 -0
- package/dist/docs/FONT_CHARACTER_REFERENCE.md +219 -0
- package/dist/docs/FREE_GLB_ASSETS.md +330 -0
- package/dist/docs/FULLSCREEN_BUTTON_FEATURE.md +296 -0
- package/dist/docs/GAMEPAD_SUPPORT.md +348 -0
- package/dist/docs/GAME_IMPROVEMENTS.md +278 -0
- package/dist/docs/GAME_QUALITY_STATUS.md +300 -0
- package/dist/docs/MIGRATION_GUIDE.md +553 -0
- package/dist/docs/NOVA64_3D_API.md +356 -0
- package/dist/docs/NOVA64_API_REFERENCE.md +1406 -0
- package/dist/docs/NOVA64_UI_API.md +503 -0
- package/dist/docs/UI_SYSTEM_SUMMARY.md +445 -0
- package/dist/docs/VOXEL_ENGINE_GUIDE.md +662 -0
- package/dist/docs/VOXEL_QUICK_REFERENCE.md +386 -0
- package/dist/docs/api-3d.html +750 -0
- package/dist/docs/api-effects.html +385 -0
- package/dist/docs/api-improvements.md +121 -0
- package/dist/docs/api-skybox.html +407 -0
- package/dist/docs/api-sprites.html +321 -0
- package/dist/docs/api-voxel.html +337 -0
- package/dist/docs/api.html +543 -0
- package/dist/docs/assets.html +306 -0
- package/dist/docs/audio.html +340 -0
- package/dist/docs/blogs.html +286 -0
- package/dist/docs/collision.html +316 -0
- package/dist/docs/console.html +247 -0
- package/dist/docs/editor.html +297 -0
- package/dist/docs/font.html +247 -0
- package/dist/docs/framebuffer.html +247 -0
- package/dist/docs/fullscreen-button.html +297 -0
- package/dist/docs/gpu-systems.html +247 -0
- package/dist/docs/index.html +580 -0
- package/dist/docs/input.html +491 -0
- package/dist/docs/physics.html +311 -0
- package/dist/docs/screens.html +311 -0
- package/dist/docs/storage.html +311 -0
- package/dist/docs/textinput.html +332 -0
- package/dist/docs/ui.html +488 -0
- package/dist/examples/3d-advanced/code.js +695 -0
- package/dist/examples/adventure-comic-3d/code.js +342 -0
- package/dist/examples/audio-lab/code.js +150 -0
- package/dist/examples/boids-flocking/code.js +270 -0
- package/dist/examples/crystal-cathedral-3d/code.js +706 -0
- package/dist/examples/cyberpunk-city-3d/code.js +1383 -0
- package/dist/examples/demoscene/README.md +192 -0
- package/dist/examples/demoscene/code.js +1081 -0
- package/dist/examples/demoscene/meta.json +21 -0
- package/dist/examples/dungeon-crawler-3d/code.js +1117 -0
- package/dist/examples/f-zero-nova-3d/code.js +865 -0
- package/dist/examples/f-zero-nova-3d/code_old.js +1555 -0
- package/dist/examples/fps-demo-3d/code.js +744 -0
- package/dist/examples/game-of-life-3d/code.js +338 -0
- package/dist/examples/generative-art/code.js +632 -0
- package/dist/examples/hello-3d/code.js +325 -0
- package/dist/examples/hello-skybox/code.js +183 -0
- package/dist/examples/hello-world/code.js +19 -0
- package/dist/examples/input-showcase/code.js +109 -0
- package/dist/examples/instancing-demo/code.js +315 -0
- package/dist/examples/minecraft-demo/code.js +387 -0
- package/dist/examples/model-viewer-3d/code.js +114 -0
- package/dist/examples/mystical-realm-3d/code.js +1203 -0
- package/dist/examples/nature-explorer-3d/code.js +1318 -0
- package/dist/examples/particles-demo/code.js +522 -0
- package/dist/examples/pbr-showcase/code.js +140 -0
- package/dist/examples/physics-demo-3d/code.js +948 -0
- package/dist/examples/screen-demo/code.js +267 -0
- package/dist/examples/shooter-demo-3d/code.js +1286 -0
- package/dist/examples/space-combat-3d/IMPLEMENTATION_SUMMARY.md +109 -0
- package/dist/examples/space-combat-3d/README.md +135 -0
- package/dist/examples/space-combat-3d/code.js +1332 -0
- package/dist/examples/space-harrier-3d/code.js +923 -0
- package/dist/examples/star-fox-nova-3d/code.js +1116 -0
- package/dist/examples/star-fox-nova-3d/code_backup.js +410 -0
- package/dist/examples/star-fox-nova-3d/code_broken.js +1821 -0
- package/dist/examples/storage-quest/code.js +209 -0
- package/dist/examples/strider-demo-3d/IMPROVEMENT_OPTIONS.md +285 -0
- package/dist/examples/strider-demo-3d/cache-test.html +132 -0
- package/dist/examples/strider-demo-3d/code-fixed.js +582 -0
- package/dist/examples/strider-demo-3d/code-old.js +1537 -0
- package/dist/examples/strider-demo-3d/code.js +1462 -0
- package/dist/examples/strider-demo-3d/code.js.bak2 +1169 -0
- package/dist/examples/strider-demo-3d/fix-game.sh +53 -0
- package/dist/examples/super-plumber-64/README.md +128 -0
- package/dist/examples/super-plumber-64/code.js +1185 -0
- package/dist/examples/super-plumber-64/index.html +88 -0
- package/dist/examples/test-2d-overlay/code.js +32 -0
- package/dist/examples/test-font/code.js +51 -0
- package/dist/examples/test-minimal/code.js +21 -0
- package/dist/examples/ui-demo/code.js +306 -0
- package/dist/examples/wing-commander-space/README.md +180 -0
- package/dist/examples/wing-commander-space/code.js +1285 -0
- package/dist/examples/wizardry-3d/CHANGELOG.md +366 -0
- package/dist/examples/wizardry-3d/code.js +3928 -0
- package/dist/index.html +666 -0
- package/dist/os9-shell/assets/index-DIHfrTaW.css +1 -0
- package/dist/os9-shell/assets/index-KchE_ngx.js +483 -0
- package/dist/os9-shell/assets/index-KchE_ngx.js.map +1 -0
- package/dist/os9-shell/index.html +23 -0
- package/dist/os9-shell/nova-icon.svg +12 -0
- package/dist/runtime/api-2d.js +1158 -0
- package/dist/runtime/api-3d/camera.js +73 -0
- package/dist/runtime/api-3d/instancing.js +180 -0
- package/dist/runtime/api-3d/lights.js +51 -0
- package/dist/runtime/api-3d/materials.js +47 -0
- package/dist/runtime/api-3d/models.js +84 -0
- package/dist/runtime/api-3d/particles.js +296 -0
- package/dist/runtime/api-3d/pbr.js +113 -0
- package/dist/runtime/api-3d/primitives.js +304 -0
- package/dist/runtime/api-3d/scene.js +169 -0
- package/dist/runtime/api-3d/transforms.js +161 -0
- package/dist/runtime/api-3d.js +166 -0
- package/dist/runtime/api-effects.js +840 -0
- package/dist/runtime/api-gameutils.js +476 -0
- package/dist/runtime/api-generative.js +610 -0
- package/dist/runtime/api-presets.js +85 -0
- package/dist/runtime/api-skybox.js +232 -0
- package/dist/runtime/api-sprites.js +100 -0
- package/dist/runtime/api-voxel.js +712 -0
- package/dist/runtime/api.js +201 -0
- package/dist/runtime/assets.js +27 -0
- package/dist/runtime/audio.js +114 -0
- package/dist/runtime/collision.js +47 -0
- package/dist/runtime/console.js +101 -0
- package/dist/runtime/editor.js +233 -0
- package/dist/runtime/font.js +233 -0
- package/dist/runtime/framebuffer.js +28 -0
- package/dist/runtime/fullscreen-button.js +185 -0
- package/dist/runtime/gpu-canvas2d.js +47 -0
- package/dist/runtime/gpu-threejs.js +643 -0
- package/dist/runtime/gpu-webgl2.js +310 -0
- package/dist/runtime/index.d.ts +682 -0
- package/dist/runtime/index.js +22 -0
- package/dist/runtime/input.js +225 -0
- package/dist/runtime/logger.js +60 -0
- package/dist/runtime/physics.js +101 -0
- package/dist/runtime/screens.js +213 -0
- package/dist/runtime/storage.js +38 -0
- package/dist/runtime/store.js +151 -0
- package/dist/runtime/textinput.js +68 -0
- package/dist/runtime/ui/buttons.js +124 -0
- package/dist/runtime/ui/panels.js +105 -0
- package/dist/runtime/ui/text.js +86 -0
- package/dist/runtime/ui/widgets.js +141 -0
- package/dist/runtime/ui.js +111 -0
- package/index.html +6 -1
- package/package.json +9 -2
- package/public/assets/sky/studio/nx.png +0 -0
- package/public/assets/sky/studio/ny.png +0 -0
- package/public/assets/sky/studio/nz.png +0 -0
- package/public/assets/sky/studio/px.png +0 -0
- package/public/assets/sky/studio/py.png +0 -0
- package/public/assets/sky/studio/pz.png +0 -0
- package/public/os9-shell/assets/index-KchE_ngx.js +483 -0
- package/public/os9-shell/assets/index-KchE_ngx.js.map +1 -0
- package/public/os9-shell/index.html +10 -1
- package/runtime/api-2d.js +301 -21
- package/runtime/api-3d/pbr.js +45 -1
- package/runtime/api-3d.js +1 -0
- package/runtime/api-effects.js +90 -3
- package/runtime/api-gameutils.js +476 -0
- package/runtime/api-generative.js +610 -0
- package/runtime/api-skybox.js +54 -0
- package/runtime/api-voxel.js +139 -28
- package/runtime/gpu-threejs.js +13 -9
- package/runtime/ui.js +2 -2
- package/src/main.js +20 -0
- package/public/os9-shell/assets/index-B1Uvacma.js +0 -32825
- package/public/os9-shell/assets/index-B1Uvacma.js.map +0 -1
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// Skybox API for Nova64 - Space, gradient, and solid sky backgrounds
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
|
|
4
|
+
export function skyboxApi(gpu) {
|
|
5
|
+
let skyboxMesh = null;
|
|
6
|
+
let starField = null;
|
|
7
|
+
let _rotSpeed = 1.0; // multiplier for animateSkybox speed
|
|
8
|
+
let _auto = false; // enableSkyboxAutoAnimate flag
|
|
9
|
+
|
|
10
|
+
// ── Space skybox ────────────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Create a procedural space background with stars and optional nebula.
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
* @param {number} [options.starCount=1000]
|
|
15
|
+
* @param {number} [options.starSize=2]
|
|
16
|
+
* @param {boolean} [options.nebulae=true]
|
|
17
|
+
* @param {number} [options.nebulaColor=0x4422aa]
|
|
18
|
+
*/
|
|
19
|
+
function createSpaceSkybox(options = {}) {
|
|
20
|
+
const { starCount = 1000, starSize = 2, nebulae = true, nebulaColor = 0x4422aa } = options;
|
|
21
|
+
|
|
22
|
+
_clearSky();
|
|
23
|
+
|
|
24
|
+
const starGeometry = new THREE.BufferGeometry();
|
|
25
|
+
const starPositions = [];
|
|
26
|
+
const starColors = [];
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < starCount; i++) {
|
|
29
|
+
const radius = 500 + Math.random() * 500;
|
|
30
|
+
const theta = Math.random() * Math.PI * 2;
|
|
31
|
+
const phi = Math.acos(2 * Math.random() - 1);
|
|
32
|
+
starPositions.push(
|
|
33
|
+
radius * Math.sin(phi) * Math.cos(theta),
|
|
34
|
+
radius * Math.sin(phi) * Math.sin(theta),
|
|
35
|
+
radius * Math.cos(phi)
|
|
36
|
+
);
|
|
37
|
+
const c = Math.random();
|
|
38
|
+
if (c < 0.7) starColors.push(1, 1, 1);
|
|
39
|
+
else if (c < 0.85) starColors.push(0.7, 0.8, 1);
|
|
40
|
+
else if (c < 0.95) starColors.push(1, 1, 0.7);
|
|
41
|
+
else starColors.push(1, 0.7, 0.6);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starPositions, 3));
|
|
45
|
+
starGeometry.setAttribute('color', new THREE.Float32BufferAttribute(starColors, 3));
|
|
46
|
+
|
|
47
|
+
starField = new THREE.Points(
|
|
48
|
+
starGeometry,
|
|
49
|
+
new THREE.PointsMaterial({
|
|
50
|
+
size: starSize,
|
|
51
|
+
vertexColors: true,
|
|
52
|
+
transparent: true,
|
|
53
|
+
opacity: 0.8,
|
|
54
|
+
sizeAttenuation: true,
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
gpu.scene.add(starField);
|
|
58
|
+
|
|
59
|
+
if (nebulae) {
|
|
60
|
+
skyboxMesh = _gradientSphere(0x000511, nebulaColor);
|
|
61
|
+
}
|
|
62
|
+
return { starField, skyboxMesh };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ── Gradient skybox ─────────────────────────────────────────────────────────
|
|
66
|
+
/**
|
|
67
|
+
* Create a two-colour gradient sky (daylight, sunset, alien worlds, etc.).
|
|
68
|
+
* @param {number} [topColor=0x1a6aa8] - hex colour at the zenith
|
|
69
|
+
* @param {number} [bottomColor=0xf48c60] - hex colour at the horizon
|
|
70
|
+
*/
|
|
71
|
+
function createGradientSkybox(topColor = 0x1a6aa8, bottomColor = 0xf48c60) {
|
|
72
|
+
_clearSky();
|
|
73
|
+
skyboxMesh = _gradientSphere(topColor, bottomColor);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ── Solid-colour skybox ──────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Fill the background with a single colour (indoor, cave, void scenes).
|
|
79
|
+
* @param {number} [color=0x000000]
|
|
80
|
+
*/
|
|
81
|
+
function createSolidSkybox(color = 0x000000) {
|
|
82
|
+
_clearSky();
|
|
83
|
+
gpu.scene.background = new THREE.Color(color);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Image-based (cube map) skybox ────────────────────────────────────────────
|
|
87
|
+
/**
|
|
88
|
+
* Load a cube-map skybox from six image URLs.
|
|
89
|
+
* The cube map is also wired up as the scene environment map so PBR metallic
|
|
90
|
+
* surfaces automatically reflect the sky.
|
|
91
|
+
*
|
|
92
|
+
* @param {string[]} urls - Six face URLs in order: [+X, -X, +Y, -Y, +Z, -Z]
|
|
93
|
+
* i.e. [right, left, top, bottom, front, back]
|
|
94
|
+
* @returns {Promise<THREE.CubeTexture>} Resolves when all six faces are loaded.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* await createImageSkybox([
|
|
98
|
+
* '/assets/sky/px.jpg', '/assets/sky/nx.jpg',
|
|
99
|
+
* '/assets/sky/py.jpg', '/assets/sky/ny.jpg',
|
|
100
|
+
* '/assets/sky/pz.jpg', '/assets/sky/nz.jpg',
|
|
101
|
+
* ]);
|
|
102
|
+
*/
|
|
103
|
+
function createImageSkybox(urls) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
if (!Array.isArray(urls) || urls.length !== 6) {
|
|
106
|
+
reject(
|
|
107
|
+
new Error('createImageSkybox: requires exactly 6 face URLs [+X, -X, +Y, -Y, +Z, -Z]')
|
|
108
|
+
);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_clearSky();
|
|
113
|
+
|
|
114
|
+
const loader = new THREE.CubeTextureLoader();
|
|
115
|
+
loader.load(
|
|
116
|
+
urls,
|
|
117
|
+
cubeTexture => {
|
|
118
|
+
cubeTexture.colorSpace = THREE.SRGBColorSpace;
|
|
119
|
+
gpu.scene.background = cubeTexture;
|
|
120
|
+
|
|
121
|
+
// Process through PMREMGenerator so metallic/PBR surfaces reflect the sky
|
|
122
|
+
try {
|
|
123
|
+
const pmrem = new THREE.PMREMGenerator(gpu.renderer);
|
|
124
|
+
pmrem.compileCubemapShader();
|
|
125
|
+
gpu.scene.environment = pmrem.fromCubemap(cubeTexture).texture;
|
|
126
|
+
pmrem.dispose();
|
|
127
|
+
} catch (_) {
|
|
128
|
+
// PMREM is optional; the skybox still renders without env reflections
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
resolve(cubeTexture);
|
|
132
|
+
},
|
|
133
|
+
undefined,
|
|
134
|
+
err => reject(err)
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── Shared gradient-sphere helper ────────────────────────────────────────────
|
|
140
|
+
function _gradientSphere(topColor, bottomColor) {
|
|
141
|
+
const geo = new THREE.SphereGeometry(800, 32, 32);
|
|
142
|
+
const mat = new THREE.ShaderMaterial({
|
|
143
|
+
uniforms: {
|
|
144
|
+
topColor: { value: new THREE.Color(topColor) },
|
|
145
|
+
bottomColor: { value: new THREE.Color(bottomColor) },
|
|
146
|
+
},
|
|
147
|
+
vertexShader: `
|
|
148
|
+
varying vec3 vWorldPosition;
|
|
149
|
+
void main() {
|
|
150
|
+
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
151
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
152
|
+
}`,
|
|
153
|
+
fragmentShader: `
|
|
154
|
+
uniform vec3 topColor;
|
|
155
|
+
uniform vec3 bottomColor;
|
|
156
|
+
varying vec3 vWorldPosition;
|
|
157
|
+
void main() {
|
|
158
|
+
float h = normalize(vWorldPosition).y;
|
|
159
|
+
gl_FragColor = vec4(mix(bottomColor, topColor, max(h * 0.5 + 0.5, 0.0)), 1.0);
|
|
160
|
+
}`,
|
|
161
|
+
side: THREE.BackSide,
|
|
162
|
+
depthWrite: false,
|
|
163
|
+
});
|
|
164
|
+
const mesh = new THREE.Mesh(geo, mat);
|
|
165
|
+
gpu.scene.add(mesh);
|
|
166
|
+
return mesh;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function _clearSky() {
|
|
170
|
+
if (skyboxMesh) {
|
|
171
|
+
gpu.scene.remove(skyboxMesh);
|
|
172
|
+
skyboxMesh.geometry?.dispose();
|
|
173
|
+
skyboxMesh.material?.dispose();
|
|
174
|
+
skyboxMesh = null;
|
|
175
|
+
}
|
|
176
|
+
if (starField) {
|
|
177
|
+
gpu.scene.remove(starField);
|
|
178
|
+
starField.geometry?.dispose();
|
|
179
|
+
starField.material?.dispose();
|
|
180
|
+
starField = null;
|
|
181
|
+
}
|
|
182
|
+
if (gpu.scene.background instanceof THREE.Color) {
|
|
183
|
+
gpu.scene.background = null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ── Animation controls ───────────────────────────────────────────────────────
|
|
188
|
+
/** Rotate the star-field one frame. Call in update(dt). */
|
|
189
|
+
function animateSkybox(dt) {
|
|
190
|
+
if (starField) starField.rotation.y += dt * 0.01 * _rotSpeed;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Control star rotation speed (0 = frozen, 1 = default, -1 = reverse). */
|
|
194
|
+
function setSkyboxSpeed(multiplier) {
|
|
195
|
+
_rotSpeed = multiplier;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Auto-animate skybox in the engine loop — no need to call animateSkybox manually. */
|
|
199
|
+
function enableSkyboxAutoAnimate(speed = 1) {
|
|
200
|
+
_auto = true;
|
|
201
|
+
_rotSpeed = speed;
|
|
202
|
+
}
|
|
203
|
+
function disableSkyboxAutoAnimate() {
|
|
204
|
+
_auto = false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function clearSkybox() {
|
|
208
|
+
_clearSky();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Internal: called by src/main.js every frame
|
|
212
|
+
function _tick(dt) {
|
|
213
|
+
if (_auto) animateSkybox(dt);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
_tick,
|
|
218
|
+
exposeTo(target) {
|
|
219
|
+
Object.assign(target, {
|
|
220
|
+
createSpaceSkybox,
|
|
221
|
+
createGradientSkybox,
|
|
222
|
+
createSolidSkybox,
|
|
223
|
+
createImageSkybox,
|
|
224
|
+
animateSkybox,
|
|
225
|
+
setSkyboxSpeed,
|
|
226
|
+
enableSkyboxAutoAnimate,
|
|
227
|
+
disableSkyboxAutoAnimate,
|
|
228
|
+
clearSkybox,
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// runtime/api-sprites.js
|
|
2
|
+
import { loadSpriteSheet, loadTilemap, loadImageElement } from './assets.js';
|
|
3
|
+
|
|
4
|
+
export function spriteApi(gpu) {
|
|
5
|
+
const assets = { sheet: null, map: null, tileSize: 8 };
|
|
6
|
+
let camRef = { x: 0, y: 0 };
|
|
7
|
+
|
|
8
|
+
// Reserved for future camera-relative sprite rendering
|
|
9
|
+
// function _setCameraRef(ref) { camRef = ref; }
|
|
10
|
+
function getSpriteSheetImage() {
|
|
11
|
+
return assets.sheet?.image || null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function loadSprites(url, tileSize = 8) {
|
|
15
|
+
assets.sheet = await loadSpriteSheet(url, tileSize);
|
|
16
|
+
assets.tileSize = tileSize;
|
|
17
|
+
if (gpu.updateTextureForImage) gpu.updateTextureForImage(assets.sheet.image);
|
|
18
|
+
}
|
|
19
|
+
async function loadMap(url) {
|
|
20
|
+
assets.map = await loadTilemap(url);
|
|
21
|
+
globalThis.__nova_map = assets.map;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function applySpriteSheetDataURL(dataURL) {
|
|
25
|
+
const img = await loadImageElement(dataURL);
|
|
26
|
+
if (!assets.sheet)
|
|
27
|
+
assets.sheet = {
|
|
28
|
+
image: img,
|
|
29
|
+
sheetWidth: img.naturalWidth,
|
|
30
|
+
tileSize: 8,
|
|
31
|
+
cols: Math.floor(img.naturalWidth / 8),
|
|
32
|
+
};
|
|
33
|
+
else {
|
|
34
|
+
assets.sheet.image = img;
|
|
35
|
+
assets.sheet.sheetWidth = img.naturalWidth;
|
|
36
|
+
assets.sheet.cols = Math.floor(img.naturalWidth / assets.tileSize);
|
|
37
|
+
}
|
|
38
|
+
if (gpu.updateTextureForImage) gpu.updateTextureForImage(img);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function spr(
|
|
42
|
+
id,
|
|
43
|
+
x,
|
|
44
|
+
y,
|
|
45
|
+
{ flipX: _flipX = false, flipY: _flipY = false, scale = 1, parallax = 1 } = {}
|
|
46
|
+
) {
|
|
47
|
+
const ts = assets.tileSize;
|
|
48
|
+
if (!assets.sheet) return;
|
|
49
|
+
const cols = Math.floor(assets.sheet.sheetWidth / ts);
|
|
50
|
+
const sx0 = (id % cols) * ts;
|
|
51
|
+
const sy0 = Math.floor(id / cols) * ts;
|
|
52
|
+
// camera
|
|
53
|
+
const camX = Math.floor(camRef.x * parallax);
|
|
54
|
+
const camY = Math.floor(camRef.y * parallax);
|
|
55
|
+
const dx = (x | 0) - camX;
|
|
56
|
+
const dy = (y | 0) - camY;
|
|
57
|
+
|
|
58
|
+
if (gpu.supportsSpriteBatch && gpu.supportsSpriteBatch()) {
|
|
59
|
+
gpu.queueSprite(assets.sheet.image, sx0, sy0, ts, ts, dx, dy, scale);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function mapDraw(mx, my, w, h, dx, dy, { scale = 1, parallax = 1 } = {}) {
|
|
65
|
+
if (!assets.map) return;
|
|
66
|
+
const ts = assets.tileSize;
|
|
67
|
+
const { width, height, data } = assets.map;
|
|
68
|
+
const camX = Math.floor(camRef.x * parallax);
|
|
69
|
+
const camY = Math.floor(camRef.y * parallax);
|
|
70
|
+
const baseX = dx - camX;
|
|
71
|
+
const baseY = dy - camY;
|
|
72
|
+
for (let ty = 0; ty < h; ty++) {
|
|
73
|
+
for (let tx = 0; tx < w; tx++) {
|
|
74
|
+
const gx = mx + tx;
|
|
75
|
+
const gy = my + ty;
|
|
76
|
+
if (gx < 0 || gy < 0 || gx >= width || gy >= height) continue;
|
|
77
|
+
const id = data[gy * width + gx];
|
|
78
|
+
spr(id, baseX + tx * ts * scale, baseY + ty * ts * scale, { scale, parallax });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
exposeTo(target) {
|
|
85
|
+
Object.assign(target, {
|
|
86
|
+
spr,
|
|
87
|
+
mapDraw,
|
|
88
|
+
loadSprites,
|
|
89
|
+
loadMap,
|
|
90
|
+
getSpriteSheetImage,
|
|
91
|
+
applySpriteSheetDataURL,
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
setCameraRef(ref) {
|
|
95
|
+
camRef = ref;
|
|
96
|
+
},
|
|
97
|
+
getSpriteSheetImage,
|
|
98
|
+
applySpriteSheetDataURL,
|
|
99
|
+
};
|
|
100
|
+
}
|