User prompt
Update shark class with: var Shark = Container.expand(function() { var self = Container.call(this); var sharkGraphics = self.attachAsset('line', { 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 = 600; var FIN_OFFSET = 57; // 5% higher than before (was 60) var MAX_WAVE_HEIGHT = 400; // Maximum height shark will follow var BASE_Y = 2732 * 0.95; // Base water level self.speed = SWIM_SPEED; self.targetY = BASE_Y; function swim() { tween(sharkGraphics, { rotation: 0.1, scaleX: 1.1 }, { duration: 500, easing: tween.easeInOut, onFinish: function() { tween(sharkGraphics, { rotation: -0.1, scaleX: 0.9 }, { duration: 500, easing: tween.easeInOut, onFinish: swim }); } }); } swim(); self.update = function() { self.x -= self.speed; 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 waveHeight = BASE_Y - waveY; // Limit how high the shark will follow the wave if (waveHeight > MAX_WAVE_HEIGHT) { // Wave is too high, swim down and away self.speed = ESCAPE_SPEED; self.targetY = BASE_Y; } else { // Calculate target Y with limited wave following var followRatio = Math.max(0, 1 - (waveHeight / MAX_WAVE_HEIGHT)); self.targetY = waveY + FIN_OFFSET + (waveHeight * followRatio); // Check distance to player for chase behavior var dx = surfer.x - self.x; var dy = surfer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < DETECTION_RANGE && waveHeight < MAX_WAVE_HEIGHT * 0.8) { if (surfer.y < self.y - 250) { self.speed = ESCAPE_SPEED; } else { self.speed = CHASE_SPEED; } } else { self.speed = SWIM_SPEED; } } // Smooth Y movement with maximum speed limit var yDiff = self.targetY - self.y; var maxYMove = 15; // Maximum Y movement per frame var moveY = Math.min(Math.abs(yDiff), maxYMove) * Math.sign(yDiff); self.y += moveY; // Calculate angle based on movement, not wave var angle = Math.atan2(moveY, -self.speed); self.rotation = angle * 0.5; } // Update collision circle position self.collisionX = self.x; self.collisionY = self.y + 20; // Circle 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.destroy(); } }; return self; });
Code edit (3 edits merged)
Please save this source code
User prompt
Update shark spawn as needed with: 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; }
User prompt
Update shark class with: var Shark = Container.expand(function() { var self = Container.call(this); var sharkGraphics = self.attachAsset('line', { anchorX: 0.5, anchorY: 0.2 }); // Circle collision data like seagulls self.radius = 50; self.collisionX = 0; self.collisionY = 0; // Constants var SWIM_SPEED = 7; var CHASE_SPEED = 12; var DETECTION_RANGE = 600; var FIN_OFFSET = 60; self.speed = SWIM_SPEED; function swim() { tween(sharkGraphics, { rotation: 0.1, scaleX: 1.1 }, { duration: 500, easing: tween.easeInOut, onFinish: function() { tween(sharkGraphics, { rotation: -0.1, scaleX: 0.9 }, { duration: 500, easing: tween.easeInOut, onFinish: swim }); } }); } swim(); self.update = function() { self.x -= self.speed; 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; self.y = waveY + FIN_OFFSET; var angle = Math.atan2(nextPoint.y - currentPoint.y, nextPoint.x - currentPoint.x); self.rotation = angle * 0.5; } // Update collision circle position self.collisionX = self.x; self.collisionY = self.y + 20; // Offset to center of shark var dx = surfer.x - self.x; var dy = surfer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < DETECTION_RANGE) { if (surfer.y < self.y - 300) { self.speed = CHASE_SPEED * 1.5; } else { self.speed = CHASE_SPEED; } } else { self.speed = SWIM_SPEED; } // Circle 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) { // 40 is approximate surfer radius LK.showGameOver(); } if (self.x < -200) { self.destroy(); } }; return self; });
User prompt
Double the size of the collision detection for the seagulls
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: Shark' in or related to this line: 'var shark = new Shark();' Line Number: 821
Code edit (1 edits merged)
Please save this source code
User prompt
If the user face leaves the screen, set pitch to 0 ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Instead of playing voice1, play a random sound effect from voice 1-5
User prompt
Play voice1 at the same time as the multiplier sound effect
User prompt
After the calibration is complete, fade in music and play on loop.
User prompt
Play the multiplier sound effect every time the multiplier text pop up happens
User prompt
Play the waves sound effect every 4-6 seconds.
User prompt
Play the seagull sound effect when one is spawned.
User prompt
Decrease the time between seagull spawns a little.
User prompt
Play a seagull sound effect if the player opens their right eye.
User prompt
Play a seagull sound effect if the player smiles. ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: tween' in or related to this line: 'console.log('Active tweens:', tween.getActiveTweens ? tween.getActiveTweens().length : 0);' Line Number: 776 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: facekit' in or related to this line: 'if (facekit.volume > 0.5) {' Line Number: 525 ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Please fix the bug: 'Can't find variable: storage' in or related to this line: 'var bestScoreText = new Text2("Best: " + storage.bestScore, {' Line Number: 746 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Play the ocean sound effect at random intervals between 4-7 seconds.
User prompt
Every time a seagull is spawned play the seagull sound effect.
User prompt
Update as needed with: // Increase buffer size for more stability var heightBuffer = Array(30).fill(0); // Changed from 15 to 30 for more samples // Modify the smoothing weights in getSmoothedHeight function getSmoothedHeight(newHeight) { heightBuffer[bufferIndex] = newHeight; bufferIndex = (bufferIndex + 1) % heightBuffer.length; // Weighted average giving more importance to recent values 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; // Increase smoothing factor for more stability lastSmoothedHeight = lastSmoothedHeight * 0.85 + smoothedHeight * 0.15; // Changed from 0.7/0.3 return lastSmoothedHeight; } // Then in the update function, adjust the pitch smoothing: targetPitch = normalizedPitch * 0.6 + lastPitch * 0.4; // Changed from 0.8/0.2
User prompt
Update fish class with: var Fish = Container.expand(function() { var self = Container.call(this); var fishGraphics = self.attachAsset('fish', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -3 - Math.random() * 2; self.y = 2732 * (0.87 + Math.random() * 0.1); self.x = 2248; // 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; if (self.x < -100) { self.destroy(); } }; return self; });
/**** * 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 ****/ 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 }); // Circle collision data like seagulls 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 = 600; var FIN_OFFSET = 57; // 5% higher than before (was 60) var MAX_WAVE_HEIGHT = 400; // Maximum height shark will follow var BASE_Y = 2732 * 0.95; // Base water level self.speed = SWIM_SPEED; self.targetY = BASE_Y; function swim() { tween(sharkGraphics, { rotation: 0.1, scaleX: 1.1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(sharkGraphics, { rotation: -0.1, scaleX: 0.9 }, { duration: 500, easing: tween.easeInOut, onFinish: swim }); } }); } swim(); self.update = function () { self.x -= self.speed; 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 waveHeight = BASE_Y - waveY; // Limit how high the shark will follow the wave if (waveHeight > MAX_WAVE_HEIGHT) { // Wave is too high, swim down and away self.speed = ESCAPE_SPEED; self.targetY = BASE_Y; } else { // Calculate target Y with limited wave following var followRatio = Math.max(0, 1 - waveHeight / MAX_WAVE_HEIGHT); self.targetY = waveY + FIN_OFFSET + waveHeight * followRatio; // Check distance to player for chase behavior var dx = surfer.x - self.x; var dy = surfer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < DETECTION_RANGE && waveHeight < MAX_WAVE_HEIGHT * 0.8) { if (surfer.y < self.y - 250) { self.speed = ESCAPE_SPEED; } else { self.speed = CHASE_SPEED; } } else { self.speed = SWIM_SPEED; } } // Smooth Y movement with maximum speed limit var yDiff = self.targetY - self.y; var maxYMove = 15; // Maximum Y movement per frame var moveY = Math.min(Math.abs(yDiff), maxYMove) * Math.sign(yDiff); self.y += moveY; // Calculate angle based on movement, not wave var angle = Math.atan2(moveY, -self.speed); self.rotation = angle * 0.5; } // Update collision circle position self.collisionX = self.x; self.collisionY = self.y + 20; // Offset to center of shark 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) { // 40 is approximate surfer radius LK.showGameOver(); } if (self.x < -200) { self.destroy(); } }; return self; }); var Surfer = Container.expand(function () { var self = Container.call(this); var BASE_GRAVITY = 1.5; // Reduced for smoother acceleration var MAX_SPEED = 40; // Increased for longer falls var DAMPENING = 0.98; // Less dampening for smoother motion var WAVE_OFFSET = -30; var FIXED_X = 2048 * 0.35; var MAX_AIR_VELOCITY = -25; // Only applies when surfer is above wave var velocityY = 0; var velocityRot = 0; var activeTween = null; // Initialize activeTween variable var lastWaveY = 2732 * 0.85; // Match WaveSystem's baseY var initialized = false; var surferGraphics = self.attachAsset('surfer', { anchorX: 0.5, anchorY: 0.8 }); self.x = FIXED_X; self.y = lastWaveY + WAVE_OFFSET; // Start at base wave height self.setWaveSystem = function (ws) { waveSystem = ws; if (!waveSystem.points) { waveSystem.points = []; } initialized = true; }; self.update = function () { // Add tween cleanup if (activeTween) { tween.stop(activeTween); } 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) { var targetY = currentPoint.y + (nextPoint.y - currentPoint.y) * progress + WAVE_OFFSET; } else { return; // Exit update if points are undefined } var waveRising = targetY < lastWaveY; var aboveWave = self.y < targetY; if (waveRising && !aboveWave) { // Natural wave following - no limits when on the wave velocityY = (targetY - self.y) * 0.2; self.y += velocityY; } else { // In air or falling velocityY += BASE_GRAVITY; velocityY *= DAMPENING; // Only cap velocity when above the wave if (aboveWave && velocityY < MAX_AIR_VELOCITY) { velocityY = MAX_AIR_VELOCITY; } self.y += velocityY; if (self.y > targetY && velocityY > 0) { var fallVelocity = velocityY; // Capture velocity before reset self.y = targetY; velocityY = 0; if (aboveWave && fallVelocity > 15) { // Only splash on significant falls createSplash(); } } } lastWaveY = targetY; var baseRotation = -0.1; // Slight left tilt as base position var waveRotation = Math.sin(LK.ticks / 30) * 0.05; // Gentle wave motion // Calculate vertical movement speed var verticalSpeed = self.y - lastWaveY; // Add rotation based on vertical movement var verticalRotation = 0; if (verticalSpeed < -2) { // Moving up - reduce sensitivity from 0.005 to 0.003 verticalRotation = Math.min(0.3, -verticalSpeed * 0.003); } else if (verticalSpeed > 2) { // Moving down - reduce sensitivity from 0.005 to 0.003 verticalRotation = Math.max(-0.4, -verticalSpeed * 0.003); } // Smoothly apply all rotations velocityRot += (baseRotation + waveRotation + verticalRotation - self.rotation) * 0.03; // Reduce rotation response speed from 0.05 to 0.03 velocityRot *= 0.95; // Increase damping from 0.9 to 0.95 for smoother transitions self.rotation += velocityRot; // Create trail particles whenever touching water if (self.y >= targetY) { createTrail(); } var targetAngle = Math.atan2(nextPoint.y - currentPoint.y, nextPoint.x - currentPoint.x); // ... rest of the rotation code ... particles.children.forEach(function (particle) { if (particle.update) { particle.update(); } }); }; self.getScore = function () { return Math.floor(score); }; // Then in the Surfer class, replace the particle system with: var particles = self.addChild(new ParticleSystem()); function createSplash() { for (var i = 0; i < 50; i++) { // Move splash up by 40 to match trail Y position game.particles.addWaterParticle(FIXED_X, self.y + 40, 'splash'); } } function createTrail() { // Create fewer particles but more frequently for trail for (var i = 0; i < 4; i++) { game.particles.addWaterParticle(FIXED_X, self.y, 'trail'); } } 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 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 = 0; 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
@@ -205,11 +205,15 @@
self.collisionY = 0;
// Constants
var SWIM_SPEED = 7;
var CHASE_SPEED = 12;
+ var ESCAPE_SPEED = 15;
var DETECTION_RANGE = 600;
- var FIN_OFFSET = 60;
+ var FIN_OFFSET = 57; // 5% higher than before (was 60)
+ var MAX_WAVE_HEIGHT = 400; // Maximum height shark will follow
+ var BASE_Y = 2732 * 0.95; // Base water level
self.speed = SWIM_SPEED;
+ self.targetY = BASE_Y;
function swim() {
tween(sharkGraphics, {
rotation: 0.1,
scaleX: 1.1
@@ -238,28 +242,44 @@
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;
- self.y = waveY + FIN_OFFSET;
- var angle = Math.atan2(nextPoint.y - currentPoint.y, nextPoint.x - currentPoint.x);
+ var waveHeight = BASE_Y - waveY;
+ // Limit how high the shark will follow the wave
+ if (waveHeight > MAX_WAVE_HEIGHT) {
+ // Wave is too high, swim down and away
+ self.speed = ESCAPE_SPEED;
+ self.targetY = BASE_Y;
+ } else {
+ // Calculate target Y with limited wave following
+ var followRatio = Math.max(0, 1 - waveHeight / MAX_WAVE_HEIGHT);
+ self.targetY = waveY + FIN_OFFSET + waveHeight * followRatio;
+ // Check distance to player for chase behavior
+ var dx = surfer.x - self.x;
+ var dy = surfer.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < DETECTION_RANGE && waveHeight < MAX_WAVE_HEIGHT * 0.8) {
+ if (surfer.y < self.y - 250) {
+ self.speed = ESCAPE_SPEED;
+ } else {
+ self.speed = CHASE_SPEED;
+ }
+ } else {
+ self.speed = SWIM_SPEED;
+ }
+ }
+ // Smooth Y movement with maximum speed limit
+ var yDiff = self.targetY - self.y;
+ var maxYMove = 15; // Maximum Y movement per frame
+ var moveY = Math.min(Math.abs(yDiff), maxYMove) * Math.sign(yDiff);
+ self.y += moveY;
+ // Calculate angle based on movement, not wave
+ var angle = Math.atan2(moveY, -self.speed);
self.rotation = angle * 0.5;
}
// Update collision circle position
self.collisionX = self.x;
self.collisionY = self.y + 20; // Offset to center of shark
- var dx = surfer.x - self.x;
- var dy = surfer.y - self.y;
- var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance < DETECTION_RANGE) {
- if (surfer.y < self.y - 300) {
- self.speed = CHASE_SPEED * 1.5;
- } else {
- self.speed = CHASE_SPEED;
- }
- } else {
- self.speed = SWIM_SPEED;
- }
- // Circle 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) {
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