Codex CLI commited on
Commit
ed36a74
·
1 Parent(s): 09a3a37

feat(fx, pickups, projectiles): remove dynamic lights to optimize performance and shader stability

Browse files
Files changed (3) hide show
  1. src/fx.js +5 -24
  2. src/pickups.js +6 -14
  3. src/projectiles.js +3 -4
src/fx.js CHANGED
@@ -42,11 +42,8 @@ export function spawnMuzzleFlash() {
42
  quad.renderOrder = 11;
43
  G.scene.add(quad);
44
 
45
- const light = new THREE.PointLight(0xfff2b0, 7, 6, 2);
46
- light.position.copy(quad.position);
47
- G.scene.add(light);
48
-
49
- G.fx.flashes.push({ mesh: quad, light, life: CFG.fx.muzzleLife });
50
  }
51
 
52
  export function spawnMuzzleFlashAt(worldPos, color = 0xffc060) {
@@ -59,11 +56,7 @@ export function spawnMuzzleFlashAt(worldPos, color = 0xffc060) {
59
  quad.renderOrder = 11;
60
  G.scene.add(quad);
61
 
62
- const light = new THREE.PointLight(color, 5.5, 5, 2);
63
- light.position.copy(worldPos);
64
- G.scene.add(light);
65
-
66
- G.fx.flashes.push({ mesh: quad, light, life: CFG.fx.muzzleLife });
67
  }
68
 
69
  // Quick, subtle dust puff at a world position
@@ -97,12 +90,9 @@ export function spawnPortalAt(worldPos, color = 0xff5522, size = 1.1, life = 0.3
97
  flare.position.copy(worldPos);
98
  flare.lookAt(G.camera.position);
99
  flare.renderOrder = 12;
100
- const light = new THREE.PointLight(color, 5, size * 6, 2);
101
- light.position.copy(worldPos);
102
  G.scene.add(ring);
103
  G.scene.add(flare);
104
- G.scene.add(light);
105
- G.fx.portals.push({ ring, flare, light, life, maxLife: life, rot: Math.random() * Math.PI * 2 });
106
  }
107
 
108
  // Grenade explosion: additive glow sphere + shock ring + light
@@ -118,12 +108,9 @@ export function spawnExplosionAt(worldPos, radius = 6) {
118
  );
119
  ring.position.copy(worldPos);
120
  ring.rotation.x = Math.PI / 2;
121
- const light = new THREE.PointLight(0xffa050, 9, radius * 3.5, 2);
122
- light.position.copy(worldPos);
123
  G.scene.add(glow);
124
  G.scene.add(ring);
125
- G.scene.add(light);
126
- G.explosions.push({ glow, ring, light, life: 0.5, maxLife: 0.5 });
127
  }
128
 
