zeroed-some/sprong / 5b429e8

Browse files

testing rotation

Authored by espadonne
SHA
5b429e81ef6d7f51823ac44a313cabde0f813df5
Parents
f1fe736
Tree
242bb4a

5 changed files

StatusFile+-
A .DS_Store bin
M js/ai.js 0 5
M js/game-systems.js 116 2
M js/rendering.js 19 12
M js/sprong.js 2 0
.DS_Storeadded
Binary file changed.
js/ai.jsmodified
@@ -559,9 +559,4 @@ function executeAIMovement(aiSettings, rightSupport) {
559559
             window.inputBuffer.right *= 0.9; // Slower decay for more visible movement
560560
         }
561561
     }
562
-}
563
-
564
-// Utility function - should match p5.js lerp
565
-function lerp(start, stop, amt) {
566
-    return amt * (stop - start) + start;
567562
 }
js/game-systems.jsmodified
@@ -1,5 +1,4 @@
11
 // game-systems.js - Core game mechanics and physics
2
-// TODO redocument
32
 
43
 // ============= CONSTANTS =============
54
 // Canvas settings
@@ -48,6 +47,18 @@ const BOP_COOLDOWN = 0; // also also self expl. PULL it.
4847
 const ANCHOR_RECOIL         = 60;   // How far the anchor moves backward during bop
4948
 const BOP_VELOCITY_BOOST    = 5;    // Initial velocity boost for paddle
5049
 
50
+// Rotation control constants
51
+const ROTATION_SPEED        = 0.05;  // Base rotation speed (radians per frame)
52
+const ROTATION_SMOOTHING    = 0.15;  // Input smoothing for rotation (0-1)
53
+const ROTATION_DAMPING      = 0.92;  // Angular velocity damping (0-1)
54
+const ROTATION_MAX_SPEED    = 0.2;   // Maximum angular velocity (radians per frame)
55
+const ROTATION_RESISTANCE   = 3.0;   // How much harder it is to rotate against momentum
56
+const ROTATION_MOMENTUM     = 0.85;  // How much angular momentum is preserved (0-1)
57
+const ROTATION_RETURN_FORCE = 0.02;  // Force returning paddle to neutral position
58
+const ROTATION_MAX_ANGLE    = Math.PI / 4; // Maximum rotation angle (45 degrees)
59
+const ROTATION_WITH_MOMENTUM_BOOST = 1.5;  // Speed multiplier when rotating with momentum
60
+const ROTATION_AGAINST_MOMENTUM_LAG = 0.05; // Lag multiplier when rotating against momentum
61
+
5162
 // ============= BOP SYSTEM =============
5263
 let bopState = {
5364
     left: {
@@ -70,6 +81,26 @@ let bopState = {
7081
     }
7182
 };
7283
 
84
+// ============= ROTATION SYSTEM =============
85
+let rotationState = {
86
+    left: {
87
+        targetAngle: 0,           // Target angle based on input
88
+        currentAngle: 0,          // Current visual angle
89
+        angularVelocity: 0,       // Current angular velocity
90
+        angularMomentum: 0,       // Angular momentum
91
+        inputBuffer: 0,           // Smoothed rotation input (-1 to 1)
92
+        lastDirection: 0          // Last input direction for momentum checks
93
+    },
94
+    right: {
95
+        targetAngle: 0,
96
+        currentAngle: 0,
97
+        angularVelocity: 0,
98
+        angularMomentum: 0,
99
+        inputBuffer: 0,
100
+        lastDirection: 0
101
+    }
102
+};
103
+
73104
 function handleBopInput(keys, aiEnabled, currentTime, leftPaddle, rightPaddle, leftSupport, rightSupport, engine, particles) {
74105
     // Left player bop - use Left Shift for both modes
75106
     let leftBopPressed = keys['Shift'] && !keys['Control'];
@@ -356,7 +387,6 @@ function resetBall(ball, world, width, height) {
356387
     return ball;
357388
 }
358389
 
359
-// ============= COLLISION =============
360390
 // ============= COLLISION =============
361391
 function setupCollisionHandlers(engine, ball, leftPaddle, rightPaddle, particles) {
362392
     const Body = Matter.Body;
@@ -507,4 +537,88 @@ function setupCollisionHandlers(engine, ball, leftPaddle, rightPaddle, particles
507537
             }
508538
         }
509539
     });
