nova64 0.2.5 → 0.2.6
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/index.html +6 -1
- package/package.json +37 -32
- 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,553 @@
|
|
|
1
|
+
# 🚀 Ultimate 3D Migration Guide for Nova64
|
|
2
|
+
|
|
3
|
+
Transform your Nova64 experiences into **spectacular 3D fantasy console adventures** with advanced materials, cinematic lighting, and Nintendo 64/PlayStation aesthetics!
|
|
4
|
+
|
|
5
|
+
## 🌟 **Migration to v0.2.0**
|
|
6
|
+
|
|
7
|
+
### 🎯 **Breaking Changes**
|
|
8
|
+
|
|
9
|
+
- **Three.js Only**: Nova64 now exclusively uses Three.js for maximum 3D performance
|
|
10
|
+
- **Enhanced API**: New 3D functions with improved parameter structure
|
|
11
|
+
- **Material System**: Advanced material options with new configuration format
|
|
12
|
+
- **Camera Controls**: Improved camera system with smooth interpolation
|
|
13
|
+
|
|
14
|
+
### ✅ **Backward Compatibility**
|
|
15
|
+
|
|
16
|
+
- **100% 2D Compatibility**: All existing 2D carts work without modification
|
|
17
|
+
- **Gradual Migration**: Add 3D elements incrementally to existing projects
|
|
18
|
+
- **API Preservation**: Core 2D functions remain unchanged
|
|
19
|
+
|
|
20
|
+
## 🌟 **Revolutionary 3D Transformation**
|
|
21
|
+
|
|
22
|
+
### 🎪 **Advanced Rendering Pipeline**
|
|
23
|
+
|
|
24
|
+
1. **🎯 3D Scene Rendering**: Automatic Three.js rendering with advanced materials and lighting
|
|
25
|
+
2. **🎨 2D Overlay Compositing**: High-precision transparent overlay for HUD and UI elements
|
|
26
|
+
3. **✅ 100% Backward Compatibility**: All existing 2D carts work flawlessly with zero changes
|
|
27
|
+
4. **⚡ Hot Reloading**: Instant updates without losing game state during development
|
|
28
|
+
|
|
29
|
+
### 📐 **Coordinate Systems**
|
|
30
|
+
|
|
31
|
+
- **🌍 3D World Space**: Standard 3D coordinates (Y-up) with perspective projection
|
|
32
|
+
- **🖥️ 2D Screen Space**: 320×180 pixel overlay coordinates (Y-down) for UI elements
|
|
33
|
+
- **🎯 Hybrid Mapping**: Seamless conversion between 2D screen and 3D world positions
|
|
34
|
+
|
|
35
|
+
## 🎯 **Spectacular Migration Steps**
|
|
36
|
+
|
|
37
|
+
### 🌟 **Step 1: Advanced 3D Scene Setup**
|
|
38
|
+
|
|
39
|
+
Transform your cart into a cinematic 3D experience:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
// ❌ Before (Basic 2D)
|
|
43
|
+
export function init() {
|
|
44
|
+
cls();
|
|
45
|
+
// Basic 2D initialization...
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ✅ After (Ultimate 3D Fantasy Console)
|
|
49
|
+
export function init() {
|
|
50
|
+
console.log('🚀 Initializing spectacular 3D world...');
|
|
51
|
+
|
|
52
|
+
// 🎪 Advanced 3D scene setup
|
|
53
|
+
setCameraPosition(0, 5, 10); // Cinematic camera position
|
|
54
|
+
setCameraTarget(0, 0, 0); // Look at world origin
|
|
55
|
+
setCameraFOV(75); // Wide-angle perspective
|
|
56
|
+
|
|
57
|
+
// 🌫️ Atmospheric effects for depth and mood
|
|
58
|
+
setFog(0x1a1a2e, 8, 25); // Mysterious purple fog
|
|
59
|
+
|
|
60
|
+
// 💡 Enhanced lighting system
|
|
61
|
+
setAmbientLight(0x404060, 0.3); // Subtle ambient lighting
|
|
62
|
+
setDirectionalLight(0xffffff, 0.8); // Strong directional light
|
|
63
|
+
|
|
64
|
+
// ✨ Visual enhancement effects
|
|
65
|
+
enablePostProcessing(true); // ACES tone mapping + bloom
|
|
66
|
+
setRenderQuality('high'); // 4K shadows, full effects
|
|
67
|
+
|
|
68
|
+
// 🎨 Existing 2D initialization (still works!)
|
|
69
|
+
cls();
|
|
70
|
+
// ... your existing 2D setup
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 🎨 **Step 2: Advanced 3D Object Creation**
|
|
75
|
+
|
|
76
|
+
Add spectacular 3D objects with professional materials:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
let player2D = { x: 160, y: 90 }; // Existing 2D player
|
|
80
|
+
let player3D,
|
|
81
|
+
worldObjects = []; // New 3D representations
|
|
82
|
+
let particleEffects = []; // Dynamic particle systems
|
|
83
|
+
|
|
84
|
+
export function init() {
|
|
85
|
+
// Previous 3D setup...
|
|
86
|
+
|
|
87
|
+
// 👤 Create spectacular 3D player with advanced materials
|
|
88
|
+
player3D = createCube(0, 1, 0, 1, {
|
|
89
|
+
material: 'metallic', // Professional metallic surface
|
|
90
|
+
color: 0x0088ff, // Bright blue primary color
|
|
91
|
+
emissive: 0x002244, // Subtle blue glow
|
|
92
|
+
metalness: 0.8, // High metallic reflection
|
|
93
|
+
roughness: 0.2, // Smooth, polished surface
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// 🌍 Create immersive world environment
|
|
97
|
+
const ground = createPlane(0, -1, 0, 30, 30, {
|
|
98
|
+
material: 'standard',
|
|
99
|
+
color: 0x2a4d3a, // Forest green ground
|
|
100
|
+
roughness: 0.8, // Natural rough surface
|
|
101
|
+
});
|
|
102
|
+
rotateMesh(ground, -Math.PI / 2, 0, 0); // Make horizontal
|
|
103
|
+
|
|
104
|
+
// ✨ Add magical floating crystals
|
|
105
|
+
for (let i = 0; i < 8; i++) {
|
|
106
|
+
const crystal = createCube(
|
|
107
|
+
Math.cos((i * Math.PI) / 4) * 5, // Circular arrangement
|
|
108
|
+
2 + Math.sin(i * 0.5), // Varied heights
|
|
109
|
+
Math.sin((i * Math.PI) / 4) * 5,
|
|
110
|
+
0.6,
|
|
111
|
+
{
|
|
112
|
+
material: 'holographic', // Ultimate visual effect
|
|
113
|
+
color: 0xff0088,
|
|
114
|
+
emissive: 0x440022,
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
worldObjects.push({ mesh: crystal, spin: i * 0.1 });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 📐 **Step 3: Advanced Coordinate Transformation**
|
|
123
|
+
|
|
124
|
+
Seamlessly convert between 2D screen and 3D world coordinates:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// 🎯 Professional coordinate mapping with perspective correction
|
|
128
|
+
function screen2DToWorld3D(screenX, screenY, depth = 0) {
|
|
129
|
+
// Advanced mapping with camera-relative positioning
|
|
130
|
+
const worldX = (screenX - 160) / 32; // Center and scale X
|
|
131
|
+
const worldZ = (screenY - 90) / 32 + depth; // Y becomes Z with depth
|
|
132
|
+
const worldY = 0; // Ground level default
|
|
133
|
+
return { x: worldX, y: worldY, z: worldZ };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function world3DToScreen2D(worldX, worldY, worldZ) {
|
|
137
|
+
// Project 3D world coordinates to 2D screen space
|
|
138
|
+
const screenX = worldX * 32 + 160;
|
|
139
|
+
const screenY = worldZ * 32 + 90;
|
|
140
|
+
return { x: screenX, y: screenY };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 🎪 Advanced raycasting for precise 3D interaction
|
|
144
|
+
function screenToWorldRay(mouseX, mouseY) {
|
|
145
|
+
// Cast ray from camera through screen point for object picking
|
|
146
|
+
const ray = raycastFromCamera(mouseX, mouseY);
|
|
147
|
+
if (ray && ray.object) {
|
|
148
|
+
console.log(`Hit 3D object: ${ray.object.uuid} at distance ${ray.distance}`);
|
|
149
|
+
return ray;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 🌍 Convert 2D game coordinates to immersive 3D positions
|
|
155
|
+
function enhance2DWith3D(gameObject2D) {
|
|
156
|
+
const world3D = screen2DToWorld3D(gameObject2D.x, gameObject2D.y);
|
|
157
|
+
|
|
158
|
+
// Create spectacular 3D representation
|
|
159
|
+
const mesh3D = createCube(world3D.x, world3D.y + 1, world3D.z, 0.8, {
|
|
160
|
+
material: 'emissive',
|
|
161
|
+
color: gameObject2D.color || 0xff4488,
|
|
162
|
+
emissive: 0x220011,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return { ...gameObject2D, mesh3D, world3D };
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### ⚡ **Step 4: Enhanced Update System**
|
|
170
|
+
|
|
171
|
+
Create smooth, responsive hybrid 2D/3D gameplay:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
export function update() {
|
|
175
|
+
// 🎮 Enhanced input system with WASD + arrows support
|
|
176
|
+
const moveSpeed = 0.12;
|
|
177
|
+
const rotationSpeed = 0.05;
|
|
178
|
+
|
|
179
|
+
// Modern WASD movement (enhanced input system)
|
|
180
|
+
if (key('KeyW') || btn(2)) {
|
|
181
|
+
// W or Up
|
|
182
|
+
player2D.y -= 2;
|
|
183
|
+
player3D.velocity.z = -moveSpeed;
|
|
184
|
+
}
|
|
185
|
+
if (key('KeyS') || btn(3)) {
|
|
186
|
+
// S or Down
|
|
187
|
+
player2D.y += 2;
|
|
188
|
+
player3D.velocity.z = moveSpeed;
|
|
189
|
+
}
|
|
190
|
+
if (key('KeyA') || btn(0)) {
|
|
191
|
+
// A or Left
|
|
192
|
+
player2D.x -= 2;
|
|
193
|
+
player3D.velocity.x = -moveSpeed;
|
|
194
|
+
}
|
|
195
|
+
if (key('KeyD') || btn(1)) {
|
|
196
|
+
// D or Right
|
|
197
|
+
player2D.x += 2;
|
|
198
|
+
player3D.velocity.x = moveSpeed;
|
|
199
|
+
}
|
|
200
|
+
if (key('Space') || btn(4)) {
|
|
201
|
+
// Space or Z button
|
|
202
|
+
player3D.velocity.y = 0.08; // Jump with physics
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 🎯 Advanced 3D physics and positioning
|
|
206
|
+
const world3D = screen2DToWorld3D(player2D.x, player2D.y);
|
|
207
|
+
|
|
208
|
+
// Smooth 3D positioning with interpolation
|
|
209
|
+
const currentPos = getMeshPosition(player3D);
|
|
210
|
+
const targetX = lerp(currentPos.x, world3D.x, 0.1);
|
|
211
|
+
const targetZ = lerp(currentPos.z, world3D.z, 0.1);
|
|
212
|
+
setPosition(player3D, targetX, currentPos.y, targetZ);
|
|
213
|
+
|
|
214
|
+
// Apply physics (gravity, ground collision)
|
|
215
|
+
player3D.velocity.y -= 0.01; // Gravity
|
|
216
|
+
if (currentPos.y <= 1) {
|
|
217
|
+
// Ground collision
|
|
218
|
+
setPosition(player3D, targetX, 1, targetZ);
|
|
219
|
+
player3D.velocity.y = 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// 🎪 Spectacular world object animations
|
|
223
|
+
worldObjects.forEach((obj, i) => {
|
|
224
|
+
obj.spin += rotationSpeed;
|
|
225
|
+
rotateMesh(obj.mesh, obj.spin, obj.spin * 1.3, obj.spin * 0.7);
|
|
226
|
+
|
|
227
|
+
// Dynamic floating motion
|
|
228
|
+
const floatY = 2 + Math.sin(time * 0.02 + i) * 0.4;
|
|
229
|
+
const pos = getMeshPosition(obj.mesh);
|
|
230
|
+
setPosition(obj.mesh, pos.x, floatY, pos.z);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// 📷 Cinematic camera following
|
|
234
|
+
setCameraPosition(world3D.x + 4, world3D.y + 3, world3D.z + 6);
|
|
235
|
+
setCameraTarget(world3D.x, world3D.y + 1, world3D.z);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 🎨 **Step 5: Professional Hybrid Rendering**
|
|
240
|
+
|
|
241
|
+
Create stunning 3D scenes with polished 2D HUD overlays:
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
export function draw() {
|
|
245
|
+
// 🎪 Advanced 3D rendering with cinematic effects
|
|
246
|
+
draw3d(() => {
|
|
247
|
+
// 3D scene renders automatically with all objects
|
|
248
|
+
// Advanced lighting, materials, and post-processing active
|
|
249
|
+
|
|
250
|
+
// 🌟 Optional: Add dynamic lighting effects
|
|
251
|
+
const lightIntensity = 0.8 + Math.sin(time * 0.05) * 0.2;
|
|
252
|
+
setDirectionalLight(0xffffff, lightIntensity);
|
|
253
|
+
|
|
254
|
+
// 💫 Optional: Dynamic atmospheric effects
|
|
255
|
+
const fogColor = Math.floor(Math.sin(time * 0.03) * 20 + 40);
|
|
256
|
+
setFog((fogColor << 16) + (fogColor << 8) + (fogColor + 20), 8, 25);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// 📊 Professional HUD system (rendered over 3D)
|
|
260
|
+
cls(); // Clear 2D overlay (transparent background)
|
|
261
|
+
|
|
262
|
+
// 🏆 Game statistics with modern styling
|
|
263
|
+
print('🏆 SCORE: 1,337', 10, 10, 0xffffff);
|
|
264
|
+
print('❤️ HEALTH: ██████████', 10, 26, 0xff4444);
|
|
265
|
+
print('💎 CRYSTALS: ' + collectedCrystals, 10, 42, 0x44ff88);
|
|
266
|
+
print('⚡ ENERGY: ' + Math.floor(playerEnergy), 10, 58, 0x4488ff);
|
|
267
|
+
|
|
268
|
+
// 🗺️ Advanced minimap with 3D awareness
|
|
269
|
+
const mapX = 240,
|
|
270
|
+
mapY = 10,
|
|
271
|
+
mapSize = 70;
|
|
272
|
+
rect(mapX, mapY, mapSize, mapSize, 0x333333, true); // Map background
|
|
273
|
+
rect(mapX, mapY, mapSize, mapSize, 0x888888, false); // Map border
|
|
274
|
+
|
|
275
|
+
// Draw 3D objects on minimap
|
|
276
|
+
worldObjects.forEach(obj => {
|
|
277
|
+
const pos = getMeshPosition(obj.mesh);
|
|
278
|
+
const mapPosX = mapX + (pos.x + 10) * (mapSize / 20);
|
|
279
|
+
const mapPosY = mapY + (pos.z + 10) * (mapSize / 20);
|
|
280
|
+
pset(mapPosX, mapPosY, 0xff0088); // Crystal positions
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Player position on minimap
|
|
284
|
+
const playerPos = getMeshPosition(player3D);
|
|
285
|
+
const playerMapX = mapX + (playerPos.x + 10) * (mapSize / 20);
|
|
286
|
+
const playerMapY = mapY + (playerPos.z + 10) * (mapSize / 20);
|
|
287
|
+
rect(playerMapX - 1, playerMapY - 1, 3, 3, 0x00ff00, true); // Player dot
|
|
288
|
+
|
|
289
|
+
// 🎮 Control instructions
|
|
290
|
+
print('WASD: Move • Space: Jump • Mouse: Look', 10, 165, 0x888888);
|
|
291
|
+
|
|
292
|
+
// 📈 Performance overlay (optional debug info)
|
|
293
|
+
if (showDebug) {
|
|
294
|
+
const stats = get3DStats();
|
|
295
|
+
print(`FPS: ${Math.round(1000 / deltaTime)}`, 270, 10, 0x88ff88);
|
|
296
|
+
print(`Triangles: ${stats.triangles}`, 270, 26, 0x88ff88);
|
|
297
|
+
print(`Objects: ${stats.objects}`, 270, 42, 0x88ff88);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Common Patterns
|
|
303
|
+
|
|
304
|
+
### Camera Following 2D Character
|
|
305
|
+
|
|
306
|
+
```js
|
|
307
|
+
export function update(dt) {
|
|
308
|
+
// Update 2D player...
|
|
309
|
+
|
|
310
|
+
// Make 3D camera follow 2D position
|
|
311
|
+
const [worldX, , worldZ] = screen2DToWorld3D(player2D.x, player2D.y);
|
|
312
|
+
setCameraPosition(worldX, 5, worldZ + 5);
|
|
313
|
+
setCameraTarget(worldX, 0, worldZ);
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### 3D Background with 2D Gameplay
|
|
318
|
+
|
|
319
|
+
Perfect for platformers or shoot-em-ups:
|
|
320
|
+
|
|
321
|
+
```js
|
|
322
|
+
let terrain3D = [];
|
|
323
|
+
let enemies2D = [];
|
|
324
|
+
|
|
325
|
+
export function init() {
|
|
326
|
+
// Create 3D terrain
|
|
327
|
+
for (let x = -10; x <= 10; x += 2) {
|
|
328
|
+
terrain3D.push(createCube(2, 0x336633, [x, -2, 0]));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Traditional 2D enemies
|
|
332
|
+
enemies2D.push({ x: 200, y: 100, vx: -1 });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function update(dt) {
|
|
336
|
+
// Update 2D gameplay
|
|
337
|
+
enemies2D.forEach(enemy => {
|
|
338
|
+
enemy.x += enemy.vx;
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Animate 3D background
|
|
342
|
+
terrain3D.forEach((cube, i) => {
|
|
343
|
+
rotateMesh(cube, 0, dt * 0.1, 0);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function draw() {
|
|
348
|
+
cls();
|
|
349
|
+
|
|
350
|
+
// Draw 2D gameplay elements
|
|
351
|
+
enemies2D.forEach(enemy => {
|
|
352
|
+
rect(enemy.x, enemy.y, 16, 16, rgba8(255, 0, 0, 255), true);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Mixed 2D/3D Particles
|
|
358
|
+
|
|
359
|
+
```js
|
|
360
|
+
let particles2D = [];
|
|
361
|
+
let particles3D = [];
|
|
362
|
+
|
|
363
|
+
function spawnExplosion(x, y) {
|
|
364
|
+
// 2D particles for UI/effects
|
|
365
|
+
for (let i = 0; i < 10; i++) {
|
|
366
|
+
particles2D.push({
|
|
367
|
+
x,
|
|
368
|
+
y,
|
|
369
|
+
vx: (Math.random() - 0.5) * 4,
|
|
370
|
+
vy: (Math.random() - 0.5) * 4,
|
|
371
|
+
life: 1.0,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// 3D particles for world objects
|
|
376
|
+
const [worldX, , worldZ] = screen2DToWorld3D(x, y);
|
|
377
|
+
for (let i = 0; i < 5; i++) {
|
|
378
|
+
const particle = createCube(0.1, 0xffaa00, [worldX, 0, worldZ]);
|
|
379
|
+
particles3D.push({
|
|
380
|
+
mesh: particle,
|
|
381
|
+
vx: (Math.random() - 0.5) * 2,
|
|
382
|
+
vy: Math.random() * 2,
|
|
383
|
+
vz: (Math.random() - 0.5) * 2,
|
|
384
|
+
life: 1.0,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Performance Tips
|
|
391
|
+
|
|
392
|
+
### Efficient 3D Object Management
|
|
393
|
+
|
|
394
|
+
```js
|
|
395
|
+
// Object pooling for frequently created/destroyed objects
|
|
396
|
+
let particlePool = [];
|
|
397
|
+
|
|
398
|
+
function getPooledParticle() {
|
|
399
|
+
if (particlePool.length > 0) {
|
|
400
|
+
return particlePool.pop();
|
|
401
|
+
}
|
|
402
|
+
return createCube(0.1, 0xffaa00);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function returnToPool(meshId) {
|
|
406
|
+
setPosition(meshId, 1000, 1000, 1000); // Move offscreen
|
|
407
|
+
particlePool.push(meshId);
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### LOD (Level of Detail)
|
|
412
|
+
|
|
413
|
+
```js
|
|
414
|
+
export function update(dt) {
|
|
415
|
+
const cameraPos = getCamera().position;
|
|
416
|
+
|
|
417
|
+
objects3D.forEach(obj => {
|
|
418
|
+
const distance = distanceTo(obj.position, cameraPos);
|
|
419
|
+
|
|
420
|
+
if (distance > 20) {
|
|
421
|
+
// Hide distant objects
|
|
422
|
+
setPosition(obj.mesh, 1000, 1000, 1000);
|
|
423
|
+
} else if (distance > 10) {
|
|
424
|
+
// Use low-detail version
|
|
425
|
+
setScale(obj.mesh, 0.5);
|
|
426
|
+
} else {
|
|
427
|
+
// Full detail
|
|
428
|
+
setScale(obj.mesh, 1);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Debugging
|
|
435
|
+
|
|
436
|
+
### Visual Debugging
|
|
437
|
+
|
|
438
|
+
```js
|
|
439
|
+
export function draw() {
|
|
440
|
+
cls();
|
|
441
|
+
|
|
442
|
+
// Show 3D object count
|
|
443
|
+
print(`3D Objects: ${get3DStats().render.geometries}`, 8, 8, rgba8(255, 255, 255, 255));
|
|
444
|
+
|
|
445
|
+
// Show renderer type
|
|
446
|
+
const rendererInfo = typeof createCube === 'function' ? 'Three.js' : 'WebGL2';
|
|
447
|
+
print(`Renderer: ${rendererInfo}`, 8, 24, rgba8(200, 200, 200, 255));
|
|
448
|
+
|
|
449
|
+
// Performance overlay
|
|
450
|
+
const stats = get3DStats();
|
|
451
|
+
if (stats.render) {
|
|
452
|
+
print(`Triangles: ${stats.render.triangles}`, 8, 40, rgba8(150, 255, 150, 255));
|
|
453
|
+
print(`Draw Calls: ${stats.render.calls}`, 8, 56, rgba8(150, 255, 150, 255));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Console Debugging
|
|
459
|
+
|
|
460
|
+
```js
|
|
461
|
+
// Check if 3D features are available
|
|
462
|
+
if (typeof createCube === 'function') {
|
|
463
|
+
console.log('3D features available');
|
|
464
|
+
} else {
|
|
465
|
+
console.log('Running in 2D-only mode');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Get object information
|
|
469
|
+
const cube = createCube(1, 0xff0000);
|
|
470
|
+
console.log('Cube position:', getPosition(cube));
|
|
471
|
+
console.log('Cube rotation:', getRotation(cube));
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Best Practices
|
|
475
|
+
|
|
476
|
+
1. **Start Simple**: Add one 3D element at a time to existing carts
|
|
477
|
+
2. **Maintain 2D Feel**: Use 3D to enhance, not replace, the 2D aesthetic
|
|
478
|
+
3. **Performance First**: Monitor triangle count and draw calls
|
|
479
|
+
4. **Consistent Style**: Use N64-style effects (`enablePixelation`, `enableDithering`)
|
|
480
|
+
5. **Test Fallbacks**: Ensure carts work on WebGL2-only systems
|
|
481
|
+
|
|
482
|
+
## Example: Upgrading a Shooter
|
|
483
|
+
|
|
484
|
+
```js
|
|
485
|
+
// Before: Pure 2D shooter
|
|
486
|
+
let player = { x: 160, y: 140 };
|
|
487
|
+
let bullets = [];
|
|
488
|
+
let enemies = [];
|
|
489
|
+
|
|
490
|
+
// After: 3D background + 2D gameplay
|
|
491
|
+
let player = { x: 160, y: 140 };
|
|
492
|
+
let player3D;
|
|
493
|
+
let bullets = [];
|
|
494
|
+
let enemies = [];
|
|
495
|
+
let stars3D = [];
|
|
496
|
+
|
|
497
|
+
export function init() {
|
|
498
|
+
// 3D setup
|
|
499
|
+
setCameraPosition(0, 0, 5);
|
|
500
|
+
setFog(0x000011, 10, 50);
|
|
501
|
+
|
|
502
|
+
// Create 3D starfield
|
|
503
|
+
for (let i = 0; i < 50; i++) {
|
|
504
|
+
const star = createCube(0.1, 0xffffff, [
|
|
505
|
+
(Math.random() - 0.5) * 40,
|
|
506
|
+
(Math.random() - 0.5) * 20,
|
|
507
|
+
Math.random() * -30,
|
|
508
|
+
]);
|
|
509
|
+
stars3D.push(star);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// 3D player ship
|
|
513
|
+
player3D = createCube(0.5, 0x00ff00, [0, 0, 0]);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export function update(dt) {
|
|
517
|
+
// 2D player movement
|
|
518
|
+
if (btn(0)) player.x -= 3;
|
|
519
|
+
if (btn(1)) player.x += 3;
|
|
520
|
+
|
|
521
|
+
// Mirror to 3D
|
|
522
|
+
const worldX = (player.x - 160) / 40;
|
|
523
|
+
setPosition(player3D, worldX, 0, 2);
|
|
524
|
+
|
|
525
|
+
// Animate starfield
|
|
526
|
+
stars3D.forEach(star => {
|
|
527
|
+
moveMesh(star, 0, 0, dt * 5);
|
|
528
|
+
const pos = getPosition(star);
|
|
529
|
+
if (pos[2] > 5) {
|
|
530
|
+
setPosition(star, pos[0], pos[1], -30);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// Standard 2D game logic...
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export function draw() {
|
|
538
|
+
cls(); // Clear for 2D overlay
|
|
539
|
+
|
|
540
|
+
// 2D gameplay elements render on top of 3D
|
|
541
|
+
rect(player.x - 8, player.y - 8, 16, 16, rgba8(0, 255, 0, 255), true);
|
|
542
|
+
|
|
543
|
+
bullets.forEach(bullet => {
|
|
544
|
+
pset(bullet.x, bullet.y, rgba8(255, 255, 0, 255));
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
enemies.forEach(enemy => {
|
|
548
|
+
rect(enemy.x, enemy.y, 12, 12, rgba8(255, 0, 0, 255), true);
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
This approach lets you gradually enhance existing games with 3D elements while maintaining their core 2D gameplay feel.
|