129
  export function updateFX(delta) {
@@ -155,10 +142,8 @@ export function updateFX(delta) {
155
  m.life -= delta;
156
  m.mesh.material.opacity = Math.max(0, m.life / CFG.fx.muzzleLife);
157
  m.mesh.scale.setScalar(1 + (1 - m.life / CFG.fx.muzzleLife) * 0.6);
158
- if (m.light) m.light.intensity = 3 + 4 * (m.life / CFG.fx.muzzleLife);
159
  if (m.life <= 0) {
160
  G.scene.remove(m.mesh);
161
- if (m.light) G.scene.remove(m.light);
162
  m.mesh.geometry.dispose();
163
  if (m.mesh.material && m.mesh.material.dispose) m.mesh.material.dispose();
164
  G.fx.flashes.splice(i, 1);
@@ -191,12 +176,10 @@ export function updateFX(delta) {
191
  p.ring.scale.setScalar(s);
192
  p.flare.material.opacity = 0.15 + 0.45 * t;
193
  p.flare.scale.setScalar(s * 1.2);
194
- if (p.light) p.light.intensity = 2 + 8 * t;
195
  p.flare.lookAt(G.camera.position);
196
  if (p.life <= 0) {
197
  G.scene.remove(p.ring);
198
  G.scene.remove(p.flare);
199
- if (p.light) G.scene.remove(p.light);
200
  p.ring.geometry.dispose();
201
  p.flare.geometry.dispose();
202
  if (p.ring.material && p.ring.material.dispose) p.ring.material.dispose();
@@ -220,11 +203,9 @@ export function updateFX(delta) {
220
  e.ring.scale.setScalar(0.9 + (1 - t) * 2.6);
221
  e.ring.rotation.z += delta * 2.5;
222
  }
223
- if (e.light) e.light.intensity = 2 + 10 * t;
224
  if (e.life <= 0) {
225
  if (e.glow) { G.scene.remove(e.glow); e.glow.geometry.dispose(); if (e.glow.material?.dispose) e.glow.material.dispose(); }
226
  if (e.ring) { G.scene.remove(e.ring); e.ring.geometry.dispose(); if (e.ring.material?.dispose) e.ring.material.dispose(); }
227
- if (e.light) { G.scene.remove(e.light); }
228
  G.explosions.splice(i, 1);
229
  }
230
  }
 
42
  quad.renderOrder = 11;
43
  G.scene.add(quad);
44
 
45
+ // Avoid dynamic lights to prevent shader recompiles
46
+ G.fx.flashes.push({ mesh: quad, light: null, life: CFG.fx.muzzleLife });
 
 
 
47
  }
48
 
49
  export function spawnMuzzleFlashAt(worldPos, color = 0xffc060) {
 
56
  quad.renderOrder = 11;
57
  G.scene.add(quad);
58
 
59
+ G.fx.flashes.push({ mesh: quad, light: null, life: CFG.fx.muzzleLife });
 
 
 
 
60
  }
61
 
62
  // Quick, subtle dust puff at a world position
 
90
  flare.position.copy(worldPos);
91
  flare.lookAt(G.camera.position);
92
  flare.renderOrder = 12;
 
 
93
  G.scene.add(ring);
94
  G.scene.add(flare);
95
+ G.fx.portals.push({ ring, flare, light: null, life, maxLife: life, rot: Math.random() * Math.PI * 2 });
 
96
  }
97
 
98
  // Grenade explosion: additive glow sphere + shock ring + light
 
108
  );
109
  ring.position.copy(worldPos);
110
  ring.rotation.x = Math.PI / 2;
 
 
111
  G.scene.add(glow);
112
  G.scene.add(ring);
113
+ G.explosions.push({ glow, ring, light: null, life: 0.5, maxLife: 0.5 });
 
114
  }
115
 