540
+}
541
+
542
+// ============= ROTATION SYSTEM =============
543
+function handleRotationInput() {
544
+    // Left paddle rotation (A/D keys)
545
+    let leftRotationInput = 0;
546
+    if (keys['a'] || keys['A']) leftRotationInput -= 1;
547
+    if (keys['d'] || keys['D']) leftRotationInput += 1;
548
+    
549
+    // Right paddle rotation (Left/Right arrows, only if AI disabled)
550
+    let rightRotationInput = 0;
551
+    if (!aiEnabled) {
552
+        if (keys['ArrowLeft']) rightRotationInput -= 1;
553
+        if (keys['ArrowRight']) rightRotationInput += 1;
554
+    }
555
+    
556
+    // Update rotation states
557
+    updateRotationPhysics('left', leftRotationInput, leftPaddle);
558
+    if (!aiEnabled) {
559
+        updateRotationPhysics('right', rightRotationInput, rightPaddle);
560
+    }
561
+}
562
+
563
+function updateRotationPhysics(side, input, paddle) {
564
+    const Body = Matter.Body;
565
+    let state = rotationState[side];
566
+    
567
+    // Smooth the input
568
+    state.inputBuffer = lerp(state.inputBuffer, input, ROTATION_SMOOTHING);
569
+    
570
+    // Calculate resistance based on momentum
571
+    let rotatingWithMomentum = (state.inputBuffer * state.angularVelocity) > 0;
572
+    let effectiveInput = state.inputBuffer;
573
+    
574
+    if (rotatingWithMomentum && Math.abs(state.inputBuffer) > 0.1) {
575
+        // Easier to rotate with momentum
576
+        effectiveInput *= ROTATION_WITH_MOMENTUM_BOOST;
577
+    } else if (!rotatingWithMomentum && Math.abs(state.inputBuffer) > 0.1) {
578
+        // Harder to rotate against momentum
579
+        effectiveInput *= ROTATION_AGAINST_MOMENTUM_LAG;
580
+    }
581
+    
582
+    // Apply torque based on input
583
+    let torque = effectiveInput * ROTATION_SPEED;
584
+    
585
+    // Update angular velocity with torque
586
+    state.angularVelocity += torque;
587
+    
588
+    // Apply damping
589
+    state.angularVelocity *= ROTATION_DAMPING;
590
+    
591
+    // Limit maximum angular velocity
592
+    state.angularVelocity = Math.max(-ROTATION_MAX_SPEED, 
593
+                                    Math.min(ROTATION_MAX_SPEED, state.angularVelocity));
594
+    
595
+    // Apply return-to-center force when no input
596
+    if (Math.abs(state.inputBuffer) < 0.1) {
597
+        let returnForce = -state.currentAngle * ROTATION_RETURN_FORCE;
598
+        state.angularVelocity += returnForce;
599
+    }
600
+    
601
+    // Update current angle
602
+    state.currentAngle += state.angularVelocity;
603
+    
604
+    // Limit maximum rotation angle
605
+    state.currentAngle = Math.max(-ROTATION_MAX_ANGLE, 
606
+                                 Math.min(ROTATION_MAX_ANGLE, state.currentAngle));
607
+    
608
+    // Apply rotation to the paddle body
609
+    Body.setAngle(paddle, state.currentAngle);
610
+    
611
+    // Update angular momentum for next frame
612
+    state.angularMomentum = state.angularMomentum * ROTATION_MOMENTUM + 
613
+                           state.angularVelocity * (1 - ROTATION_MOMENTUM);
614
+    
615
+    // Track last direction for momentum calculations
616
+    if (Math.abs(input) > 0.1) {
617
+        state.lastDirection = Math.sign(input);
618
+    }
619
+}
620
+
621
+// ============= HELPER FUNCTIONS =============
622
+function lerp(start, stop, amt) {
623
+    return amt * (stop - start) + start;
510624
 }
