User prompt
Please fix the bug: 'ReferenceError: Can't find variable: targetY' in or related to this line: 'self.y = targetY; // Force position to exactly match wave on landing' Line Number: 508
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: targetY' in or related to this line: 'self.y = targetY; // Force position to exactly match wave on landing' Line Number: 508
User prompt
Update surfer as needed with: // Debug counter to see multiple transitions var landingCount = 0; function updateRotation(aboveWave) { // Debug logs if (currentRotationState === ROTATION_STATES.RECOVERING || currentRotationState === ROTATION_STATES.FLIPPING) { console.log('Frame:', LK.ticks, 'State:', currentRotationState, 'Above:', aboveWave, 'VelocityY:', velocityY, 'Landing Count:', landingCount); } // Handle trick and landing as a single sequence switch(currentRotationState) { case ROTATION_STATES.FLIPPING: var velocityFactor = Math.min(Math.abs(velocityY) / 20, 1); var rotationSpeed = MIN_ROTATION_SPEED + (MAX_ROTATION_SPEED - MIN_ROTATION_SPEED) * velocityFactor; rotationData.trickRotation += rotationSpeed; rotationData.totalRotation += rotationSpeed; self.rotation = rotationData.trickRotation; // Check for landing if (!aboveWave) { landingCount++; console.log('Landing initiated:', landingCount); currentRotationState = ROTATION_STATES.RECOVERING; // Force position to exactly match wave on landing self.y = targetY; velocityY = 0; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: // Stay in recovery until rotation is complete, regardless of position var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { console.log('Recovery complete, landing count:', landingCount); currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; landingCount = 0; // Reset counter // Force proper wave riding position self.y = targetY; velocityY = 0; } else { self.rotation += diff * 0.1; } break; case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 10 && airTime > 10) { console.log('Starting new trick sequence'); currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; landingCount = 0; // Reset counter for new trick } else { // Normal wave riding rotation var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (Math.abs(verticalSpeed) > 5) { if (verticalSpeed < -2) { verticalRotation = Math.min(0.2, -verticalSpeed * 0.003); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003); } } var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation; self.rotation += (targetRotation - self.rotation) * 0.1; } break; } } self.update = function() { // ... existing update code ... // Force position during recovery if (currentRotationState === ROTATION_STATES.RECOVERING) { self.y = targetY; velocityY = 0; }
User prompt
Update the surfer with: var groundContact = false; var lastGroundContact = false; function updateRotation(aboveWave) { // Track ground contact changes lastGroundContact = groundContact; groundContact = !aboveWave; // Debug our state transitions if (LK.ticks % 10 === 0) { console.log('State:', currentRotationState, 'Ground:', groundContact, 'LastGround:', lastGroundContact); } switch(currentRotationState) { case ROTATION_STATES.FLIPPING: var velocityFactor = Math.min(Math.abs(velocityY) / 20, 1); var rotationSpeed = MIN_ROTATION_SPEED + (MAX_ROTATION_SPEED - MIN_ROTATION_SPEED) * velocityFactor; rotationData.trickRotation += rotationSpeed; rotationData.totalRotation += rotationSpeed; self.rotation = rotationData.trickRotation; // Only transition to recovering on first ground contact if (groundContact && !lastGroundContact) { currentRotationState = ROTATION_STATES.RECOVERING; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); // Only complete recovery once we're very close to target if (Math.abs(diff) < 0.01 && groundContact) { currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; } else { self.rotation += diff * 0.1; } break; case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 10 && airTime > 10) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (Math.abs(verticalSpeed) > 5) { if (verticalSpeed < -2) { verticalRotation = Math.min(0.2, -verticalSpeed * 0.003); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003); } } var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation; self.rotation += (targetRotation - self.rotation) * 0.1; } break; } } });
User prompt
Update surfer as needed with: var isLanding = false; var landingStartRotation = 0; function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.FLIPPING: // Calculate rotation speed based on initial upward velocity var velocityFactor = Math.min(Math.abs(velocityY) / 20, 1); var rotationSpeed = MIN_ROTATION_SPEED + (MAX_ROTATION_SPEED - MIN_ROTATION_SPEED) * velocityFactor; rotationData.trickRotation += rotationSpeed; rotationData.totalRotation += rotationSpeed; self.rotation = rotationData.trickRotation; if (!aboveWave && !isLanding) { isLanding = true; landingStartRotation = self.rotation; currentRotationState = ROTATION_STATES.RECOVERING; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; isLanding = false; // Reset landing flag } else { self.rotation += diff * 0.1; // Slower recovery } break; case ROTATION_STATES.NORMAL: isLanding = false; // Ensure flag is reset // ... rest of normal state ... break;
User prompt
Update surfer as needed with: var BASE_GRAVITY = 1.2; // Reduced gravity for more hang time var DAMPENING = 0.995; // Less dampening for more momentum var JUMP_BOOST = 1.5; // Multiplier for upward velocity var MIN_ROTATION_SPEED = 0.15; // Base rotation speed var MAX_ROTATION_SPEED = 0.4; // Max rotation speed // ... existing initializations ... self.update = function() { // ... existing wave calculations ... // Enhanced physics for more air if (aboveWave) { airTime++; // If we're going up, boost the velocity if (velocityY < 0) { velocityY *= JUMP_BOOST; } velocityY += BASE_GRAVITY; velocityY *= DAMPENING; // Debug if (LK.ticks % 10 === 0) { console.log('Air time:', airTime, 'VelocityY:', velocityY); } } else { airTime = 0; self.y = targetY; velocityY *= 0.8; } // ... rest of update ... function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: // ... existing normal state code ... break; case ROTATION_STATES.FLIPPING: // Calculate rotation speed based on initial upward velocity var velocityFactor = Math.min(Math.abs(velocityY) / 20, 1); // Normalize velocity var rotationSpeed = MIN_ROTATION_SPEED + (MAX_ROTATION_SPEED - MIN_ROTATION_SPEED) * velocityFactor; rotationData.trickRotation += rotationSpeed; rotationData.totalRotation += rotationSpeed; self.rotation = rotationData.trickRotation; if (!aboveWave) { // ... existing landing code ... } break;
User prompt
Update as needed with: case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 10 && airTime > 10) { console.log('Starting trick!'); currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (Math.abs(verticalSpeed) > 5) { if (verticalSpeed < -2) { verticalRotation = Math.min(0.2, -verticalSpeed * 0.003); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003); } } var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation; // Smoother interpolation after landing var lerpSpeed = currentRotationState === ROTATION_STATES.RECOVERING ? 0.05 : 0.1; self.rotation += (targetRotation - self.rotation) * lerpSpeed; } break;
User prompt
Update surfer as needed with: case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { // Don't immediately set rotation when transitioning to NORMAL // Just change the state and let NORMAL state handle it smoothly currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; } else { self.rotation += diff * 0.15; // Slower recovery } break;
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: inWaterContact' in or related to this line: 'if (inWaterContact) {' Line Number: 545
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: inWaterContact' in or related to this line: 'if (inWaterContact) {' Line Number: 545
User prompt
Update surfer as needed with: // Modify constants var BASE_GRAVITY = 1.5; var MAX_AIR_VELOCITY = 25; // Changed to positive since we're falling var DAMPENING = 0.99; // Less dampening var WAVE_TOLERANCE = 2; // Tighter tolerance var TRICK_HEIGHT_THRESHOLD = 50; // Lower threshold for testing // Add debug variable var airTime = 0; self.update = function() { if (!waveSystem) return; // ... existing wave point calculations ... var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET; // Simpler above wave check var aboveWave = self.y < targetY; // Physics update if (aboveWave) { airTime++; velocityY += BASE_GRAVITY; velocityY *= DAMPENING; // Remove MAX_AIR_VELOCITY for now // Debug log if (LK.ticks % 10 === 0) { console.log('Air time:', airTime, 'VelocityY:', velocityY, 'Height:', self.y); } } else { airTime = 0; self.y = targetY; velocityY *= 0.8; } // Update position self.y += velocityY; function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: // Simplified trick check if (aboveWave && velocityY > 10 && airTime > 10) { // Need some air time console.log('Starting trick!'); currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { // ... existing normal rotation code ... } break; case ROTATION_STATES.FLIPPING: rotationData.trickRotation += 0.15; rotationData.totalRotation += 0.15; self.rotation = rotationData.trickRotation; if (!aboveWave) { currentRotationState = ROTATION_STATES.RECOVERING; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; // ... keep RECOVERING state the same ... } } // Update rotation state updateRotation(aboveWave); lastWaveY = targetY; };
User prompt
Update surfer as needed with: var TRICK_HEIGHT_THRESHOLD = 100; var initialJumpY = 0; var wasAboveWave = false; function updateRotation(aboveWave) { // Debug log outside switch to see all values if (aboveWave) { console.log('State:', currentRotationState, 'VelocityY:', velocityY, 'Height diff:', initialJumpY - self.y); } // Handle jump height tracking outside of state machine if (aboveWave && !wasAboveWave) { initialJumpY = self.y; } else if (!aboveWave) { initialJumpY = 0; } switch(currentRotationState) { case ROTATION_STATES.NORMAL: // Simplified trick check if (aboveWave && velocityY > 0) { if ((initialJumpY - self.y) > TRICK_HEIGHT_THRESHOLD) { console.log('Starting trick!'); currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (Math.abs(verticalSpeed) > 5) { if (verticalSpeed < -2) { verticalRotation = Math.min(0.2, -verticalSpeed * 0.003); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003); } } var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation; self.rotation += (targetRotation - self.rotation) * 0.1; } break; case ROTATION_STATES.FLIPPING: rotationData.trickRotation += 0.15; rotationData.totalRotation += 0.15; self.rotation = rotationData.trickRotation; if (!aboveWave) { currentRotationState = ROTATION_STATES.RECOVERING; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break;
User prompt
Update surfer as needed with: var TRICK_HEIGHT_THRESHOLD = 100; var initialJumpY = 0; var wasAboveWave = false; // Add this to track state change function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: // Only set initial height when first leaving wave if (aboveWave && !wasAboveWave) { initialJumpY = self.y; } else if (!aboveWave) { // Reset when touching wave initialJumpY = 0; } // Debug log to see what's happening if (aboveWave && velocityY > 0) { console.log('Height diff:', initialJumpY - self.y); } if (aboveWave && velocityY > 0 && (initialJumpY - self.y) > TRICK_HEIGHT_THRESHOLD) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { // ... existing normal rotation code ... } break; // ... other states stay the same ... } // Update wasAboveWave at the end wasAboveWave = aboveWave; }
User prompt
Update surfer as needed with: // Add with other constants var TRICK_HEIGHT_THRESHOLD = 100; // Minimum height fallen before trick allowed var initialJumpY = 0; // Track height where we left the wave function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: if (aboveWave) { // Record height when leaving wave initialJumpY = self.y; } else { // Reset when touching wave initialJumpY = 0; } // Only enter flip state if we've fallen far enough if (aboveWave && velocityY > 0 && (initialJumpY - self.y) > TRICK_HEIGHT_THRESHOLD) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else {
User prompt
Update surfer class as needed with: // Add threshold constants at the top with other constants var WAVE_TOLERANCE = 5; // Buffer zone for wave contact var SPLASH_VELOCITY_THRESHOLD = 15; // Minimum velocity for splash function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: // Add dampening to vertical rotation var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (Math.abs(verticalSpeed) > 5) { // Add threshold for rotation change if (verticalSpeed < -2) { verticalRotation = Math.min(0.2, -verticalSpeed * 0.003); // Reduced multiplier } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003); // Reduced multiplier } } // Smooth rotation transition var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation; self.rotation += (targetRotation - self.rotation) * 0.1; // Smooth interpolation break; // ... keep other states the same ... } } self.update = function() { if (!waveSystem) return; // ... keep existing wave point calculations ... var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET; // Add tolerance zone for wave contact var aboveWave = self.y < targetY - WAVE_TOLERANCE; var inWaterContact = Math.abs(self.y - targetY) <= WAVE_TOLERANCE; // Physics update with smoother transitions if (aboveWave) { velocityY += BASE_GRAVITY; velocityY *= DAMPENING; if (velocityY < MAX_AIR_VELOCITY) { velocityY = MAX_AIR_VELOCITY; } } else if (inWaterContact) { // Smooth transition when near water var waterForce = (targetY - self.y) * 0.1; velocityY += waterForce; velocityY *= 0.95; // Additional dampening in water } else { // Below water surface self.y = targetY; velocityY *= 0.8; } // Update position self.y += velocityY; // Update rotation state updateRotation(aboveWave); // More controlled particle triggers if (inWaterContact) { createTrail(); // Only create splash on hard impacts if (velocityY > SPLASH_VELOCITY_THRESHOLD) { createSplash(); } } lastWaveY = targetY; };
User prompt
Replace surfer class with: var Surfer = Container.expand(function() { var self = Container.call(this); // Constants var BASE_GRAVITY = 1.5; var MAX_SPEED = 40; var DAMPENING = 0.98; var WAVE_OFFSET = -30; var FIXED_X = 2048 * 0.35; var MAX_AIR_VELOCITY = -25; // State management var ROTATION_STATES = { NORMAL: 'normal', FLIPPING: 'flipping', RECOVERING: 'recovering' }; var currentRotationState = ROTATION_STATES.NORMAL; var rotationData = { baseRotation: -0.1, trickRotation: 0, totalRotation: 0, recoveryTarget: 0 }; // Physics variables var velocityY = 0; var lastWaveY = 2732 * 0.85; var initialized = false; // Setup surfer graphics var surferGraphics = self.attachAsset('surfer', { anchorX: 0.5, anchorY: 0.8 }); // Initial position self.x = FIXED_X; self.y = lastWaveY + WAVE_OFFSET; // Helper functions function normalizeRotation(rotation) { return rotation % (Math.PI * 2); } function showScorePopup(points) { var scorePopup = new Text2("+" + points, { size: 40, fill: 0xFFFFFF }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = self.x; scorePopup.y = self.y; game.addChild(scorePopup); tween(scorePopup, { y: scorePopup.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function() { scorePopup.destroy(); } }); } function createSplash() { for (var i = 0; i < 50; i++) { game.particles.addWaterParticle(FIXED_X, self.y + 40, 'splash'); } } function createTrail() { for (var i = 0; i < 4; i++) { game.particles.addWaterParticle(FIXED_X, self.y, 'trail'); } } function updateRotation(aboveWave) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 0) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (verticalSpeed < -2) { verticalRotation = Math.min(0.3, -verticalSpeed * 0.005); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.4, -verticalSpeed * 0.005); } self.rotation = rotationData.baseRotation + waveRotation + verticalRotation; } break; case ROTATION_STATES.FLIPPING: rotationData.trickRotation += 0.15; rotationData.totalRotation += 0.15; self.rotation = rotationData.trickRotation; if (!aboveWave) { currentRotationState = ROTATION_STATES.RECOVERING; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; } else { self.rotation += diff * 0.2; } break; } } // Wave system setup self.setWaveSystem = function(ws) { waveSystem = ws; if (!waveSystem.points) { waveSystem.points = []; } initialized = true; }; // Main update function self.update = function() { if (!waveSystem) return; var normalizedX = self.x / 2048; var pointIndex = Math.floor(normalizedX * (waveSystem.points.length - 1)); var nextPointIndex = Math.min(pointIndex + 1, waveSystem.points.length - 1); var progress = normalizedX * (waveSystem.points.length - 1) - pointIndex; var currentPoint = waveSystem.points[pointIndex]; var nextPoint = waveSystem.points[nextPointIndex]; if (!currentPoint || !nextPoint) return; var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET; var aboveWave = self.y < targetY; // Physics update if (aboveWave) { velocityY += BASE_GRAVITY; velocityY *= DAMPENING; if (velocityY < MAX_AIR_VELOCITY) { velocityY = MAX_AIR_VELOCITY; } } else { if (self.y > targetY) { self.y = targetY; velocityY = 0; } } // Update position self.y += velocityY; // Update rotation state updateRotation(aboveWave); // Create trail when on water if (!aboveWave) { createTrail(); } lastWaveY = targetY; }; self.getScore = function() { return Math.floor(score); }; return self; }); ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: velocityY' in or related to this line: 'if (aboveWave && velocityY > 0) {' Line Number: 393
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'currentPoint.y')' in or related to this line: 'var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress;' Line Number: 442
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: targetY' in or related to this line: 'var aboveWave = self.y < targetY;' Line Number: 441
User prompt
Please fix the bug: 'surfer.setWaveSystem is not a function. (In 'surfer.setWaveSystem(waveSystem)', 'surfer.setWaveSystem' is undefined)' in or related to this line: 'surfer.setWaveSystem(waveSystem);' Line Number: 856
User prompt
Update surfer only as needed with: var Surfer = Container.expand(function() { var self = Container.call(this); // Constants and state at class level var ROTATION_STATES = { NORMAL: 'normal', FLIPPING: 'flipping', RECOVERING: 'recovering' }; var currentRotationState = ROTATION_STATES.NORMAL; var rotationData = { baseRotation: -0.1, trickRotation: 0, totalRotation: 0, recoveryTarget: 0 }; // Helper functions within the class scope function normalizeRotation(rotation) { return rotation % (Math.PI * 2); } function showScorePopup(points) { var scorePopup = new Text2("+" + points, { size: 40, fill: 0xFFFFFF }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = self.x; scorePopup.y = self.y; game.addChild(scorePopup); tween(scorePopup, { y: scorePopup.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function() { scorePopup.destroy(); } }); } function updateRotation(aboveWave, targetY) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 0) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (verticalSpeed < -2) { verticalRotation = Math.min(0.3, -verticalSpeed * 0.005); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.4, -verticalSpeed * 0.005); } self.rotation = rotationData.baseRotation + waveRotation + verticalRotation; } break; case ROTATION_STATES.FLIPPING: rotationData.trickRotation += 0.15; rotationData.totalRotation += 0.15; self.rotation = rotationData.trickRotation; if (!aboveWave) { currentRotationState = ROTATION_STATES.RECOVERING; var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; } else { self.rotation += diff * 0.2; } break; } } // Main update function attached to self self.update = function() { // Your existing update logic here... var normalizedX = self.x / 2048; var pointIndex = Math.floor(normalizedX * (waveSystem.points.length - 1)); // ... rest of position calculation ... var aboveWave = self.y < targetY; // Call our rotation update updateRotation(aboveWave, targetY); // Rest of update logic... }; return self; }); ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Update self.update in surfer class with: function updateRotation(aboveWave, targetY) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 0) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (verticalSpeed < -2) { verticalRotation = Math.min(0.3, -verticalSpeed * 0.005); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.4, -verticalSpeed * 0.005); } self.rotation = rotationData.baseRotation + waveRotation + verticalRotation; } break; case ROTATION_STATES.FLIPPING: rotationData.trickRotation += 0.15; rotationData.totalRotation += 0.15; self.rotation = rotationData.trickRotation; if (!aboveWave) { currentRotationState = ROTATION_STATES.RECOVERING; // Score the flips before starting recovery var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } // Start recovery tween rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; } else { self.rotation += diff * 0.2; } break; } } function normalizeRotation(rotation) { return rotation % (Math.PI * 2); } function showScorePopup(points) { var scorePopup = new Text2("+" + points, { size: 40, fill: 0xFFFFFF }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = self.x; scorePopup.y = self.y; game.addChild(scorePopup); tween(scorePopup, { y: scorePopup.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function() { scorePopup.destroy(); } }); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Update surfer class as needed with: var self = Container.call(this); var ROTATION_STATES = { NORMAL: 'normal', FLIPPING: 'flipping', RECOVERING: 'recovering' }; var currentRotationState = ROTATION_STATES.NORMAL; var rotationData = { baseRotation: -0.1, trickRotation: 0, totalRotation: 0, recoveryTarget: 0 };
User prompt
Update surfer class as needed with: // In the Surfer class var self = Container.call(this); var ROTATION_STATES = { NORMAL: 'normal', FLIPPING: 'flipping', RECOVERING: 'recovering' }; var currentRotationState = ROTATION_STATES.NORMAL; var rotationData = { baseRotation: -0.1, trickRotation: 0, totalRotation: 0, recoveryTarget: 0 }; // In update() function updateRotation(aboveWave, targetY) { switch(currentRotationState) { case ROTATION_STATES.NORMAL: if (aboveWave && velocityY > 0) { currentRotationState = ROTATION_STATES.FLIPPING; rotationData.trickRotation = self.rotation; } else { var waveRotation = Math.sin(LK.ticks / 30) * 0.05; var verticalSpeed = self.y - lastWaveY; var verticalRotation = 0; if (verticalSpeed < -2) { verticalRotation = Math.min(0.3, -verticalSpeed * 0.005); } else if (verticalSpeed > 2) { verticalRotation = Math.max(-0.4, -verticalSpeed * 0.005); } self.rotation = rotationData.baseRotation + waveRotation + verticalRotation; } break; case ROTATION_STATES.FLIPPING: rotationData.trickRotation += 0.15; rotationData.totalRotation += 0.15; self.rotation = rotationData.trickRotation; if (!aboveWave) { currentRotationState = ROTATION_STATES.RECOVERING; // Score the flips before starting recovery var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2)); if (completedFlips > 0) { score += completedFlips * 1000; showScorePopup(completedFlips * 1000); } // Start recovery tween rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation); createSplash(); } break; case ROTATION_STATES.RECOVERING: var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation); if (Math.abs(diff) < 0.01) { currentRotationState = ROTATION_STATES.NORMAL; rotationData.trickRotation = 0; rotationData.totalRotation = 0; } else { self.rotation += diff * 0.2; } break; } } function normalizeRotation(rotation) { return rotation % (Math.PI * 2); } function showScorePopup(points) { var scorePopup = new Text2("+" + points, { size: 40, fill: 0xFFFFFF }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = self.x; scorePopup.y = self.y; game.addChild(scorePopup); tween(scorePopup, { y: scorePopup.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function() { scorePopup.destroy(); } }); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Update surfer class with: if (wasAboveWave) { // Force valid position before any rotation changes self.y = Math.min(targetY, 2732); velocityY = 0; if (isDoingFlip) { isDoingFlip = false; isRecovering = true; // Enter recovery state // Calculate shortest path to recovery rotation var currentRot = self.rotation % (Math.PI * 2); var targetRot = -0.1; // Base rotation // Use tween for smooth recovery tween(self, { rotation: targetRot }, { duration: 500, easing: tween.elasticOut, onFinish: function() { isRecovering = false; trickRotation = 0; totalRotation = 0; lastFlipScore = 0; } }); // Create splash effect if landing with speed if (velocityY > 10) { createSplash(); } } } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestScore: 0
});
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Define BASE_Y constant
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudAlpha = 0.5 + Math.random() * 0.4; // Random alpha between 0.5 and 0.9
var cloudGraphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
alpha: cloudAlpha
});
cloudGraphics.scale.set(cloudAlpha, cloudAlpha); // Scale based on alpha
// Initialize cloud position
self.x = 2248; // Start off-screen right
self.y = Math.random() * (2732 * 0.33); // Top third of screen
self.speed = -2 - Math.random() * 2; // Random speed variation
self.update = function () {
self.x += self.speed;
// Remove if off screen
if (self.x < -self.width) {
self.destroy();
}
};
return self;
});
var Fish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('fish', {
anchorX: 0.5,
anchorY: 0.5
});
var randomScale = 0.5 + Math.random(); // Random scale between 0.5 and 1.5
fishGraphics.scale.set(randomScale, randomScale);
self.speed = -3 - Math.random() * 2; // Slower than seagulls
self.y = 2732 * (0.87 + Math.random() * 0.1); // Position between 87-97% of screen height
self.x = 2248; // Start off-screen right
// Use simple sine wave for animation instead of tweens
self.baseY = self.y;
self.startTime = LK.ticks;
self.update = function () {
self.x += self.speed;
// Smooth swimming motion using sine wave
self.y = self.baseY + Math.sin((LK.ticks - self.startTime) * 0.05) * 15;
fishGraphics.rotation = Math.sin((LK.ticks - self.startTime) * 0.1) * 0.1;
// Remove if off screen
if (self.x < -100) {
self.destroy();
}
};
return self;
});
var ParticleSystem = Container.expand(function () {
var self = Container.call(this);
self.addWaterParticle = function (x, y, type) {
var particle = ParticlePool.get();
if (type === 'trail') {
// Move spawn point up and behind surfer
particle.x = x - 100; // Spawn behind (to the right of) surfer
particle.y = y + 10; // Raised up from previous +90
} else {
// Keep original splash positioning
particle.x = x + Math.random() * 130 - 40;
particle.y = y - 20;
}
particle.init(type);
self.addChild(particle);
};
self.update = function () {
for (var i = self.children.length - 1; i >= 0; i--) {
var particle = self.children[i];
if (particle.update) {
particle.update();
}
// Remove particles that have moved far off screen
if (particle.x < -500 || particle.x > 2548 || particle.y < -500 || particle.y > 3232) {
ParticlePool["return"](particle);
self.removeChild(particle);
}
}
};
return self;
});
var Rock = Container.expand(function () {
var self = Container.call(this);
var rock = self.attachAsset('island', {
anchorX: 0.5,
anchorY: 1 // Anchor to top since we're stretching upward
});
// Set scales independently
rock.scaleX = 2;
rock.scaleY = 2; // Start with a base scale
self.checkCollision = function (surfer) {
var rockWidth = self.width;
var rockHeight = self.height;
var rockTop = self.y - rockHeight;
var points = [{
x: self.x,
y: rockTop
}, {
x: self.x - rockWidth * 0.4,
y: self.y - rockHeight * 0.1
}, {
x: self.x + rockWidth * 0.4,
y: self.y - rockHeight * 0.1
}];
var surferBox = {
x: surfer.x - 30,
y: surfer.y - 30,
width: 60,
height: 60
};
return isPointInTriangle(surferBox.x, surferBox.y, points) || isPointInTriangle(surferBox.x + surferBox.width, surferBox.y, points) || isPointInTriangle(surferBox.x, surferBox.y + surferBox.height, points) || isPointInTriangle(surferBox.x + surferBox.width, surferBox.y + surferBox.height, points);
};
self.update = function () {
if (self.lastX === undefined) {
self.lastX = self.x;
} // Initialize lastX if not set
self.x -= 8;
if (self.x < -self.width) {
self.destroy();
}
self.lastX = self.x; // Update lastX
};
return self;
});
var Seagull = Container.expand(function () {
var self = Container.call(this);
var seagullGraphics = self.attachAsset('seagull', {
anchorX: 0.5,
anchorY: 0.5
});
// Circle collision data
self.radius = 130; // Double the original radius
self.collisionX = 0;
self.collisionY = 0;
self.speed = -5 - Math.random() * 3; // Random speed variation
self.y = Math.random() * (2732 * 0.33); // Top third of screen
self.x = 2248; // Start off-screen right
// Flying animation
function flyAnimation() {
tween(self, {
y: self.y + (Math.random() * 100 - 50)
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: flyAnimation
});
// Wing flap effect
tween(seagullGraphics, {
scaleY: 0.8,
y: 5
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(seagullGraphics, {
scaleY: 1,
y: 0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
}
flyAnimation();
self.update = function () {
self.x += self.speed;
// Update collision circle position
self.collisionX = self.x;
self.collisionY = self.y;
// Remove if off screen
if (self.x < -100) {
self.destroy();
}
// Circle collision with surfer
var dx = self.collisionX - surfer.x;
var dy = self.collisionY - surfer.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.radius + 40) {
// 40 is approximate surfer radius
LK.showGameOver();
}
};
return self;
});
var Shark = Container.expand(function () {
var self = Container.call(this);
var sharkGraphics = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.2
});
self.radius = 50;
self.collisionX = 0;
self.collisionY = 0;
// Constants
var SWIM_SPEED = 7;
var CHASE_SPEED = 12;
var ESCAPE_SPEED = 15;
var DETECTION_RANGE = 800;
var CRUISE_HEIGHT = 2732 * 0.85;
var MIN_CHASE_TIME = 60; // 1 second at 60fps
var GRAVITY = 0.8;
var MAX_FALL_SPEED = 20;
self.chaseTimer = 0;
self.speed = SWIM_SPEED;
self.state = 'cruising';
self.targetRotation = 0;
self.velocityY = 0;
self.y = CRUISE_HEIGHT;
function swim() {
tween(sharkGraphics, {
scaleX: 1.1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sharkGraphics, {
scaleX: 0.9
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: swim
});
}
});
}
swim();
self.update = function () {
// Get wave height at current position for collision
var normalizedX = self.x / 2048;
var pointIndex = Math.floor(normalizedX * (waveSystem.points.length - 1));
var nextPointIndex = Math.min(pointIndex + 1, waveSystem.points.length - 1);
if (pointIndex >= 0 && pointIndex < waveSystem.points.length) {
var currentPoint = waveSystem.points[pointIndex];
var nextPoint = waveSystem.points[nextPointIndex];
var progress = normalizedX * (waveSystem.points.length - 1) - pointIndex;
var waveY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress;
var dx = surfer.x - self.x;
var dy = surfer.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Only apply gravity if we're above the wave
if (self.y < waveY) {
// In air, apply gravity
self.velocityY += GRAVITY;
self.velocityY = Math.min(self.velocityY, MAX_FALL_SPEED);
self.y += self.velocityY;
} else {
// Return to cruise height when in water, BUT NOT DURING CHASE
if (self.state !== 'chasing' && self.state !== 'escaping') {
self.y = CRUISE_HEIGHT;
self.velocityY = 0;
}
}
switch (self.state) {
case 'cruising':
self.speed = SWIM_SPEED;
self.targetRotation = 0;
// Only chase if shark is to the right of surfer and within height/distance
if (distance < DETECTION_RANGE && surfer.y > self.y - 500 && self.x > surfer.x) {
// Increased from 300
self.state = 'chasing';
self.chaseTimer = 0;
}
break;
case 'chasing':
self.speed = CHASE_SPEED;
// Only rotate toward player if shark hasn't passed them
if (self.x > surfer.x) {
self.targetRotation = -Math.atan2(surfer.y - self.y, self.x - surfer.x) * 0.3;
} else {
self.targetRotation = 0;
}
self.chaseTimer++;
// Increased movement factor for more aggressive vertical chase
if (self.y > waveY) {
// Only move up if in water
var targetY = Math.max(surfer.y, CRUISE_HEIGHT - 400);
self.y += (targetY - self.y) * 0.1; // Increased from 0.05 to 0.1
}
// Only escape if minimum chase time has elapsed AND escape conditions are met
if (self.chaseTimer > MIN_CHASE_TIME && (surfer.y < self.y - 600 || self.x < surfer.x - 100)) {
self.state = 'escaping';
self.targetRotation = 0;
}
break;
case 'escaping':
self.speed = ESCAPE_SPEED;
self.y += 10;
self.targetRotation = 0;
break;
}
// Smooth rotation
self.rotation += (self.targetRotation - self.rotation) * 0.1;
}
// Move based on current speed
self.x -= self.speed;
// Update collision
self.collisionX = self.x;
self.collisionY = self.y + 20;
// Check collision with surfer
var collisionDx = self.collisionX - surfer.x;
var collisionDy = self.collisionY - surfer.y;
var collisionDistance = Math.sqrt(collisionDx * collisionDx + collisionDy * collisionDy);
if (collisionDistance < self.radius + 40) {
LK.showGameOver();
}
if (self.x < -200 || self.y > CRUISE_HEIGHT + 400) {
self.destroy();
}
};
return self;
});
var Surfer = Container.expand(function () {
var self = Container.call(this);
// Constants
var BASE_GRAVITY = 1.5;
var MAX_SPEED = 40;
var DAMPENING = 0.99; // Less dampening
var WAVE_OFFSET = -30;
var FIXED_X = 2048 * 0.35;
var MAX_AIR_VELOCITY = 25; // Changed to positive since we're falling
var WAVE_TOLERANCE = 2; // Tighter tolerance
var SPLASH_VELOCITY_THRESHOLD = 15; // Minimum velocity for splash
var TRICK_HEIGHT_THRESHOLD = 50; // Lower threshold for testing
var initialJumpY = 0; // Track height where we left the wave
var wasAboveWave = false; // Add this to track state change
// State management
var ROTATION_STATES = {
NORMAL: 'normal',
FLIPPING: 'flipping',
RECOVERING: 'recovering'
};
var currentRotationState = ROTATION_STATES.NORMAL;
var rotationData = {
baseRotation: -0.1,
trickRotation: 0,
totalRotation: 0,
recoveryTarget: 0
};
// Physics variables
var velocityY = 0;
var lastWaveY = 2732 * 0.85;
var initialized = false;
// Setup surfer graphics
var surferGraphics = self.attachAsset('surfer', {
anchorX: 0.5,
anchorY: 0.8
});
// Initial position
self.x = FIXED_X;
self.y = lastWaveY + WAVE_OFFSET;
// Helper functions
function normalizeRotation(rotation) {
return rotation % (Math.PI * 2);
}
function showScorePopup(points) {
var scorePopup = new Text2("+" + points, {
size: 40,
fill: 0xFFFFFF
});
scorePopup.anchor.set(0.5, 0.5);
scorePopup.x = self.x;
scorePopup.y = self.y;
game.addChild(scorePopup);
tween(scorePopup, {
y: scorePopup.y - 100,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
scorePopup.destroy();
}
});
}
function createSplash() {
for (var i = 0; i < 50; i++) {
game.particles.addWaterParticle(FIXED_X, self.y + 40, 'splash');
}
}
function createTrail() {
for (var i = 0; i < 4; i++) {
game.particles.addWaterParticle(FIXED_X, self.y, 'trail');
}
}
function updateRotation(aboveWave) {
// Debug log outside switch to see all values
if (aboveWave) {
console.log('State:', currentRotationState, 'VelocityY:', velocityY, 'Height diff:', initialJumpY - self.y);
}
// Handle jump height tracking outside of state machine
if (aboveWave && !wasAboveWave) {
initialJumpY = self.y;
} else if (!aboveWave) {
initialJumpY = 0;
}
switch (currentRotationState) {
case ROTATION_STATES.NORMAL:
// Update wasAboveWave at the end
wasAboveWave = aboveWave;
if (aboveWave && !wasAboveWave) {
initialJumpY = self.y;
} else if (!aboveWave) {
// Reset when touching wave
initialJumpY = 0;
}
// Debug log to see what's happening
if (aboveWave && velocityY > 0) {
console.log('Height diff:', initialJumpY - self.y);
}
// Only enter flip state if we've fallen far enough
// Simplified trick check
if (aboveWave && velocityY > 10 && airTime > 10) {
// Need some air time
console.log('Starting trick!');
currentRotationState = ROTATION_STATES.FLIPPING;
rotationData.trickRotation = self.rotation;
} else {
var waveRotation = Math.sin(LK.ticks / 30) * 0.05;
var verticalSpeed = self.y - lastWaveY;
var verticalRotation = 0;
if (Math.abs(verticalSpeed) > 5) {
// Add threshold for rotation change
if (verticalSpeed < -2) {
verticalRotation = Math.min(0.2, -verticalSpeed * 0.003); // Reduced multiplier
} else if (verticalSpeed > 2) {
verticalRotation = Math.max(-0.3, -verticalSpeed * 0.003); // Reduced multiplier
}
}
// Smooth rotation transition
var targetRotation = rotationData.baseRotation + waveRotation + verticalRotation;
self.rotation += (targetRotation - self.rotation) * 0.1; // Smooth interpolation
}
break;
case ROTATION_STATES.FLIPPING:
rotationData.trickRotation += 0.15;
rotationData.totalRotation += 0.15;
self.rotation = rotationData.trickRotation;
if (!aboveWave) {
currentRotationState = ROTATION_STATES.RECOVERING;
var completedFlips = Math.floor(rotationData.totalRotation / (Math.PI * 2));
if (completedFlips > 0) {
score += completedFlips * 1000;
showScorePopup(completedFlips * 1000);
}
rotationData.recoveryTarget = normalizeRotation(rotationData.baseRotation);
createSplash();
}
break;
case ROTATION_STATES.RECOVERING:
var diff = rotationData.recoveryTarget - normalizeRotation(self.rotation);
if (Math.abs(diff) < 0.01) {
currentRotationState = ROTATION_STATES.NORMAL;
rotationData.trickRotation = 0;
rotationData.totalRotation = 0;
} else {
self.rotation += diff * 0.2;
}
break;
}
}
// Wave system setup
self.setWaveSystem = function (ws) {
waveSystem = ws;
if (!waveSystem.points) {
waveSystem.points = [];
}
initialized = true;
};
// Main update function
self.update = function () {
if (!waveSystem) {
return;
}
var normalizedX = self.x / 2048;
var pointIndex = Math.floor(normalizedX * (waveSystem.points.length - 1));
var nextPointIndex = Math.min(pointIndex + 1, waveSystem.points.length - 1);
var progress = normalizedX * (waveSystem.points.length - 1) - pointIndex;
var currentPoint = waveSystem.points[pointIndex];
var nextPoint = waveSystem.points[nextPointIndex];
if (!currentPoint || !nextPoint) {
return;
}
var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET;
var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET;
// Add tolerance zone for wave contact
var aboveWave = self.y < targetY;
// Add tolerance zone for wave contact
var inWaterContact = Math.abs(self.y - targetY) <= WAVE_TOLERANCE;
// Simpler above wave check
if (aboveWave) {
airTime++;
velocityY += BASE_GRAVITY;
velocityY *= DAMPENING;
// Debug log
if (LK.ticks % 10 === 0) {
console.log('Air time:', airTime, 'VelocityY:', velocityY, 'Height:', self.y);
}
} else {
airTime = 0;
self.y = targetY;
velocityY *= 0.8;
}
// Update position
self.y += velocityY;
// Update rotation state
updateRotation(aboveWave);
// More controlled particle triggers
if (inWaterContact) {
createTrail();
// Only create splash on hard impacts
if (velocityY > SPLASH_VELOCITY_THRESHOLD) {
createSplash();
}
}
lastWaveY = targetY;
};
self.getScore = function () {
return Math.floor(score);
};
return self;
});
var WaterParticle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('wave_point', {
anchorX: 0.5,
anchorY: 0.5
});
var speed, angle, scale;
self.init = function (type) {
// Reset properties
scale = 1;
self.type = type;
if (type === 'trail') {
speed = Math.random() * 8 + 6;
angle = Math.PI + (Math.random() * 0.4 - 0.2);
scale = 0.7;
particleGraphics.alpha = 0.8;
} else {
speed = Math.random() * 12 + 8;
angle = -Math.PI / 2 + (Math.random() * 1.4 - 0.7);
scale = 1.2;
particleGraphics.alpha = 0.9;
}
self.scale.set(scale, scale);
};
self.update = function () {
scale -= self.type === 'splash' ? 0.04 : 0.02;
self.scale.set(scale, scale);
if (scale <= 0) {
// Instead of destroying, return to pool
if (self.parent) {
self.parent.removeChild(self);
}
ParticlePool["return"](self);
return;
}
self.x += Math.cos(angle) * speed;
self.y += Math.sin(angle) * speed;
};
return self;
});
var WaveSystem = Container.expand(function () {
var self = Container.call(this);
var NUM_POINTS = 40;
var SCREEN_WIDTH = 2048;
var points = [];
var baseY = 2732 * 0.85;
var MIN_PITCH = 60;
var MAX_PITCH = 400;
var calibrationSamples = [];
self.isCalibrating = true;
var CALIBRATION_SAMPLES = 100; // Doubled to 100 samples
var CALIBRATION_VOLUME_THRESHOLD = 0.5; // Minimum volume to count as valid input
var calibrationStartTime = LK.ticks;
var CALIBRATION_TIMEOUT = 300; // 5 seconds (60 ticks per second)
var WAVE_HEIGHT = 2000;
var lastPitch = 0;
// Create calibration message
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.alpha = 0.7;
background.scale.set(10, 2); // Adjust scale as needed
// Add background first so it's behind the text
LK.gui.center.addChild(background);
var calibrationText = new Text2("Make some noise!\nHum high and low to calibrate", {
size: 60,
fill: 0xFFFFFF,
align: 'center'
});
calibrationText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(calibrationText);
// Progress indicator
var progressText = new Text2("0%", {
size: 40,
fill: 0xFFFFFF,
alpha: 0.8
});
progressText.anchor.set(0.5, 0.5);
progressText.y = calibrationText.y + 80;
LK.gui.center.addChild(progressText);
// Removed visual pitch indicator and labels
function updatePitchRange(pitch) {
if (facekit.volume > CALIBRATION_VOLUME_THRESHOLD) {
calibrationSamples.push(pitch);
// Update progress display
var progress = Math.min(100, Math.floor(calibrationSamples.length / CALIBRATION_SAMPLES * 100));
progressText.setText(progress + "%");
// Removed pitch indicator position update as visual indicator is no longer used
if (calibrationSamples.length >= CALIBRATION_SAMPLES) {
finishCalibration();
}
}
// Check for timeout
if (LK.ticks - calibrationStartTime > CALIBRATION_TIMEOUT) {
if (calibrationSamples.length < 10) {
// Not enough samples
// Reset and extend time
calibrationSamples = [];
calibrationStartTime = LK.ticks;
calibrationText.setText("Let's try again!\nMake some noise - hum or speak");
} else {
finishCalibration(); // Use what we have
}
}
}
function finishCalibration() {
var sortedPitches = calibrationSamples.sort(function (a, b) {
return a - b;
});
MIN_PITCH = sortedPitches[Math.floor(calibrationSamples.length * 0.1)];
MAX_PITCH = sortedPitches[Math.floor(calibrationSamples.length * 0.9)];
// Add padding to range
MIN_PITCH = Math.max(30, MIN_PITCH - 10);
MAX_PITCH = MAX_PITCH + 20;
self.isCalibrating = false;
// Show completion message
calibrationText.setText("Ready!");
background.destroy();
calibrationText.destroy();
progressText.destroy();
// Fade out completion message
tween(calibrationText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
return calibrationText.destroy();
}
});
// Removed pitch meter cleanup
console.log("Calibrated pitch range:", MIN_PITCH, "to", MAX_PITCH);
}
// Enhanced smoothing system
var heightBuffer = Array(30).fill(0);
var bufferIndex = 0;
var lastSmoothedHeight = 0;
// Water fill rectangles
var waterRects = [];
var NUM_WATER_SECTIONS = 80; // Reduced from 80
for (var i = 0; i < NUM_WATER_SECTIONS; i++) {
var rect = self.attachAsset('wave_line', {
anchorX: 0.5,
// Center anchor
anchorY: 0,
// Top anchor
height: 2732,
width: SCREEN_WIDTH / NUM_WATER_SECTIONS + 1,
// Tiny overlap to prevent pixel gaps
tint: 0x0066cc,
alpha: 0.3
});
waterRects.push(rect);
}
// Create wave line segments
var lines = [];
function createLines() {
// Clean up any existing lines first
lines.forEach(function (line) {
line.destroy();
self.removeChild(line);
});
lines = [];
// Create new lines
for (var i = 0; i < NUM_POINTS - 1; i++) {
var line = self.attachAsset('wave_line', {
anchorX: 0,
anchorY: 0.5,
height: 4
});
lines.push(line);
}
}
// Call initial creation
createLines();
function gaussianCurve(x) {
return Math.exp(-(x * x) / 0.8);
}
function getSmoothedHeight(newHeight) {
heightBuffer[bufferIndex] = newHeight;
bufferIndex = (bufferIndex + 1) % heightBuffer.length;
// Simplified smoothing calculation
var total = 0;
var weights = 0;
for (var i = 0; i < heightBuffer.length; i++) {
var weight = Math.pow(0.95, i); // Exponential decay
total += heightBuffer[(bufferIndex - i + heightBuffer.length) % heightBuffer.length] * weight;
weights += weight;
}
var smoothedHeight = total / weights;
lastSmoothedHeight = lastSmoothedHeight * 0.85 + smoothedHeight * 0.15; // Changed from 0.7/0.3
return lastSmoothedHeight;
}
self.update = function () {
// Always calculate wave points first, regardless of calibration state
var targetPitch = 0;
if (facekit.volume > 0.5) {
var normalizedPitch = (facekit.pitch - MIN_PITCH) / (MAX_PITCH - MIN_PITCH);
normalizedPitch = Math.max(0, Math.min(1, normalizedPitch));
targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4;
}
lastPitch += (targetPitch - lastPitch) * 0.2;
var smoothedHeight = getSmoothedHeight(lastPitch * WAVE_HEIGHT);
points = [];
for (var i = 0; i < NUM_POINTS; i++) {
var x = i / (NUM_POINTS - 1) * SCREEN_WIDTH;
var distanceFromCenter = (x - SCREEN_WIDTH * 0.35) / (SCREEN_WIDTH * 0.45);
var heightFactor = gaussianCurve(distanceFromCenter);
var y = baseY - smoothedHeight * heightFactor;
points.push({
x: x,
y: y
});
}
// Always update water rectangles
for (var i = 0; i < NUM_WATER_SECTIONS; i++) {
var rect = waterRects[i];
var xPosition = i / NUM_WATER_SECTIONS * SCREEN_WIDTH;
var exactPointPosition = xPosition / SCREEN_WIDTH * (NUM_POINTS - 1);
var pointIndex = Math.floor(exactPointPosition);
var nextPointIndex = Math.min(pointIndex + 1, NUM_POINTS - 1);
var progress = exactPointPosition - pointIndex;
var y1 = points[pointIndex].y;
var y2 = points[nextPointIndex].y;
var y = y1 + (y2 - y1) * progress;
rect.x = xPosition;
rect.y = y;
rect.height = 2732 - y;
rect.alpha = 0.3 + Math.sin(LK.ticks * 0.02 + i * 0.2) * 0.02;
}
self.points = points;
// Handle calibration if still calibrating
if (self.isCalibrating) {
if (facekit.volume > CALIBRATION_VOLUME_THRESHOLD) {
calibrationSamples.push(facekit.pitch);
var progress = Math.min(100, Math.floor(calibrationSamples.length / CALIBRATION_SAMPLES * 100));
progressText.setText(progress + "%");
if (calibrationSamples.length >= CALIBRATION_SAMPLES) {
finishCalibration();
}
}
if (LK.ticks - calibrationStartTime > CALIBRATION_TIMEOUT) {
if (calibrationSamples.length < 10) {
calibrationSamples = [];
calibrationStartTime = LK.ticks;
calibrationText.setText("Let's try again!\nMake some noise - hum or speak");
} else {
finishCalibration();
}
}
} else {
// Only update score when not calibrating
if (facekit.volume > 0.5) {
score += smoothedHeight / WAVE_HEIGHT * multiplier;
multiplier += 0.001;
} else {
multiplier = Math.max(1, multiplier - 0.01);
}
}
// Always update wave line segments
for (var i = 0; i < lines.length; i++) {
var start = points[i];
var end = points[i + 1];
var dx = end.x - start.x;
var dy = end.y - start.y;
var length = Math.sqrt(dx * dx + dy * dy);
var angle = Math.atan2(dy, dx);
lines[i].x += (start.x - lines[i].x) * 0.3;
lines[i].y += (start.y - lines[i].y) * 0.3;
lines[i].width += (length - lines[i].width) * 0.3;
var angleDiff = angle - lines[i].rotation;
if (angleDiff > Math.PI) {
angleDiff -= Math.PI * 2;
}
if (angleDiff < -Math.PI) {
angleDiff += Math.PI * 2;
}
lines[i].rotation += angleDiff * 0.3;
}
};
self.destroy = function () {
waterRects.forEach(function (rect) {
return rect.destroy();
});
lines.forEach(function (line) {
return line.destroy();
});
waterRects = [];
lines = [];
Container.prototype.destroy.call(this);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 //Init game with black background
});
/****
* Game Code
****/
var BASE_Y = 2732 * 0.85;
var ParticlePool = {
pool: [],
maxSize: 200,
get: function get() {
if (this.pool.length > 0) {
var particle = this.pool.pop();
particle.visible = true;
return particle;
}
return new WaterParticle();
},
"return": function _return(particle) {
if (this.pool.length < this.maxSize) {
// Reset particle properties
particle.visible = false;
particle.scale.set(1, 1);
particle.x = 0;
particle.y = 0;
particle.rotation = 0;
this.pool.push(particle);
} else {
particle.destroy();
}
}
};
function isPointInTriangle(px, py, points) {
var p0 = points[0],
p1 = points[1],
p2 = points[2];
var A = 1 / 2 * (-p1.y * p2.x + p0.y * (-p1.x + p2.x) + p0.x * (p1.y - p2.y) + p1.x * p2.y);
var sign = A < 0 ? -1 : 1;
var s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * px + (p0.x - p2.x) * py) * sign;
var t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * px + (p1.x - p0.x) * py) * sign;
return s > 0 && t > 0 && s + t < 2 * A * sign;
}
var lastScoreDisplay = -1;
var lastMultiplierDisplay = -1;
var originalSetInterval = LK.setInterval;
LK.setInterval = function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var timer = originalSetInterval.apply(this, args);
gameTimers.push(timer);
return timer;
};
var originalSetTimeout = LK.setTimeout;
LK.setTimeout = function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
var timer = originalSetTimeout.apply(this, args);
gameTimers.push(timer);
return timer;
};
var gameTimers = [];
// Set an interval to play the waves sound effect every 4-6 seconds
var wavesSoundInterval = LK.setInterval(function () {
LK.getSound('waves').play();
}, 4000 + Math.random() * 2000); // Random interval between 4-6 seconds
gameTimers.push(wavesSoundInterval);
var seagullSpawnInterval = 6000; // Spawn every 3 seconds
var lastSeagullSpawn = 0;
var lastCloudSpawn = 0;
var cloudSpawnInterval = 1000 + Math.random() * 2000; // Random interval between 1-3 seconds
function spawnSeagull() {
if (Date.now() - lastSeagullSpawn > seagullSpawnInterval) {
var seagull = new Seagull();
game.addChild(seagull);
LK.getSound('seagull').play(); // Play seagull sound effect
lastSeagullSpawn = Date.now();
seagullSpawnInterval = 3000 + Math.random() * 3000; // Random interval between 1-3 seconds
}
}
var rocks = [];
var lastRockTime = 0;
var fishSpawnInterval = 8000;
var lastFishSpawn = 0;
var lastSharkSpawn = Date.now() + 8000;
var sharkSpawnInterval = 8000; // Initial spawn interval (8 seconds)
var lastWholeMultiplier = 1;
var score = 0; // Initialize score variable
var multiplier = 1;
var lastWaveHeight = 0;
var lastWaveUpdate = 0;
var devicePerformance = 1; // Default performance multiplier
var poseidon = LK.getAsset('poseidon', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(poseidon);
var mouth = LK.getAsset('mouth', {
anchorX: 0.5,
// Center anchor
anchorY: 0.5,
// Center anchor
alpha: 0 // Initialize alpha to 0
});
game.addChild(mouth);
var waveSystem = game.addChild(new WaveSystem());
var particles = new ParticleSystem();
game.particles = game.addChild(new ParticleSystem());
var surfer = game.addChild(new Surfer());
surfer.setWaveSystem(waveSystem);
var scoreText = new Text2("", {
size: 100,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var multiplierText = new Text2("", {
size: 60,
fill: 0xFFFFFF,
alpha: 0.8
});
multiplierText.anchor.set(1, 1);
LK.gui.bottomRight.addChild(multiplierText);
var bestScoreText = new Text2("Best: " + storage.bestScore, {
size: 60,
fill: 0xFFFFFF,
alpha: 0.8
});
bestScoreText.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(bestScoreText);
// Game update function
var lastUpdateTime = 0;
game.update = function () {
var now = Date.now();
if (now - lastUpdateTime < 16) {
// Don't update faster than 60fps
return;
}
lastUpdateTime = now;
// Every 300 frames, log counts
if (LK.ticks % 600 === 0) {
console.log('Active timers:', gameTimers.length);
}
if (LK.ticks % 300 === 0) {
console.log('Particle count:', game.particles.children.length);
console.log('Wave points:', waveSystem.points.length);
console.log('Total game children:', game.children.length);
console.log('Active tweens:', tween.getActiveTweens ? tween.getActiveTweens().length : 0);
}
waveSystem.update();
surfer.update();
particles.update();
// Update Poseidon's position to follow the player's face
if (facekit.noseTip) {
poseidon.x = facekit.noseTip.x;
poseidon.y = facekit.noseTip.y;
}
// Update mouth position to follow the player's mouth
if (facekit.mouthCenter) {
mouth.x = facekit.mouthCenter.x;
mouth.y = facekit.mouthCenter.y + 90;
if (facekit.volume > 0.45) {
// Change alpha to 1 when volume is greater than 0.35
mouth.alpha = 1;
} else {
mouth.alpha = 0;
}
}
// Only spawn obstacles if not calibrating
if (!waveSystem.isCalibrating) {
// Rock spawning
if (LK.ticks - lastRockTime > 240 + Math.random() * 360) {
lastRockTime = LK.ticks;
var rock = game.addChild(new Rock());
rock.x = 2548; // Start off right side
rock.y = 2732 + 200; // Place base below screen
// Set the vertical scale independently for random height
rock.children[0].scaleY = 3 + Math.random() * 4; // Random height between 3x and 7x
rocks.push(rock);
}
if (!waveSystem.isCalibrating && Date.now() - lastSharkSpawn > sharkSpawnInterval) {
var shark = new Shark();
shark.x = 2548;
var spawnPointIndex = waveSystem.points.length - 1;
var waveY = waveSystem.points[spawnPointIndex].y;
shark.y = waveY + 60;
game.addChild(shark);
lastSharkSpawn = Date.now();
sharkSpawnInterval = 8000 + Math.random() * 8000;
}
// Seagull spawning
spawnSeagull();
}
// Cloud spawning
if (Date.now() - lastCloudSpawn > cloudSpawnInterval) {
var cloud = new Cloud();
game.addChildAt(cloud, game.getChildIndex(poseidon) + (Math.random() < 0.5 ? 0 : 1)); // Add cloud at Poseidon's layer or one above
lastCloudSpawn = Date.now();
cloudSpawnInterval = 2000 + Math.random() * 2000; // Random interval between 2-4 seconds
}
if (Date.now() - lastFishSpawn > fishSpawnInterval) {
var fish = new Fish();
game.addChild(fish);
lastFishSpawn = Date.now();
fishSpawnInterval = 3000 + Math.random() * 3000; // Random interval between 3-6 seconds
}
// Update and check rocks
for (var i = rocks.length - 1; i >= 0; i--) {
var rock = rocks[i];
rock.update();
// Remove destroyed rocks
if (!rock.parent) {
rocks.splice(i, 1);
continue;
}
// Check collision with surfer
if (rock.checkCollision(surfer)) {
LK.showGameOver();
}
}
game.children.forEach(function (child) {
if (child instanceof Seagull && child.update) {
child.update();
}
});
var currentScore = Math.floor(score);
if (currentScore !== lastScoreDisplay) {
lastScoreDisplay = currentScore;
scoreText.setText(currentScore.toLocaleString());
}
if (currentScore > storage.bestScore) {
storage.bestScore = currentScore;
bestScoreText.setText("Best: " + storage.bestScore);
}
var currentMultiplier = Math.floor(multiplier * 10) / 10; // Round to 1 decimal
if (currentMultiplier !== lastMultiplierDisplay) {
lastMultiplierDisplay = currentMultiplier;
multiplierText.setText("x" + currentMultiplier.toFixed(1));
}
var currentWholeMultiplier = Math.floor(multiplier);
if (currentWholeMultiplier > lastWholeMultiplier) {
console.log("Multiplier increased:", currentWholeMultiplier); // Debug log
LK.getSound('multiplier').play();
var randomVoice = 'voice' + (Math.floor(Math.random() * 5) + 1);
LK.getSound(randomVoice).play();
var popupText = new Text2(currentWholeMultiplier + "X MULTIPLIER!", {
size: 120,
fill: 0xFFFFFF,
align: 'center',
weight: 800
});
popupText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(popupText);
popupText.scale.set(0.1);
// Animate in
tween(popupText.scale, {
x: 1.2,
y: 1.2
}, {
duration: 400,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Animate out
tween(popupText, {
alpha: 0,
y: popupText.y - 100
}, {
duration: 800,
delay: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.gui.center.removeChild(popupText);
popupText.destroy();
}
});
}
});
lastWholeMultiplier = currentWholeMultiplier;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -495,8 +495,10 @@
var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET;
var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET;
// Add tolerance zone for wave contact
var aboveWave = self.y < targetY;
+ // Add tolerance zone for wave contact
+ var inWaterContact = Math.abs(self.y - targetY) <= WAVE_TOLERANCE;
// Simpler above wave check
if (aboveWave) {
airTime++;
velocityY += BASE_GRAVITY;
A surfer standing and riding on a surfboard. Side profile. Cartoon. Full body. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A peaked blue rock. Cartoon style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Poseidon’s face. Cartoon style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
An opened pair of lips as if singing . Light Skin color. Cell shading vector art style. Facing forward. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A tropical fish. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows