Codex CLI commited on
Commit
2c6b4f6
·
1 Parent(s): 1f43352

feat(pickups): enhance health orb mechanics with magnetism and attraction animations

Browse files
Files changed (1) hide show
  1. src/pickups.js +35 -8
src/pickups.js CHANGED
@@ -44,19 +44,23 @@ export function spawnHealthOrbs(center, count) {
44
  mesh: group,
45
  light: null,
46
  pos: group.position,
47
- radius: 0.7, // pickup radius
48
  heal: 1,
49
  bobT: G.random() * Math.PI * 2,
50
  vel,
51
  state: 'air', // 'air' | 'settled'
52
  settleTimer: 0,
53
- baseY: 0.2
 
54
  };
55
  G.orbs.push(orb);
56
  }
57
  }
58
 
59
  export function updatePickups(delta) {
 
 
 
60
  for (let i = G.orbs.length - 1; i >= 0; i--) {
61
  const o = G.orbs[i];
62
 
@@ -104,20 +108,43 @@ export function updatePickups(delta) {
104
 
105
  // Visuals: rotation and glow pulse
106
  o.bobT += delta * 2.0;
107
- o.mesh.rotation.y += delta * 1.5;
 
 
108
  // No dynamic light; keep unlit glow cheap
109
 
110
- // If settled, apply gentle bob around baseY
111
- if (o.state === 'settled') {
112
  o.pos.y = o.baseY + Math.sin(o.bobT) * 0.06;
113
  }
114
 
115
- // Pickup check (2D distance on ground plane)
116
  const dx = o.pos.x - G.player.pos.x;
117
  const dz = o.pos.z - G.player.pos.z;
118
  const dist = Math.hypot(dx, dz);
119
- const minDist = o.radius + G.player.radius;
120
- if (dist <= minDist && G.player.alive && G.state === 'playing') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  G.player.health = Math.min(CFG.player.health, G.player.health + o.heal);
122
  // Pulse green heal overlay
123
  G.healFlash = Math.min(1, G.healFlash + CFG.hud.healPulsePerPickup + o.heal * CFG.hud.healPulsePerHP);
 
44
  mesh: group,
45
  light: null,
46
  pos: group.position,
47
+ radius: 0.7, // legacy; pickup now uses absolute distance
48
  heal: 1,
49
  bobT: G.random() * Math.PI * 2,
50
  vel,
51
  state: 'air', // 'air' | 'settled'
52
  settleTimer: 0,
53
+ baseY: 0.2,
54
+ magnet: false
55
  };
56
  G.orbs.push(orb);
57
  }
58
  }
59
 
60
  export function updatePickups(delta) {
61
+ // Attraction/pickup thresholds (meters)
62
+ const ATTRACT_RADIUS = 5.0; // start pulling from farther away
63
+ const PICKUP_DIST = 3.0; // auto-collect distance
64
  for (let i = G.orbs.length - 1; i >= 0; i--) {
65
  const o = G.orbs[i];
66
 
 
108
 
109
  // Visuals: rotation and glow pulse
110
  o.bobT += delta * 2.0;
111
+ // Speed up spin slightly when magnetized
112
+ const spin = o.magnet ? 4.0 : 1.5;
113
+ o.mesh.rotation.y += delta * spin;
114
  // No dynamic light; keep unlit glow cheap
115
 
116
+ // If settled and not magnetized, apply gentle bob around baseY
117
+ if (o.state === 'settled' && !o.magnet) {
118
  o.pos.y = o.baseY + Math.sin(o.bobT) * 0.06;
119
  }
120
 
121
+ // Distance on ground plane (for feel); magnet + pickup thresholds
122
  const dx = o.pos.x - G.player.pos.x;
123
  const dz = o.pos.z - G.player.pos.z;
124
  const dist = Math.hypot(dx, dz);
125
+ // Begin attraction when close enough
126
+ if (!o.magnet && dist <= ATTRACT_RADIUS) {
127
+ o.magnet = true;
128
+ }
129
+ // Attraction animation: pull toward player smoothly
130
+ if (o.magnet) {
131
+ // Disable physics while magnetized for a clean pull
132
+ if (o.vel) { o.vel.set(0, 0, 0); }
133
+ const t = Math.max(0, Math.min(1, 1 - dist / ATTRACT_RADIUS));
134
+ // Non-linear catch-up factor for a snappy feel
135
+ const alpha = 1 - Math.pow(1 - Math.min(0.95, 0.15 + t * 0.8), Math.max(1, delta * 60));
136
+ // Target toward player's position (eye-level), looks good with vertical glide
137
+ o.pos.lerp(G.player.pos, alpha);
138
+ // Scale up slightly as it gets closer
139
+ const s = 1 + 0.35 * t;
140
+ o.mesh.scale.setScalar(s);
141
+ } else {
142
+ // Reset scale when not magnetized
143
+ o.mesh.scale.setScalar(1);
144
+ }
145
+
146
+ // Pickup check using absolute distance threshold (meters)
147
+ if (dist <= PICKUP_DIST && G.player.alive && G.state === 'playing') {
148
  G.player.health = Math.min(CFG.player.health, G.player.health + o.heal);
149
  // Pulse green heal overlay
150
  G.healFlash = Math.min(1, G.healFlash + CFG.hud.healPulsePerPickup + o.heal * CFG.hud.healPulsePerHP);