js/rendering.jsmodified
@@ -344,32 +344,38 @@ function drawDebugInfo(ball, leftSupport, leftPaddle, rightSupport, rightPaddle,
344344
     text(`R Spring: ${Math.round(rightSpringLength)}px (${((SPRING_LENGTH/rightSpringLength - 1) * 100).toFixed(0)}%)`, 10, 95);
345345
     text(`Input: L=${inputBuffer.left.toFixed(2)} R=${inputBuffer.right.toFixed(2)}`, 10, 110);
346346
     
347
+    // Rotation info
348
+    if (window.rotationState) {
349
+        text(`L Rot: ${(window.rotationState.left.currentAngle * 180 / Math.PI).toFixed(1)}° (vel: ${window.rotationState.left.angularVelocity.toFixed(3)})`, 10, 125);
350
+        text(`R Rot: ${(window.rotationState.right.currentAngle * 180 / Math.PI).toFixed(1)}° (vel: ${window.rotationState.right.angularVelocity.toFixed(3)})`, 10, 140);
351
+    }
352
+    
347353
     // AI debug info
348354
     if (aiEnabled) {
349
-        text(`AI State: ${aiState.mode} | Aggression: ${aiState.aggressionLevel.toFixed(2)}`, 10, 125);
350
-        text(`Target: ${Math.round(aiState.targetY)} | Intercept: ${Math.round(aiState.interceptY)}`, 10, 140);
351
-        text(`Ball: (${Math.round(ball.position.x)}, ${Math.round(ball.position.y)}) Vel: (${ball.velocity.x.toFixed(1)}, ${ball.velocity.y.toFixed(1)})`, 10, 155);
355
+        text(`AI State: ${aiState.mode} | Aggression: ${aiState.aggressionLevel.toFixed(2)}`, 10, 155);
356
+        text(`Target: ${Math.round(aiState.targetY)} | Intercept: ${Math.round(aiState.interceptY)}`, 10, 170);
357
+        text(`Ball: (${Math.round(ball.position.x)}, ${Math.round(ball.position.y)}) Vel: (${ball.velocity.x.toFixed(1)}, ${ball.velocity.y.toFixed(1)})`, 10, 185);
352358
         
353359
         // AI technique indicators
354360
         if (aiState.mode === 'WINDING_UP') {
355361
             fill(255, 150, 50, 200);
356
-            text(`AI WINDING UP | Phase: ${(aiState.windupPhase % (Math.PI * 2)).toFixed(2)} | Velocity: ${aiState.currentVelocity.toFixed(1)}`, 10, 175);
362
+            text(`AI WINDING UP | Phase: ${(aiState.windupPhase % (Math.PI * 2)).toFixed(2)} | Velocity: ${aiState.currentVelocity.toFixed(1)}`, 10, 205);
357363
             
358364
             if (aiState.comboBop) {
359365
                 fill(255, 50, 255, 200);
360
-                text("⚡ COMBO PLANNED!", 10, 190);
366
+                text("⚡ COMBO PLANNED!", 10, 220);
361367
             }
362368
         } else if (aiState.mode === 'SWINGING') {
363369
             fill(255, 50, 50, 200);
364
-            text("AI POWER SWING!", 10, 175);
370
+            text("AI POWER SWING!", 10, 205);
365371
         } else if (aiState.consideringBop) {
366372
             fill(255, 255, 100, 200);
367
-            text("AI PREPARING BOP!", 10, 175);
373
+            text("AI PREPARING BOP!", 10, 205);
368374
         }
369375
         
370376
         if (bopState.right.active) {
371377
             fill(255, 255, 0, 255);
372
-            text("AI BOPPING!", 10, 190);
378
+            text("AI BOPPING!", 10, 220);
373379
         }
374380
     }
375381
 }
@@ -382,10 +388,11 @@ function drawStartMessage(aiEnabled, aiDifficulty) {
382388
     textSize(14);
383389
     
384390
     if (aiEnabled) {
385
-        text("Player vs CPU | Left paddle: W/S or Mouse/Touch", width/2, height/2 + 125);
391
+        text("Player vs CPU | Move: W/S or Mouse/Touch | Rotate: A/D | Bop: Left Shift", width/2, height/2 + 125);
386392
         text(`AI Difficulty: ${aiDifficulty.toUpperCase()}`, width/2, height/2 + 145);
387393
     } else {
388
-        text("2 Player Mode | P1: W/S | P2: ↑/↓ | Mouse/Touch: Drag paddles", width/2, height/2 + 125);
394
+        text("2 Player Mode | P1: W/S + A/D + L.Shift | P2: ↑/↓ + ←/→ + Enter", width/2, height/2 + 125);
395
+        text("Mouse/Touch: Drag paddles", width/2, height/2 + 145);
389396
     }
390397
     
391398
     textSize(12);
@@ -451,9 +458,9 @@ function drawMenu(menuState) {
451458
     textSize(12);
452459
     fill(255, 100);
453460
     if (menuState.selectedOption === 0) {
454
-        text("Controls: W/S keys + LEFT SHIFT (bop) or Mouse/Touch", width/2, height - 30);
461
+        text("Controls: W/S (move) + A/D (rotate) + LEFT SHIFT (bop) or Mouse/Touch", width/2, height - 30);
455462
     } else {
456
-        text("Controls: P1 (W/S + L.Shift) | P2 (↑/↓ + Enter) | Mouse/Touch", width/2, height - 30);
463
+        text("P1: W/S + A/D + L.Shift | P2: ↑/↓ + ←/→ + Enter | Mouse/Touch", width/2, height - 30);
457464
     }
458465
 }
459466
 
js/sprong.jsmodified
@@ -49,6 +49,7 @@ let mouseInput = {
4949
 window.inputBuffer = inputBuffer;
5050
 window.moveSupportEnhanced = moveSupportEnhanced;
5151
 window.ball = null;
52
+window.rotationState = rotationState;
5253
 
5354
 function setup() {
5455
     let canvas = createCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
@@ -125,6 +126,7 @@ function draw() {
125126
 function handleEnhancedInput() {
126127
     handleKeyboardInput();
127128
     handleMouseTouchInput();
129
+    handleRotationInput();  // Add rotation handling
128130
     handleBopInput(keys, aiEnabled, millis(), leftPaddle, rightPaddle, 
129131
                    leftSupport, rightSupport, engine, particles);
130132