zeroed-some/sprong / 2145632

Browse files

particle effects, physics tweaks

Authored by espadonne
SHA
2145632cfdb982019e2de7f8c080b30420adb1d1
Parents
52438bc
Tree
6abc092

1 changed file

StatusFile+-
M sprong.js 231 60
sprong.jsmodified
@@ -1,5 +1,5 @@
11
 // Matter.js module aliases
2
-const Body = Matter.Body;
2
+const Body  = Matter.Body;
33
 const World = Matter.World;
44
 const Engine = Matter.Engine;
55
 const Bodies = Matter.Bodies;
@@ -25,6 +25,10 @@ let gameStarted = false;
2525
 let keys = {};
2626
 let inputBuffer = { left: 0, right: 0 };
2727
 
28
+// Particle systems
29
+let particles = [];
30
+let impactParticles = [];
31
+
2832
 // Canvas settings
2933
 const CANVAS_WIDTH  = 800;
3034
 const CANVAS_HEIGHT = 400;
@@ -36,21 +40,27 @@ const PADDLE_WIDTH = 20;
3640
 const PADDLE_HEIGHT = 80;
3741
 
3842
 // Enhanced movement constants
39
-const SUPPORT_SPEED     = 4.5;
40
-const SUPPORT_ACCEL     = 0.8;
41
-const INPUT_SMOOTHING   = 0.15;
42
-const SUPPORT_MAX_SPEED = 6;
43
+const SUPPORT_SPEED     = 6.5;
44
+const SUPPORT_ACCEL     = 1.2;
45
+const INPUT_SMOOTHING   = 0.25
46
+const SUPPORT_MAX_SPEED = 8;  
4347
 
4448
 // Spring physics constants
45
-const PADDLE_MASS       = 0.8;
49
+const PADDLE_MASS       = 0.6;
4650
 const SPRING_LENGTH     = 40;
47
-const SPRING_DAMPING    = 0.8;
48
-const SPRING_STIFFNESS  = 0.02;
51
+const SPRING_DAMPING    = 0.4;
52
+const SPRING_STIFFNESS  = 0.035;
4953
 
5054
 // Visual enhancement constants
5155
 const TRAIL_SEGMENTS        = 8;
5256
 const PADDLE_GLOW_DISTANCE  = 25;
53
-const SPRING_GLOW_INTENSITY = 80;
57
+const SPRING_GLOW_INTENSITY = 120;
58
+
59
+// Particle system constants
60
+const MAX_PARTICLES         = 100;
61
+const PARTICLE_LIFE         = 60;
62
+const IMPACT_PARTICLES      = 8;
63
+const SPRING_PARTICLE_RATE  = 0.3;
5464
 
