@@ -41,11 +41,11 @@ const IMPACT_PARTICLES = 8; |
| 41 | 41 | const SPRING_PARTICLE_RATE = 0.3; |
| 42 | 42 | |
| 43 | 43 | // Bop system constants |
| 44 | | -const BOP_FORCE = 0.2; // self explanatory. BOP it. |
| 45 | | -const BOP_RANGE = 40; // also self explanatory. TWIST it. |
| 46 | | -const BOP_DURATION = 1500; // traversal duration. SHAKE it. |
| 47 | | -const BOP_COOLDOWN = 500; // also also self expl. PULL it. |
| 48 | | -const ANCHOR_RECOIL = 40; // How far the anchor moves backward during bop |
| 44 | +const BOP_FORCE = 1.0; // self explanatory. BOP it. |
| 45 | +const BOP_RANGE = 500; // also self explanatory. TWIST it. |
| 46 | +const BOP_DURATION = 1000; // traversal duration. SHAKE it. |
| 47 | +const BOP_COOLDOWN = 0; // also also self expl. PULL it. |
| 48 | +const ANCHOR_RECOIL = 60; // How far the anchor moves backward during bop |
| 49 | 49 | const BOP_VELOCITY_BOOST = 5; // Initial velocity boost for paddle |
| 50 | 50 | |
| 51 | 51 | // ============= BOP SYSTEM ============= |
@@ -74,8 +74,9 @@ function handleBopInput(keys, aiEnabled, currentTime, leftPaddle, rightPaddle, l |
| 74 | 74 | // Left player bop - use Left Shift for both modes |
| 75 | 75 | let leftBopPressed = keys['Shift'] && !keys['Control']; |
| 76 | 76 | |
| 77 | + // BOP_COOLDOWN controls the minimum time between bops |
| 77 | 78 | if (leftBopPressed && !bopState.left.active && |
| 78 | | - currentTime - bopState.left.lastBopTime > bopState.left.cooldown) { |
| 79 | + currentTime - bopState.left.lastBopTime > BOP_COOLDOWN) { |
| 79 | 80 | activateBop('left', currentTime, leftPaddle, leftSupport, engine, particles); |
| 80 | 81 | } |
| 81 | 82 | |
@@ -83,8 +84,9 @@ function handleBopInput(keys, aiEnabled, currentTime, leftPaddle, rightPaddle, l |
| 83 | 84 | if (!aiEnabled) { |
| 84 | 85 | let rightBopPressed = keys['Enter']; |
| 85 | 86 | |
| 87 | + // BOP_COOLDOWN controls the minimum time between bops |
| 86 | 88 | if (rightBopPressed && !bopState.right.active && |
| 87 | | - currentTime - bopState.right.lastBopTime > bopState.right.cooldown) { |
| 89 | + currentTime - bopState.right.lastBopTime > BOP_COOLDOWN) { |
| 88 | 90 | activateBop('right', currentTime, rightPaddle, rightSupport, engine, particles); |
| 89 | 91 | } |
| 90 | 92 | } |
@@ -109,32 +111,35 @@ function activateBop(side, currentTime, paddle, support, engine, particles) { |
| 109 | 111 | if (magnitude > 0) { |
| 110 | 112 | dx /= magnitude; |
| 111 | 113 | dy /= magnitude; |
| 112 | | - // Calculate anchor recoil distance |
| 113 | | - let anchorRecoilDistance = ANCHOR_RECOIL * 0.3; |
| 114 | + |
| 115 | + // ANCHOR_RECOIL now properly controls the recoil distance |
| 116 | + let anchorRecoilDistance = ANCHOR_RECOIL * 0.3; // Can adjust the 0.3 multiplier |
| 114 | 117 | |
| 115 | | - // Move support and paddle in one solver step (no teleport → no ghost collisions) |
| 118 | + // Move support and paddle backward together |
| 116 | 119 | Body.translate(support, { x: -dx * anchorRecoilDistance, y: -dy * anchorRecoilDistance }); |
| 117 | 120 | Body.translate(paddle, { x: -dx * anchorRecoilDistance, y: -dy * anchorRecoilDistance }); |
| 118 | 121 | |
| 119 | 122 | // Remember where the support started so we can ease it back later |
| 120 | | - const preSupportPos = { x: support.position.x + dx * anchorRecoilDistance, |
| 121 | | - y: support.position.y + dy * anchorRecoilDistance }; |
| 122 | | - bopState[side].originalPos = preSupportPos; |
| 123 | + bopState[side].originalPos = { |
| 124 | + x: support.position.x + dx * anchorRecoilDistance, |
| 125 | + y: support.position.y + dy * anchorRecoilDistance |
| 126 | + }; |
| 123 | 127 | |
| 124 | | - // Now apply forward thrust from this new position |
| 125 | | - let forwardSpeed = BOP_VELOCITY_BOOST * 1.0; // Restored to full power |
| 128 | + // BOP_VELOCITY_BOOST controls the initial forward velocity |
| 129 | + let forwardSpeed = BOP_VELOCITY_BOOST; |
| 126 | 130 | Body.setVelocity(paddle, { |
| 127 | 131 | x: paddle.velocity.x + dx * forwardSpeed, |
| 128 | 132 | y: paddle.velocity.y + dy * forwardSpeed |
| 129 | 133 | }); |
| 130 | 134 | |
| 131 | | - // Apply a forward force for continued acceleration |
| 135 | + // BOP_FORCE controls the sustained forward thrust |
| 136 | + // Combined with BOP_RANGE for the total force applied |
| 132 | 137 | Body.applyForce(paddle, paddle.position, { |
| 133 | | - x: dx * bopState[side].power * BOP_RANGE * 0.08, |
| 134 | | - y: dy * bopState[side].power * BOP_RANGE * 0.08 |
| 138 | + x: dx * BOP_FORCE * BOP_RANGE * 0.002, // Scaled down for Matter.js |
| 139 | + y: dy * BOP_FORCE * BOP_RANGE * 0.002 |
| 135 | 140 | }); |
| 136 | 141 | |
| 137 | | - // Create particle burst for visual feedback at the support position |
| 142 | + // Create particle burst for visual feedback |
| 138 | 143 | for (let i = 0; i < 5; i++) { |
| 139 | 144 | let angle = Math.atan2(dy, dx) + (Math.random() - 0.5) * 0.5; |
| 140 | 145 | let speed = Math.random() * 4 + 2; |
@@ -152,7 +157,7 @@ function activateBop(side, currentTime, paddle, support, engine, particles) { |
| 152 | 157 | } |
| 153 | 158 | } |
| 154 | 159 | |
| 155 | | - console.log(side + " player BOP!"); |
| 160 | + console.log(`${side} player BOP! Duration: ${BOP_DURATION}ms, Cooldown: ${BOP_COOLDOWN}ms`); |
| 156 | 161 | } |
| 157 | 162 | |
| 158 | 163 | function updateBopStates(currentTime, leftSupport, rightSupport, leftPaddle, rightPaddle) { |
@@ -161,11 +166,12 @@ function updateBopStates(currentTime, leftSupport, rightSupport, leftPaddle, rig |
| 161 | 166 | // Update left bop |
| 162 | 167 | if (bopState.left.active) { |
| 163 | 168 | let elapsed = currentTime - bopState.left.startTime; |
| 164 | | - let progress = elapsed / bopState.left.duration; |
| 169 | + let progress = elapsed / BOP_DURATION; // BOP_DURATION controls how long the effect lasts |
| 165 | 170 | |
| 166 | 171 | if (progress >= 1.0) { |
| 167 | 172 | bopState.left.active = false; |
| 168 | 173 | bopState.left.originalPos = null; |
| 174 | + console.log("Left bop ended after", elapsed, "ms"); |
| 169 | 175 | } else { |
| 170 | 176 | if (bopState.left.originalPos) { |
| 171 | 177 | let support = leftSupport; |
@@ -187,11 +193,12 @@ function updateBopStates(currentTime, leftSupport, rightSupport, leftPaddle, rig |
| 187 | 193 | // Update right bop (same logic) |
| 188 | 194 | if (bopState.right.active) { |
| 189 | 195 | let elapsed = currentTime - bopState.right.startTime; |
| 190 | | - let progress = elapsed / bopState.right.duration; |
| 196 | + let progress = elapsed / BOP_DURATION; // BOP_DURATION controls how long the effect lasts |
| 191 | 197 | |
| 192 | 198 | if (progress >= 1.0) { |
| 193 | 199 | bopState.right.active = false; |
| 194 | 200 | bopState.right.originalPos = null; |
| 201 | + console.log("Right bop ended after", elapsed, "ms"); |
| 195 | 202 | } else { |
| 196 | 203 | if (bopState.right.originalPos) { |
| 197 | 204 | let support = rightSupport; |
@@ -216,6 +223,7 @@ function limitBopRange(support, paddle) { |
| 216 | 223 | let currentDistance = dist(support.position.x, support.position.y, |
| 217 | 224 | paddle.position.x, paddle.position.y); |
| 218 | 225 | |
| 226 | + // BOP_RANGE controls the maximum extension allowed |
| 219 | 227 | let maxDistance = SPRING_LENGTH + BOP_RANGE; |
| 220 | 228 | if (currentDistance > maxDistance) { |
| 221 | 229 | let dx = paddle.position.x - support.position.x; |
@@ -225,11 +233,14 @@ function limitBopRange(support, paddle) { |
| 225 | 233 | dx /= magnitude; |
| 226 | 234 | dy /= magnitude; |
| 227 | 235 | |
| 236 | + // Clamp paddle position to max range |
| 228 | 237 | let newX = support.position.x + dx * maxDistance; |
| 229 | 238 | let newY = support.position.y + dy * maxDistance; |
| 230 | 239 | |
| 231 | 240 | let currentVel = paddle.velocity; |
| 232 | 241 | Body.setPosition(paddle, { x: newX, y: newY }); |
| 242 | + |
| 243 | + // Dampen velocity when hitting the range limit |
| 233 | 244 | Body.setVelocity(paddle, { |
| 234 | 245 | x: currentVel.x * 0.7, |
| 235 | 246 | y: currentVel.y * 0.7 |