116
  export function updateFX(delta) {
 
142
  m.life -= delta;
143
  m.mesh.material.opacity = Math.max(0, m.life / CFG.fx.muzzleLife);
144
  m.mesh.scale.setScalar(1 + (1 - m.life / CFG.fx.muzzleLife) * 0.6);
 
145
  if (m.life <= 0) {
146
  G.scene.remove(m.mesh);
 
147
  m.mesh.geometry.dispose();
148
  if (m.mesh.material && m.mesh.material.dispose) m.mesh.material.dispose();
149
  G.fx.flashes.splice(i, 1);
 
176
  p.ring.scale.setScalar(s);
177
  p.flare.material.opacity = 0.15 + 0.45 * t;
178
  p.flare.scale.setScalar(s * 1.2);
 
179
  p.flare.lookAt(G.camera.position);
180
  if (p.life <= 0) {
181
  G.scene.remove(p.ring);
182
  G.scene.remove(p.flare);
 
183
  p.ring.geometry.dispose();
184
  p.flare.geometry.dispose();
185
  if (p.ring.material && p.ring.material.dispose) p.ring.material.dispose();
 
203
  e.ring.scale.setScalar(0.9 + (1 - t) * 2.6);
204
  e.ring.rotation.z += delta * 2.5;
205
  }
 
206
  if (e.life <= 0) {
207
  if (e.glow) { G.scene.remove(e.glow); e.glow.geometry.dispose(); if (e.glow.material?.dispose) e.glow.material.dispose(); }
208
  if (e.ring) { G.scene.remove(e.ring); e.ring.geometry.dispose(); if (e.ring.material?.dispose) e.ring.material.dispose(); }
 
209
  G.explosions.splice(i, 1);
210
  }
211
  }
src/pickups.js CHANGED
@@ -4,12 +4,9 @@ import { CFG } from './config.js';
4
  import { getTerrainHeight } from './world.js';
5
 
6
  // Share orb material/geometry to avoid per-orb allocations
7
- const ORB_MAT = new THREE.MeshStandardMaterial({
8
- color: 0x33ff66,
9
- emissive: 0x1faa4e,
10
- emissiveIntensity: 1.1,
11
- roughness: 0.3,
12
- metalness: 0.0
13
  });
14
  const ORB_GEO = new THREE.SphereGeometry(0.12, 14, 12);
15
 
@@ -30,15 +27,10 @@ export function spawnHealthOrbs(center, count) {
30
  );
31
 
32
  const sphere = new THREE.Mesh(ORB_GEO, ORB_MAT);
33
- sphere.castShadow = true;
34
  sphere.receiveShadow = false;
35
  group.add(sphere);
36
 
37
- // Soft green point light for glow
38
- const light = new THREE.PointLight(0x33ff66, 0.9, 6, 2);
39
- light.position.set(0, 0.1, 0);
40
- group.add(light);
41
-
42
  G.scene.add(group);
43
 
44
  // Initial outward + upward velocity (reduced to keep grouping tighter)
@@ -49,7 +41,7 @@ export function spawnHealthOrbs(center, count) {
49
 
50
  const orb = {
51
  mesh: group,
52
- light,
53
  pos: group.position,
54
  radius: 0.7, // pickup radius
55
  heal: 1,
@@ -112,7 +104,7 @@ export function updatePickups(delta) {
112
  // Visuals: rotation and glow pulse
113
  o.bobT += delta * 2.0;
114
  o.mesh.rotation.y += delta * 1.5;
115
- if (o.light) o.light.intensity = 0.7 + 0.4 * (0.5 + 0.5 * Math.sin(o.bobT * 2.0));
116
 
117
  // If settled, apply gentle bob around baseY
118
  if (o.state === 'settled') {
 
4
  import { getTerrainHeight } from './world.js';
5
 
6
  // Share orb material/geometry to avoid per-orb allocations
7
+ // Switch to unlit Basic material so orbs glow without extra scene lights
8
+ const ORB_MAT = new THREE.MeshBasicMaterial({
9
+ color: 0x5cff9a
 
 
 
10
  });
11
  const ORB_GEO = new THREE.SphereGeometry(0.12, 14, 12);
12
 
 
27
  );
28
 
29
  const sphere = new THREE.Mesh(ORB_GEO, ORB_MAT);
30
+ sphere.castShadow = false;
31
  sphere.receiveShadow = false;
32
  group.add(sphere);
33
 
 
 
 
 
 
34
  G.scene.add(group);
35
 
36
  // Initial outward + upward velocity (reduced to keep grouping tighter)
 
41
 
42
  const orb = {
43
  mesh: group,
44
+ light: null,
45
  pos: group.position,
46
  radius: 0.7, // pickup radius
47
  heal: 1,
 
104
  // Visuals: rotation and glow pulse
105
  o.bobT += delta * 2.0;
106
  o.mesh.rotation.y += delta * 1.5;
107
+ // No dynamic light; keep unlit glow cheap
108
 
109
  // If settled, apply gentle bob around baseY
110
  if (o.state === 'settled') {
src/projectiles.js CHANGED
@@ -80,8 +80,7 @@ export function spawnEnemyFireball(start, dirOrVel, asVelocity = false) {
80
  group.add(core);
81
  group.add(glow);
82
  group.add(ring);
83
- const light = new THREE.PointLight(0xff5522, 7, 11, 2);
84
- group.add(light);
85
 
86
  group.position.copy(start);
87
  G.scene.add(group);
@@ -106,7 +105,7 @@ export function spawnEnemyFireball(start, dirOrVel, asVelocity = false) {
106
  core,
107
  glow,
108
  ring,
109
- light,
110
  osc: Math.random() * Math.PI * 2
111
  };
112
 
@@ -135,7 +134,7 @@ export function updateEnemyProjectiles(delta, onPlayerDeath) {
135
  p.mesh.scale.setScalar(pulse);
136
  if (p.ring) p.ring.rotation.z += delta * 3;
137
  if (p.glow) p.glow.material.opacity = 0.6 + Math.abs(Math.sin(p.osc * 1.3)) * 0.5;
138
- if (p.light) p.light.intensity = 6 + Math.abs(Math.sin(p.osc * 2.1)) * 6;
139
  }
140
  p.life -= delta;
141
 
 
80
  group.add(core);
81
  group.add(glow);
82
  group.add(ring);
83
+ // Avoid dynamic lights to keep shaders stable; rely on glow meshes
 
84
 
85
  group.position.copy(start);
86
  G.scene.add(group);
 
105
  core,
106
  glow,
107
  ring,
108
+ light: null,
109
  osc: Math.random() * Math.PI * 2
110
  };
111
 
 
134
  p.mesh.scale.setScalar(pulse);
135
  if (p.ring) p.ring.rotation.z += delta * 3;
136
  if (p.glow) p.glow.material.opacity = 0.6 + Math.abs(Math.sin(p.osc * 1.3)) * 0.5;
137
+ // no dynamic light
138
  }
139
  p.life -= delta;
140