5565
 function setup() {
5666
     // Create p5.js canvas
@@ -87,9 +97,9 @@ function setup() {
8797
 }
8898
 
8999
 function createSpringPaddleSystem(side) {
90
-    let supportX = side === 'left' ? 60 : width - 60;
91
-    let paddleX = side === 'left' ? 60 + SPRING_LENGTH : width - 60 - SPRING_LENGTH;
92
-    let startY = height / 2;
100
+    let startY    = height / 2;
101
+    let supportX  = side === 'left' ? 60 : width - 60;
102
+    let paddleX   = side === 'left' ? 60 + SPRING_LENGTH : width - 60 - SPRING_LENGTH;
93103
     
94104
     if (side === 'left') {
95105
         // Left support (invisible anchor point controlled by player)
@@ -101,9 +111,9 @@ function createSpringPaddleSystem(side) {
101111
         // Left paddle (the actual hitting surface)
102112
         leftPaddle = Bodies.rectangle(paddleX, startY, PADDLE_WIDTH, PADDLE_HEIGHT, {
103113
             mass: PADDLE_MASS,
104
-            restitution: 1.2,
114
+            restitution: 1.3,
105115
             friction: 0,
106
-            frictionAir: 0.01
116
+            frictionAir: 0.005 // Less air resistance
107117
         });
108118
         
109119
         // Spring constraint connecting support to paddle
@@ -124,9 +134,9 @@ function createSpringPaddleSystem(side) {
124134
         // Right paddle (the actual hitting surface)
125135
         rightPaddle = Bodies.rectangle(paddleX, startY, PADDLE_WIDTH, PADDLE_HEIGHT, {
126136
             mass: PADDLE_MASS,
127
-            restitution: 1.2,
137
+            restitution: 1.3,
128138
             friction: 0,
129
-            frictionAir: 0.01
139
+            frictionAir: 0.005
130140
         });
131141
         
132142
         // Spring constraint connecting support to paddle
@@ -147,12 +157,19 @@ function draw() {
147157
     // Handle enhanced player input
148158
     handleEnhancedInput();
149159
     
160
+    // Update particle systems
161
+    updateParticles();
162
+    checkCollisions();
163
+    
150164
     // Check for scoring
151165
     checkBallPosition();
152166
     
153167
     // Clear canvas
154168
     background(10, 10, 10);
155169
     
170
+    // Draw particles behind everything
171
+    drawParticles();
172
+    
156173
     // Draw game objects with enhanced visuals
157174
     drawSpringPaddleSystemsEnhanced();
158175
     drawBallEnhanced();
@@ -170,16 +187,16 @@ function draw() {
170187
 
171188
 function handleEnhancedInput() {
172189
     // Smooth input accumulation with acceleration
173
-    let leftInput = 0;
174
-    let rightInput = 0;
190
+    let leftInput   = 0;
191
+    let rightInput  = 0;
175192
     
176193
     // Left paddle input (W/S keys)
177194
     if (keys['w'] || keys['W']) leftInput -= 1;
178195
     if (keys['s'] || keys['S']) leftInput += 1;
179196
     
180197
     // Right paddle input (Arrow keys)
181
-    if (keys['ArrowUp']) rightInput -= 1;
182
-    if (keys['ArrowDown']) rightInput += 1;
198
+    if (keys['ArrowUp'])    rightInput -= 1;
199
+    if (keys['ArrowDown'])  rightInput += 1;
183200
     
184201
     // Apply acceleration and smoothing
185202
     inputBuffer.left = lerp(inputBuffer.left, leftInput, INPUT_SMOOTHING);
@@ -210,8 +227,125 @@ function moveSupportEnhanced(support, deltaY) {
210227
     Body.setPosition(support, { x: support.position.x, y: newY });
211228
 }
212229
 
230
+function checkCollisions() {
231
+    let ballPos = ball.position;
232
+    let ballVel = ball.velocity;
233
+    
234
+    // Check paddle collisions for particle effects
235
+    let leftDist = dist(ballPos.x, ballPos.y, leftPaddle.position.x, leftPaddle.position.y);
236
+    let rightDist = dist(ballPos.x, ballPos.y, rightPaddle.position.x, rightPaddle.position.y);
237
+    
238
+    // Collision threshold
239
+    let collisionDist = BALL_RADIUS + PADDLE_WIDTH/2 + 5;
240
+    
241
+    // Left paddle collision
242
+    if (leftDist < collisionDist && ballVel.x < 0) {
243
+        createImpactParticles(ballPos.x, ballPos.y, ballVel.x, ballVel.y);
244
+    }
245
+    
246
+    // Right paddle collision  
247
+    if (rightDist < collisionDist && ballVel.x > 0) {
248
+        createImpactParticles(ballPos.x, ballPos.y, ballVel.x, ballVel.y);
249
+    }
250
+}
251
+
252
+function createImpactParticles(x, y, velX, velY) {
253
+    for (let i = 0; i < IMPACT_PARTICLES; i++) {
254
+        let angle = random(TWO_PI);
255
+        let speed = random(2, 8);
256
+        let size = random(2, 6);
257
+        
258
+        particles.push({
259
+            x: x + random(-5, 5),
260
+            y: y + random(-5, 5),
261
+            vx: cos(angle) * speed - velX * 0.2,
262
+            vy: sin(angle) * speed - velY * 0.2,
263
+            size: size,
264
+            life: PARTICLE_LIFE,
265
+            maxLife: PARTICLE_LIFE,
266
+            color: { r: 255, g: random(100, 255), b: random(100, 150) },
267
+            type: 'impact'
268
+        });
269
+    }
270
+}
271
+
272
+function createSpringParticles(springPos, compression) {
273
+    if (random() < SPRING_PARTICLE_RATE * compression) {
274
+        let angle = random(TWO_PI);
275
+        let speed = random(1, 3) * compression;
276
+        
277
+        particles.push({
278
+            x: springPos.x + random(-10, 10),
279
+            y: springPos.y + random(-10, 10),
280
+            vx: cos(angle) * speed,
281
+            vy: sin(angle) * speed,
282
+            size: random(1, 3),
283
+            life: PARTICLE_LIFE * 0.5,
284
+            maxLife: PARTICLE_LIFE * 0.5,
285
+            color: { r: 0, g: 255, b: 136 },
286
+            type: 'spring'
287
+        });
288
+    }
289
+}
290
+
291
+function updateParticles() {
292
+    // Update and remove dead particles
293
+    for (let i = particles.length - 1; i >= 0; i--) {
294
+        let p = particles[i];
295
+        
296
+        // Update position
297
+        p.x += p.vx;
298
+        p.y += p.vy;
299
+        
300
+        // Apply drag
301
+        p.vx *= 0.98;
302
+        p.vy *= 0.98;
303
+        
304
+        // Update life
305
+        p.life--;
306
+        
307
+        // Remove dead particles
308
+        if (p.life <= 0) {
309
+            particles.splice(i, 1);
310
+        }
311
+    }
312
+    
313
+    // Limit particle count
314
+    if (particles.length > MAX_PARTICLES) {
315
+        particles.splice(0, particles.length - MAX_PARTICLES);
316
+    }
317
+}
318
+
319
+function drawParticles() {
320
+    for (let p of particles) {
321
+        let alpha = map(p.life, 0, p.maxLife, 0, 255);
322
+        
323
+        push();
324
+        translate(p.x, p.y);
325
+        
326
+        if (p.type === 'impact') {
327
+            // Impact particles: bright sparks
328
+            fill(p.color.r, p.color.g, p.color.b, alpha);
329
+            noStroke();
330
+            ellipse(0, 0, p.size, p.size);
331
+            
332
+            // Add glow
333
+            fill(p.color.r, p.color.g, p.color.b, alpha * 0.3);
334
+            ellipse(0, 0, p.size * 2, p.size * 2);
335
+            
336
+        } else if (p.type === 'spring') {
337
+            // Spring particles: green energy
338
+            fill(p.color.r, p.color.g, p.color.b, alpha);
339
+            noStroke();
340
+            ellipse(0, 0, p.size, p.size);
341
+        }
342
+        
343
+        pop();
344
+    }
345
+}
346
+
213347
 function drawSpringPaddleSystemsEnhanced() {
214
-    // Draw springs with enhanced visuals
348
+    // Draw springs with enhanced visuals and particles
215349
     drawSpringsEnhanced();
216350
     
217351
     // Draw paddles with glow effects
@@ -225,17 +359,19 @@ function drawSpringsEnhanced() {
225359
     // Left spring
226360
     let leftSupportPos = leftSupport.position;
227361
     let leftPaddlePos = leftPaddle.position;
228
-    drawSpringLineEnhanced(leftSupportPos, leftPaddlePos);
362
+    let leftCompression = drawSpringLineEnhanced(leftSupportPos, leftPaddlePos);
363
+    createSpringParticles(leftPaddlePos, leftCompression);
229364
     
230365
     // Right spring
231366
     let rightSupportPos = rightSupport.position;
232367
     let rightPaddlePos = rightPaddle.position;
233
-    drawSpringLineEnhanced(rightSupportPos, rightPaddlePos);
368
+    let rightCompression = drawSpringLineEnhanced(rightSupportPos, rightPaddlePos);
369
+    createSpringParticles(rightPaddlePos, rightCompression);
234370
 }
235371
 
236372
 function drawSpringLineEnhanced(startPos, endPos) {
237
-    let segments = 10;
238
-    let amplitude = 8;
373
+    let segments = 12; // More segments for smoother springs
374
+    let amplitude = 10; // Bigger amplitude for more dramatic effect
239375
     
240376
     // Calculate spring compression for visual effects
241377
     let currentLength = dist(startPos.x, startPos.y, endPos.x, endPos.y);
@@ -245,7 +381,7 @@ function drawSpringLineEnhanced(startPos, endPos) {
245381
     // Enhanced spring glow based on compression
246382
     let glowIntensity = 150 + compression * SPRING_GLOW_INTENSITY;
247383
     stroke(0, 255, 136, glowIntensity);
248
-    strokeWeight(2 + compression * 1.5);
384
+    strokeWeight(3 + compression * 2); // Thicker when compressed
249385
     
250386
     // Draw spring coil with smooth curves
251387
     beginShape();
@@ -260,7 +396,7 @@ function drawSpringLineEnhanced(startPos, endPos) {
260396
         if (i > 0 && i < segments) {
261397
             let perpX = -(endPos.y - startPos.y) / currentLength;
262398
             let perpY = (endPos.x - startPos.x) / currentLength;
263
-            let offset = sin(i * PI * 1.2) * amplitude;
399
+            let offset = sin(i * PI * 1.5) * amplitude; // More dramatic oscillation
264400
             x += perpX * offset;
265401
             y += perpY * offset;
266402
         }
@@ -270,9 +406,10 @@ function drawSpringLineEnhanced(startPos, endPos) {
270406
     
271407
     endShape();
272408
     
273
-    // Add spring glow effect
274
-    stroke(0, 255, 136, glowIntensity * 0.3);
275
-    strokeWeight(6 + compression * 2);
409
+    // Add spring glow effect with pulsing
410
+    let pulse = sin(frameCount * 0.1) * 0.2 + 1;
411
+    stroke(0, 255, 136, glowIntensity * 0.4 * pulse);
412
+    strokeWeight(8 + compression * 3);
276413
     beginShape();
277414
     noFill();
278415
     
@@ -284,6 +421,8 @@ function drawSpringLineEnhanced(startPos, endPos) {
284421
     }
285422
     
286423
     endShape();
424
+    
425
+    return compression; // Return compression for particle effects
287426
 }
288427
 
289428
 function drawPaddlesWithGlow() {
@@ -302,28 +441,37 @@ function drawSinglePaddleEnhanced(paddle, ballDistance) {
302441
     let angle = paddle.angle;
303442
     
304443
     // Calculate glow intensity based on ball proximity
305
-    let glowIntensity = map(ballDistance, 0, PADDLE_GLOW_DISTANCE, 100, 0);
306
-    glowIntensity = constrain(glowIntensity, 0, 100);
444
+    let glowIntensity = map(ballDistance, 0, PADDLE_GLOW_DISTANCE, 150, 0);
445
+    glowIntensity = constrain(glowIntensity, 0, 150);
307446
     
308447
     push();
309448
     translate(pos.x, pos.y);
310449
     rotate(angle);
311450
     
312
-    // Draw glow effect first
451
+    // Draw enhanced glow effect first
313452
     if (glowIntensity > 0) {
314
-        fill(0, 255, 136, glowIntensity * 0.5);
453
+        fill(0, 255, 136, glowIntensity * 0.6);
315454
         noStroke();
316455
         rectMode(CENTER);
317
-        rect(0, 0, PADDLE_WIDTH + 8, PADDLE_HEIGHT + 8);
456
+        rect(0, 0, PADDLE_WIDTH + 12, PADDLE_HEIGHT + 12);
457
+        
458
+        // Add outer glow
459
+        fill(0, 255, 136, glowIntensity * 0.3);
460
+        rect(0, 0, PADDLE_WIDTH + 20, PADDLE_HEIGHT + 20);
318461
     }
319462
     
320
-    // Draw main paddle
463
+    // Draw main paddle with enhanced visual
321464
     fill(0, 255, 136);
322
-    stroke(0, 255, 136, 200 + glowIntensity);
323
-    strokeWeight(2);
465
+    stroke(0, 255, 136, 220 + glowIntensity * 0.5);
466
+    strokeWeight(3);
324467
     rectMode(CENTER);
325468
     rect(0, 0, PADDLE_WIDTH, PADDLE_HEIGHT);
326469
     
470
+    // Add core highlight
471
+    fill(150, 255, 200, 100);
472
+    noStroke();
473
+    rect(0, 0, PADDLE_WIDTH - 4, PADDLE_HEIGHT - 4);
474
+    
327475
     pop();
328476
 }
329477
 
@@ -332,14 +480,20 @@ function drawSupportPointsEnhanced() {
332480
     let leftActivity = Math.abs(inputBuffer.left) * 255;
333481
     let rightActivity = Math.abs(inputBuffer.right) * 255;
334482
     
335
-    // Left support
336
-    fill(0, 255, 136, 100 + leftActivity * 0.5);
483
+    // Left support with pulsing effect
484
+    let leftPulse = sin(frameCount * 0.2) * 0.3 + 1;
485
+    fill(0, 255, 136, 100 + leftActivity * 0.6);
337486
     noStroke();
338
-    ellipse(leftSupport.position.x, leftSupport.position.y, 8 + leftActivity * 0.1, 8 + leftActivity * 0.1);
339
-    
340
-    // Right support
341
-    fill(0, 255, 136, 100 + rightActivity * 0.5);
342
-    ellipse(rightSupport.position.x, rightSupport.position.y, 8 + rightActivity * 0.1, 8 + rightActivity * 0.1);
487
+    ellipse(leftSupport.position.x, leftSupport.position.y, 
488
+           (8 + leftActivity * 0.15) * leftPulse, 
489
+           (8 + leftActivity * 0.15) * leftPulse);
490
+    
491
+    // Right support with pulsing effect
492
+    let rightPulse = sin(frameCount * 0.2 + PI) * 0.3 + 1;
493
+    fill(0, 255, 136, 100 + rightActivity * 0.6);
494
+    ellipse(rightSupport.position.x, rightSupport.position.y, 
495
+           (8 + rightActivity * 0.15) * rightPulse, 
496
+           (8 + rightActivity * 0.15) * rightPulse);
343497
 }
344498
 
345499
 function drawBallEnhanced() {
@@ -350,22 +504,35 @@ function drawBallEnhanced() {
350504
     // Enhanced ball with speed-based effects
351505
     let speedIntensity = map(speed, 0, 15, 50, 255);
352506
     
353
-    // Ball trail effect
354
-    fill(255, 100, 100, 30);
355
-    noStroke();
356
-    ellipse(ballPos.x, ballPos.y, BALL_RADIUS * 4, BALL_RADIUS * 4);
507
+    // Multi-layered trail effect
508
+    for (let i = 0; i < 3; i++) {
509
+        let offset = i * 3;
510
+        fill(255, 100, 100, 40 - i * 10);
511
+        noStroke();
512
+        ellipse(ballPos.x - ballVel.x * offset * 0.1, 
513
+               ballPos.y - ballVel.y * offset * 0.1, 
514
+               BALL_RADIUS * (4 - i), BALL_RADIUS * (4 - i));
515
+    }
357516
     
358
-    // Main ball
517
+    // Main ball with enhanced glow
359518
     fill(255, 100, 100);
360
-    stroke(255, 150, 150, speedIntensity);
361
-    strokeWeight(2 + speed * 0.1);
519
+    stroke(255, 200, 200, speedIntensity);
520
+    strokeWeight(3 + speed * 0.15);
362521
     ellipse(ballPos.x, ballPos.y, BALL_RADIUS * 2, BALL_RADIUS * 2);
363522
     
364
-    // Speed indicator
365
-    if (speed > 10) {
366
-        fill(255, 255, 255, speedIntensity * 0.5);
523
+    // Speed indicator core
524
+    if (speed > 8) {
525
+        fill(255, 255, 255, speedIntensity * 0.8);
367526
         noStroke();
368
-        ellipse(ballPos.x, ballPos.y, BALL_RADIUS, BALL_RADIUS);
527
+        ellipse(ballPos.x, ballPos.y, BALL_RADIUS * 0.8, BALL_RADIUS * 0.8);
528
+    }
529
+    
530
+    // Outer energy ring for high speeds
531
+    if (speed > 12) {
532
+        noFill();
533
+        stroke(255, 255, 255, speedIntensity * 0.5);
534
+        strokeWeight(2);
535
+        ellipse(ballPos.x, ballPos.y, BALL_RADIUS * 3, BALL_RADIUS * 3);
369536
     }
370537
 }
371538
 
@@ -392,6 +559,7 @@ function drawDebugInfo() {
392559
     textSize(12);
393560
     text(`FPS: ${Math.round(frameRate())}`, 10, 20);
394561
     text(`Ball Speed: ${Math.round(getBallSpeed())}`, 10, 35);
562
+    text(`Particles: ${particles.length}`, 10, 50);
395563
     
396564
     // Enhanced spring info
397565
     let leftSpringLength = dist(leftSupport.position.x, leftSupport.position.y, 
@@ -399,9 +567,9 @@ function drawDebugInfo() {
399567
     let rightSpringLength = dist(rightSupport.position.x, rightSupport.position.y, 
400568
                                 rightPaddle.position.x, rightPaddle.position.y);
401569
     
402
-    text(`Left Spring: ${Math.round(leftSpringLength)}px`, 10, 50);
403
-    text(`Right Spring: ${Math.round(rightSpringLength)}px`, 10, 65);
404
-    text(`Input Buffer: L=${inputBuffer.left.toFixed(2)} R=${inputBuffer.right.toFixed(2)}`, 10, 80);
570
+    text(`L Spring: ${Math.round(leftSpringLength)}px (${((SPRING_LENGTH/leftSpringLength - 1) * 100).toFixed(0)}%)`, 10, 65);
571
+    text(`R Spring: ${Math.round(rightSpringLength)}px (${((SPRING_LENGTH/rightSpringLength - 1) * 100).toFixed(0)}%)`, 10, 80);
572
+    text(`Input: L=${inputBuffer.left.toFixed(2)} R=${inputBuffer.right.toFixed(2)}`, 10, 95);
405573
 }
406574
 
407575
 function drawStartMessage() {
@@ -410,7 +578,7 @@ function drawStartMessage() {
410578
     textSize(20);
411579
     text("Press any key to start!", width/2, height/2 + 100);
412580
     textSize(14);
413
-    text("Enhanced controls with smooth acceleration!", width/2, height/2 + 125);
581
+    text("Bouncier springs, faster paddles, explosive particles!", width/2, height/2 + 125);
414582
 }
415583
 
416584
 function resetBall() {
@@ -492,6 +660,9 @@ function keyPressed() {
492660
         inputBuffer.left = 0;
493661
         inputBuffer.right = 0;
494662
         
663
+        // Clear particles
664
+        particles = [];
665
+        
495666
         console.log("🔄 Game reset!");
496667
     }
497668
 }