Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
add tween effect after dashing ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: EagleWarningIcon is not defined' in or related to this line: 'var warningIconClassMap = {' Line Number: 2454
User prompt
delete eagle obstacle
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'isJumping')' in or related to this line: 'if (coot.isJumping || coot.isFalling || coot.isDiving || coot.isReturning || coot.returnDelay > 0) {' Line Number: 2696
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'if (powerups[i].x < -powerups[i].width / 2) {' Line Number: 182
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError is not a constructor' in or related to this line: 'throw new TypeError("Super expression must either be null or a function");' Line Number: 95
Code edit (1 edits merged)
Please save this source code
User prompt
prompt for the boat asset
User prompt
make sure the river flowing or not
User prompt
ensuring that the flow appears uninterrupted to the player.
User prompt
creating a loop effect that maintains the visual continuity of the flowing river. This effect is achieved by checking the river's Y position and resetting it when it reaches a certain point
User prompt
the river's movement should loop indefinitely, giving the impression of an endless flow. The river's position should reset once it reaches the bottom of the screen,
User prompt
The river should flow continuously throughout the game to create a seamless and immersive experience. This means that the river's movement should loop indefinitely,
User prompt
The river should flow continuously throughout the game to create a seamless and immersive experience. This means that the river's movement should loop indefinitely, giving the impression of an endless flow. The river's position should reset once it reaches the bottom of the screen, creating a loop effect that maintains the visual continuity of the flowing river. This effect is achieved by checking the river's Y position and resetting it when it reaches a certain point, ensuring that the flow appears uninterrupted to the player.
User prompt
make the river flow
User prompt
Make sure boat wil stop moving forward
User prompt
Stop the boat from moving forward
/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1", { coins: 0 }); var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Import tween plugin // Initialize with default coins value var Butterfly = Container.expand(function () { var self = Container.call(this); var butterflyGraphics; var selectedType; // Initialize butterfly properties self.speedX = -2; self.flitAmplitude = 20; self.flitFrequency = 0.1; self.startY = 0; self.init = function () { var butterflyTypes = ['GreenButterfly', 'PinkButterfly', 'YellowButterfly']; selectedType = butterflyTypes[Math.floor(Math.random() * butterflyTypes.length)]; if (!butterflyGraphics || butterflyGraphics.assetId !== selectedType) { if (butterflyGraphics) { self.removeChild(butterflyGraphics); } butterflyGraphics = self.attachAsset(selectedType, { anchorX: 0.5, anchorY: 0.5 }); } self.startY = Math.random() * (2732 * 0.6) + 2732 * 0.2; return self; }; self.reset = function () { var butterflyTypes = ['GreenButterfly', 'PinkButterfly', 'YellowButterfly']; var newType = butterflyTypes[Math.floor(Math.random() * butterflyTypes.length)]; if (newType !== selectedType) { selectedType = newType; if (butterflyGraphics) { self.removeChild(butterflyGraphics); } butterflyGraphics = self.attachAsset(selectedType, { anchorX: 0.5, anchorY: 0.5 }); } self.startY = Math.random() * (2732 * 0.6) + 2732 * 0.2; return self; }; self.destroy = function () { if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('Butterfly', self); }; self.update = function () { // Move the butterfly left self.x += self.speedX * gameSpeed; // Apply flitting motion self.y = self.startY + Math.sin(self.x * self.flitFrequency) * self.flitAmplitude; // Simulate wing flapping by adjusting scale var flapScale = 0.2 * Math.sin(LK.ticks * 0.3) + 1; butterflyGraphics.scale.set(flapScale); // Destroy the butterfly if it goes off screen if (self.x < -butterflyGraphics.width / 2) { self.destroy(); } }; return self.init(); }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('Coin', { anchorX: 0.5, anchorY: 0.5 }); // Initialize coin properties self.rotationSpeed = 0.05; // Rotation speed for the coin self.speedX = -5; // Speed of the coin moving left self.collecting = false; // Flag to check if the coin is being collected self.targetX = 0; // Target X position for collection animation self.targetY = 0; // Target Y position for collection animation self.update = function () { // Generate GoldSparkle particles if (Math.random() < 0.0525) { var sparkle = ObjectPool.get('GoldSparkle', GoldSparkle); sparkle.x = self.x + (Math.random() * coinGraphics.width - coinGraphics.width / 2); sparkle.y = self.y + (Math.random() * coinGraphics.height - coinGraphics.height / 2); sparkle.coin = self; // Associate sparkle with the coin game.addChild(sparkle); } // Move the coin left self.x += self.speedX * gameSpeed; // Apply spin effect over Y axis coinGraphics.scale.x = Math.sin(self.x * 0.015); if (coot && coot.isMagnetActive && !self.collecting && self.x < 2048 * 0.9) { // Set initial target and mark as magnetized self.targetX = coot.x; self.targetY = coot.y; self.magnetized = true; } if (self.magnetized && !self.collecting) { // Continuously update target position to track Coot self.targetX = coot.x; self.targetY = coot.y; // Move directly toward Coot with increasing speed as it gets closer var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Calculate movement speed based on distance var speed = Math.max(5, 20 - distance / 30); // Move coin toward Coot self.x += dx / distance * speed * gameSpeed; self.y += dy / distance * speed * gameSpeed; // If very close to Coot, complete collection if (distance < 30) { self.collecting = true; // Mark as being collected to prevent double counting LK.getSound('coin').play(); coinCount++; storage.coins = coinCount; coinCounter.setText(Math.min(coinCount, 9999).toString()); coinIcon.x = -coinCounter.width - 10; // Check for life addition if (coinCount % 100 === 0 && coot && coot.lives < 3) { coot.lives++; heartIcons[coot.lives - 1].alpha = 1; } // Clean up sparkles game.children.forEach(function (child) { if (child instanceof GoldSparkle && child.coin === self) { child.destroy(); } }); // Remove from game if (self.parent) { self.parent.removeChild(self); } } } if (self.collecting && !self.tweenStarted) { // Set flag to prevent multiple tweens self.tweenStarted = true; // Create collection tween tween(self, { x: self.targetX, y: self.targetY }, { duration: 500, easing: tween.quartOut, onUpdate: function onUpdate(progress) { coinGraphics.scale.set(1 - progress * 0.9); }, onFinish: function onFinish() { if (self.targetX === coot.x && self.targetY === coot.y) { LK.getSound('coin').play(); // Play sound effect if the target is coot } // Count coin and update display coinCount++; storage.coins = coinCount; coinCounter.setText(Math.min(coinCount, 999).toString()); coinIcon.x = -coinCounter.width - 10; // Check for life addition if (coinCount % 100 === 0 && coot && coot.lives < 3) { coot.lives++; heartIcons[coot.lives - 1].alpha = 1; } // Clean up game.children.forEach(function (child) { if (child instanceof GoldSparkle && child.coin === self) { child.destroy(); } }); // Remove from game if (self.parent) { self.parent.removeChild(self); } } }); } else if (self.x < -coinGraphics.width / 2) { // Destroy the coin if it goes off screen self.destroy(); } }; }); var CollisionBlock = Container.expand(function () { var self = Container.call(this); var collisionBlockGraphics = self.attachAsset('Collisionblock', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); }); // Assets will be automatically created and loaded by the LK engine based on their usage in the code. // Example assets: 'coot', 'obstacle', 'background' // Class for the main character, the American coot var Coot = Container.expand(function () { var self = Container.call(this); var cootGraphics = self.attachAsset('coot', { anchorX: 0.5, anchorY: 0.5 }); // Add this to ensure cootGraphics is always at bottom self.ensureGraphicsOrder = function () { self.setChildIndex(cootGraphics, 0); if (cootGraphics.children.length > 0) { // Find hat if it exists for (var i = 0; i < cootGraphics.children.length; i++) { if (cootGraphics.children[i].isHat) { cootGraphics.setChildIndex(cootGraphics.children[i], cootGraphics.children.length - 1); break; } } } }; self.hasHat = false; // Flag to track if a hat is equipped // Add hat update method self.updateHat = function () { // Remove existing hat for (var i = 0; i < cootGraphics.children.length; i++) { if (cootGraphics.children[i].isHat) { cootGraphics.removeChild(cootGraphics.children[i]); break; self.ensureGraphicsOrder(); } ; } // Check if a hat is equipped var hatId = storage.equippedHat || null; if (hatId) { try { // Attach hat to cootGraphics for movement var hatId = storage.equippedHat || null; if (hatId) { try { // Find hat config var hatConfig = availableHats.find(function (hat) { return hat.id === hatId; }); if (hatConfig) { var hatGraphics = cootGraphics.attachAsset(hatId, { anchorX: 0.5, anchorY: 1.0, x: hatConfig.x, y: hatConfig.y, rotation: hatConfig.rotation }); hatGraphics.isHat = true; self.setChildIndex(cootGraphics, 0); cootGraphics.setChildIndex(hatGraphics, cootGraphics.children.length - 1); self.hasHat = true; } } catch (e) { console.error("Could not load hat asset: " + hatId); storage.equippedHat = null; self.hasHat = false; } } // Mark as hat hatGraphics.isHat = true; // Make sure cootGraphics is at the bottom of main container self.setChildIndex(cootGraphics, 0); // Set hat to top within cootGraphics cootGraphics.setChildIndex(hatGraphics, cootGraphics.children.length - 1); self.hasHat = true; } catch (e) { console.error("Could not load hat asset: " + hatId); storage.equippedHat = null; self.hasHat = false; } } else { self.hasHat = false; } }; self.originalX = self.x; // Store original X position self.speed = 6.5; self.dashSpeed = 15; self.lives = 3; // Initialize Coot with three lives self.dashDelay = 30; self.isFalling = false; self.isDashing = false; self.fallRotation = 0; // Initialize fall rotation self.dashTimer = 0; self.jumpVelocity = 40; // Increased initial upward velocity for jump self.gravity = 1.0; // Gravity to apply during jump self.jumpHeight = 105; self.isJumping = false; self.isReturning = false; // New state to handle returning to top after diving self.isInvincible = false; // Initialize invincible state self.isShielded = false; // Initialize shielded state self.isMagnetActive = false; // Initialize magnet state self.isWarningActive = false; // Initialize warning state self.isPowerDashActive = false; // Initialize PowerDash state self.hasPhoenixFeather = false; // Initialize Phoenix Feather state self.powerUpTimers = { 'CoinMagnet': { endTime: 0 }, 'PowerDash': { endTime: 0 }, 'Warning': { endTime: 0 } }; self.update = function () { if (self.isFalling) { handleFalling(); } else if (self.isDiving) { handleDiving(); } else if (self.returnDelay > 0) { handleReturnDelay(); } else if (self.isReturning) { handleReturning(); } // Define state key mapping for power-ups var stateKeyMap = { 'CoinMagnet': 'isMagnetActive', 'PowerDash': 'isPowerDashActive', 'Warning': 'isWarningActive' }; // Check power-up timers for (var powerUpType in self.powerUpTimers) { if (self.powerUpTimers.hasOwnProperty(powerUpType)) { var timer = self.powerUpTimers[powerUpType]; if (Date.now() >= timer.endTime) { var stateKey = stateKeyMap[powerUpType]; if (self[stateKey]) { self[stateKey] = false; // Deactivate the power-up } } } } function handleFalling() { if (self.lives <= 0) { self.y -= self.fallSpeed; self.fallRotation += 0.05; cootGraphics.rotation = -self.fallRotation; if (self.y <= self.fallStartY - 50) { self.fallSpeed = -10; } if (self.y > 2732) { LK.showGameOver(); } } else { self.y += self.gravity * 10; // Increase gravity effect during fall if (self.y >= self.originalY) { self.y = self.originalY; self.isFalling = false; self.jumpVelocity = 40; self.isJumping = false; } cootGraphics.rotation = 0; } } function handleDiving() { self.y += self.speed * 1.5; cootGraphics.alpha = Math.max(0.5, cootGraphics.alpha - 0.05); cootGraphics.tint = 0x0000ff; if (self.y >= 2732 * 0.90) { self.y = 2732 * 0.90; self.isDiving = false; self.returnDelay = Date.now() + 1000; } } function handleReturnDelay() { if (Date.now() >= self.returnDelay) { self.returnDelay = 0; if (self.y >= 2732 * 0.90) { self.isReturning = true; } } } function handleReturning() { self.y -= self.speed * 1.5; var transitionFactor = 1 - (self.y - self.originalY) / (2732 * 0.90 - self.originalY); cootGraphics.alpha = 0.5 + 0.5 * transitionFactor; var startTint = self.underwaterTint; var endTint = 0xffffff; var r = (startTint >> 16 & 0xff) + ((endTint >> 16 & 0xff) - (startTint >> 16 & 0xff)) * transitionFactor; var g = (startTint >> 8 & 0xff) + ((endTint >> 8 & 0xff) - (startTint >> 8 & 0xff)) * transitionFactor; var b = (startTint & 0xff) + ((endTint & 0xff) - (startTint & 0xff)) * transitionFactor; cootGraphics.tint = (r << 16) + (g << 8) + b; if (self.y <= self.originalY) { self.y = self.originalY; self.isReturning = false; cootGraphics.alpha = 1.0; cootGraphics.tint = 0xffffff; } if (self.isReturning) { self.x += (self.originalX - self.x) * 0.1; } } // Add wobble effect to the coot while running if (!self.isJumping && !self.isDiving && !self.isReturning && !self.isFalling) { cootGraphics.rotation = Math.sin(LK.ticks / 5) * 0.1; // Increase wobble speed by reducing the divisor // Generate 1-2 water splash particles every 60 ticks (1 second) only when not jumping, diving, or falling if (!self.isJumping && !self.isDiving && !self.isFalling && LK.ticks % 60 == 0) { var numParticles = Math.floor(Math.random() * 2) + 1; for (var i = 0; i < numParticles; i++) { var splashLeft = ObjectPool.get('Splash', Splash); splashLeft.x = self.x - cootGraphics.width / 2; splashLeft.y = self.y + cootGraphics.height / 2; game.addChildAt(splashLeft, game.getChildIndex(foreground1) - 1); var splashRight = ObjectPool.get('Splash', Splash); splashRight.x = self.x + cootGraphics.width / 2; splashRight.y = self.y + cootGraphics.height / 2; game.addChildAt(splashRight, game.getChildIndex(foreground1) - 1); } } } // Handle dash state if (self.isDashing) { if (self.dashTimer === 0) { LK.getSound('dashsound').play(); // Play dashsound when dash starts } if (self.dashTimer < self.dashDelay) { // Dash forward if (self.x < 2048 * 0.75) { // Stop at 3/4 of screen width self.x += self.dashSpeed * 1.1; } // Create echo trail effect only if PowerDash is active if (self.isPowerDashActive) { var echo = ObjectPool.get('EchoTrail', EchoTrail); echo.x = self.x; echo.y = self.y; game.addChild(echo); } self.dashTimer++; } else { var returnSpeed = 10; // Fixed return speed self.x += Math.sign(self.originalX - self.x) * Math.min(returnSpeed, Math.abs(self.originalX - self.x)); if (Math.abs(self.x - self.originalX) < returnSpeed) { self.x = self.originalX; self.isDashing = false; self.dashTimer = 0; } } } // Ensure smooth return to original position if falling and returning from a dash if (self.isFalling && self.isReturning) { var returnSpeed = 10; // Fixed return speed self.x += Math.sign(self.originalX - self.x) * Math.min(returnSpeed, Math.abs(self.originalX - self.x)); if (Math.abs(self.x - self.originalX) < returnSpeed) { self.x = self.originalX; self.isReturning = false; } } self.ensureGraphicsOrder(); }; self.isDiving = false; self.isDashing = false; self.dashSpeed = 15; self.dashDelay = 60; self.dashTimer = 0; self.originalX = self.x; self.jump = function () { if (canPerformAction()) { // Cancel any existing tweens on this object tween.stop(self); self.isJumping = true; LK.getSound('jumpsound').play(); self.originalX = self.x; self.isReturning = false; self.originalY = self.y; // Fixed jump height - much higher than before var jumpHeight = 805; // Try with a specific large value // Jump tween with steep curve tween(self, { y: self.y - jumpHeight }, { duration: 450, // Longer duration easing: tween.backOut, onFinish: function onFinish() { // Fall tween back to original position tween(self, { y: self.originalY }, { duration: 600, // Longer duration down too easing: tween.backIn, onFinish: function onFinish() { self.isJumping = false; } }); } }); } }; self.dash = function () { if (canPerformAction()) { self.isDashing = true; self.originalX = self.x; self.dashTimer = 0; } }; self.dive = function () { if (canPerformAction()) { LK.getSound('cootdive').play(); // Play cootdive sound effect when the coot starts to dive self.isDiving = true; self.returnDelay = Date.now() + 5000; self.isReturning = false; self.underwaterTint = 0x4444ff; self.originalX = self.x; self.originalY = self.y; self.y += self.speed * 2; generateSplashParticles(2, 4); } }; function canPerformAction() { return !self.isJumping && !self.isDiving && !self.isReturning && !self.isDashing; } function generateSplashParticles(min, max) { var numParticles = Math.floor(Math.random() * (max - min + 1)) + min; for (var i = 0; i < numParticles; i++) { var splash = ObjectPool.get('Splash', Splash); splash.x = self.x; splash.y = self.y + cootGraphics.height / 2; game.addChildAt(splash, game.getChildIndex(foreground1) - 1); } } }); var DayCountDisplay = Container.expand(function () { var self = Container.call(this); var dayText = new Text2('Day ' + DayCount, { size: 100, fill: 0xFFFFFF }); dayText.anchor.set(0.5, 0.5); dayText.alpha = 0; // Set alpha to 0 by default self.addChild(dayText); self.show = function () { dayText.setText('Day ' + DayCount); dayText.alpha = 1; LK.setTimeout(function () { dayText.alpha = 0; // Set alpha back to 0 instead of destroying }, 1500); // Set a timer to make the day count display visible for 3 seconds every time the day count increases LK.setTimeout(function () { dayText.alpha = 1; LK.setTimeout(function () { dayText.alpha = 0; }, 1500); }, 1500); }; }); var DuckWarningIcon = Container.expand(function () { var self = Container.call(this); var iconGraphics = self.attachAsset('DuckIcon', { anchorX: 0.5, anchorY: 0.5, alpha: 0.75 }); self.flashInterval = 0; self.update = function () { self.flashInterval++; if (coot.isWarningActive) { if (self.flashInterval % 30 < 15) { iconGraphics.alpha = 0.75; } else { iconGraphics.alpha = 0.5; } } else { iconGraphics.alpha = 0; } }; }); var EagleFeather = Container.expand(function () { var self = Container.call(this); var featherGraphics; self.rotationSpeed = 0; self.driftX = 0; self.driftY = 0; self.fadeRate = 0.005; self.init = function () { if (!featherGraphics) { featherGraphics = self.attachAsset('Eaglefeather', { anchorX: 0.5, anchorY: 0.5 }); } // Initialize feather properties self.rotationSpeed = Math.random() * 0.02 - 0.01; self.driftX = Math.random() * 2 - 1; self.driftY = Math.random() * -1 - 0.5; featherGraphics.alpha = 1; return self; }; self.reset = function () { self.rotationSpeed = Math.random() * 0.02 - 0.01; self.driftX = Math.random() * 2 - 1; self.driftY = Math.random() * -1 - 0.5; featherGraphics.alpha = 1; featherGraphics.rotation = 0; return self; }; self.destroy = function () { if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('EagleFeather', self); }; self.update = function () { self.x += self.driftX * gameSpeed; self.y += self.driftY * gameSpeed; featherGraphics.rotation += self.rotationSpeed; featherGraphics.alpha -= self.fadeRate; // Destroy feather when fully faded if (featherGraphics.alpha <= 0) { self.destroy(); } }; return self.init(); }); var EagleWarningIcon = Container.expand(function () { var self = Container.call(this); var iconGraphics = self.attachAsset('EagleIcon', { anchorX: 0.5, anchorY: 0.5, alpha: 0.75 }); self.flashInterval = 0; self.update = function () { self.flashInterval++; if (coot.isWarningActive) { if (self.flashInterval % 30 < 15) { iconGraphics.alpha = 0.75; } else { iconGraphics.alpha = 0.5; } } else { iconGraphics.alpha = 0; } }; }); var EchoTrail = Container.expand(function () { var self = Container.call(this); var echoGraphics; self.fadeRate = 0.05; self.init = function () { if (!echoGraphics) { echoGraphics = self.attachAsset('coot', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } else { echoGraphics.alpha = 0.5; } return self; }; self.reset = function () { if (echoGraphics) { echoGraphics.alpha = 0.5; } return self; }; self.destroy = function () { if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('EchoTrail', self); }; self.update = function () { echoGraphics.alpha -= self.fadeRate; if (echoGraphics.alpha <= 0) { self.destroy(); } }; return self.init(); }); var Firefly = Container.expand(function () { var self = Container.call(this); var fireflyGraphics = self.attachAsset('Firefly', { anchorX: 0.5, anchorY: 0.5 }); // Initialize firefly properties self.speedX = Math.random() * 8 - 4; // Further increased random horizontal speed self.speedY = Math.random() * 8 - 4; // Further increased random vertical speed self.fadeRate = 0.005; // Much slower fade rate for slow pulsing self.flickerTimer = Math.random() * 240 + 120; // Random flicker timer between 2 to 4 seconds self.alphaDirection = 1; // Direction of alpha change (1 for fade in, -1 for fade out) self.lifetime = Math.random() * 180 + 180; // Random lifetime between 3 to 5 seconds self.update = function () { // Move the firefly self.x += self.speedX; self.y += self.speedY; // Create trail effect var trail = ObjectPool.get('FireflyTrail', FireflyTrail); trail.x = self.x; trail.y = self.y; game.addChild(trail); // Loop around the screen if (self.x < 0) { self.x = 2048; } if (self.x > 2048) { self.x = 0; } if (self.y < 0) { self.y = 2732; } if (self.y > 2732) { self.y = 0; } // Flicker effect self.flickerTimer--; if (self.flickerTimer <= 0) { fireflyGraphics.alpha = Math.random(); // Random alpha for flicker self.flickerTimer = Math.random() * 60 + 30; // Reset flicker timer } // Fade in and out fireflyGraphics.alpha += self.fadeRate * self.alphaDirection; if (fireflyGraphics.alpha <= 0 || fireflyGraphics.alpha >= 1) { self.alphaDirection *= -1; // Reverse fade direction } // Destroy firefly after its lifetime self.lifetime--; if (self.lifetime <= 0) { self.destroy(); } }; }); var FireflyTrail = Container.expand(function () { var self = Container.call(this); var trailGraphics; self.fadeRate = 0.02; self.init = function () { if (!trailGraphics) { trailGraphics = self.attachAsset('FireflyTrail', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); } else { trailGraphics.alpha = 1; } return self; }; self.reset = function () { if (trailGraphics) { trailGraphics.alpha = 1; } return self; }; self.destroy = function () { if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('FireflyTrail', self); }; self.update = function () { trailGraphics.alpha -= self.fadeRate; if (trailGraphics.alpha <= 0) { self.destroy(); } }; return self.init(); }); var FishWarningIcon = Container.expand(function () { var self = Container.call(this); var iconGraphics = self.attachAsset('FishIcon', { anchorX: 0.5, anchorY: 0.5, alpha: 0.75 }); self.flashInterval = 0; self.update = function () { self.flashInterval++; if (coot.isWarningActive) { if (self.flashInterval % 30 < 15) { iconGraphics.alpha = 0.75; } else { iconGraphics.alpha = 0.5; } } else { iconGraphics.alpha = 0; } }; }); // Define a single obstacleTypes array as a constant // Class for the foreground var Foreground = Container.expand(function () { var self = Container.call(this); var foregroundGraphics = self.attachAsset('Foreground', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.isFirst = false; // Will be set during initialization self.update = function () { // Only move the first piece if (self.isFirst) { self.x -= self.speed * gameSpeed; // Apply gameSpeed to movement // Move second piece to maintain fixed distance self.other.x = self.x + self.width; // Reset both pieces when first goes off screen if (self.x < -self.width / 1.5) { // Reset earlier - when piece is mostly off screen self.x += self.width; self.other.x = self.x + self.width; } } }; }); var GoldSparkle = Container.expand(function () { var self = Container.call(this); var sparkleGraphics; // Initialize variables but don't create graphics yet self.speedX = 0; self.speedY = 0; self.fadeRate = 0.02; self.coin = null; // Reference to associated coin self.init = function () { // Only create graphics if they don't exist if (!sparkleGraphics) { sparkleGraphics = self.attachAsset('GoldSparkle', { anchorX: 0.5, anchorY: 0.5 }); } // Set initial properties self.speedX = (Math.random() * 2 - 1) * 0.75; self.speedY = (Math.random() * 2 - 1) * 0.75; sparkleGraphics.alpha = 1; return self; }; self.reset = function () { // Reset properties without recreating the graphics self.speedX = (Math.random() * 2 - 1) * 0.75; self.speedY = (Math.random() * 2 - 1) * 0.75; self.coin = null; if (sparkleGraphics) { sparkleGraphics.alpha = 1; } return self; }; self.cleanup = function () { // Clear any references to other objects self.coin = null; }; self.destroy = function () { // Instead of destroying, return to pool if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('GoldSparkle', self); }; self.update = function () { self.x += self.speedX; self.y += self.speedY; sparkleGraphics.alpha -= self.fadeRate; if (sparkleGraphics.alpha <= 0) { self.destroy(); // This now recycles instead of destroying } }; return self.init(); // Initialize on creation }); var HatShopButton = Container.expand(function () { var self = Container.call(this); var hatShopButtonGraphics = self.attachAsset('HatShopButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function () { gameLogo.visible = false; if (gameLogo.playButton) { gameLogo.playButton.visible = false; } if (gameLogo.instructionsButton) { gameLogo.instructionsButton.visible = false; } if (gameLogo.hatShopButton) { gameLogo.hatShopButton.visible = false; } showHatShop(); }; }); var HatShopScreen = Container.expand(function () { var self = Container.call(this); // Title var shopTitle = new Text2('Hat Shop', { size: 100, fill: 0xFFFFFF, fontWeight: "bold" }); shopTitle.anchor.set(0.5, 0); shopTitle.x = 2048 / 2; shopTitle.y = 2732 * 0.15; self.addChild(shopTitle); // Initialize purchased hats array if not present if (!storage.purchasedHats) { storage.purchasedHats = []; } // Hat grid var gridItems = []; var itemsPerRow = 3; var itemWidth = 400; var itemHeight = 400; var padding = 50; var startX = 2048 / 2 - (itemWidth + padding) * (itemsPerRow / 2) + itemWidth / 2 + 2048 * 0.01; var startY = 2732 * 0.27; availableHats.forEach(function (hat, index) { var row = Math.floor(index / itemsPerRow); var col = index % itemsPerRow; var itemContainer = new Container(); itemContainer.x = startX + col * (itemWidth + padding); itemContainer.y = startY + row * (itemHeight + padding); // Background var bg = LK.getAsset('Collisionblock', { anchorX: 0.5, anchorY: 0.5, width: itemWidth, height: itemHeight, alpha: 0.5 }); itemContainer.addChild(bg); // Hat image var hatImg = LK.getAsset(hat.id, { anchorX: 0.5, anchorY: 0.5, y: -50, scaleX: 1.35, // Increase width by 25% scaleY: 1.35 // Increase height by 25% }); itemContainer.addChild(hatImg); // Hat name var nameText = new Text2(hat.name, { size: 50, // Increased by 15% fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0); nameText.y = 50; itemContainer.addChild(nameText); // Price or status var isPurchased = storage.purchasedHats && storage.purchasedHats.indexOf(hat.id) !== -1; var isEquipped = storage.equippedHat === hat.id; var statusText; if (isEquipped) { statusText = new Text2('EQUIPPED', { size: 40, fill: 0x00FF00 }); } else if (isPurchased) { statusText = new Text2('OWNED', { size: 40, fill: 0xAAAAAA }); } else { statusText = new Text2(hat.price + ' coins', { size: 40, // Increased by 15% fill: 0xFFD700 }); } statusText.anchor.set(0.5, 0); statusText.y = 100; itemContainer.addChild(statusText); // Add interaction itemContainer.down = function () { handleHatSelection(hat, statusText); }; self.addChild(itemContainer); gridItems.push(itemContainer); }); // Back button var backButton = new Text2('Back', { size: 100, fill: 0xFFFFFF, fontWeight: "bold" }); backButton.anchor.set(0.5, 0.5); backButton.x = 2048 / 2; backButton.y = 2732 * 0.875; self.addChild(backButton); backButton.down = function () { self.menuBackground.destroy(); self.destroy(); isTitleScreen = true; gameLogo.visible = true; if (gameLogo.playButton) { gameLogo.playButton.visible = true; } if (gameLogo.instructionsButton) { gameLogo.instructionsButton.visible = true; } if (gameLogo.hatShopButton) { gameLogo.hatShopButton.visible = true; } }; function handleHatSelection(hat, statusText) { var isPurchased = storage.purchasedHats && storage.purchasedHats.indexOf(hat.id) !== -1; var isEquipped = storage.equippedHat === hat.id; if (isEquipped) { // Unequip hat storage.equippedHat = null; // Update UI self.menuBackground.destroy(); self.destroy(); showHatShop(); } else if (isPurchased) { // Equip hat storage.equippedHat = hat.id; // Update UI self.menuBackground.destroy(); self.destroy(); showHatShop(); } else if (storage.coins >= hat.price) { // Purchase hat storage.coins -= hat.price; // Initialize array if needed if (!storage.purchasedHats) { storage.purchasedHats = []; } // Get current purchased hats as array var currentHats = getPurchasedHats(); // Add new hat currentHats.push(hat.id); // Save back to storage savePurchasedHats(currentHats); storage.equippedHat = hat.id; // Update UI if (typeof coinDisplay !== 'undefined') { coinDisplay.setText('Coins: ' + storage.coins); } // Update coin counter in game coinCount = storage.coins; coinCounter.setText(Math.min(coinCount, 9999).toString()); // Refresh shop self.menuBackground.destroy(); self.destroy(); showHatShop(); // Show purchase confirmation var confirmText = new Text2('Purchased ' + hat.name + '!', { size: 100, fill: 0x00FF00 }); confirmText.anchor.set(0.5, 0.5); confirmText.x = 2048 / 2; confirmText.y = 2732 / 2; game.addChild(confirmText); LK.setTimeout(function () { confirmText.destroy(); }, 1500); // Play purchase sound LK.getSound('coin').play(); } else { // Not enough coins var errorText = new Text2('Not enough coins!', { size: 100, fill: 0xFF0000 }); errorText.anchor.set(0.5, 0.5); errorText.x = 2048 / 2; errorText.y = 2732 / 2; game.addChild(errorText); LK.setTimeout(function () { errorText.destroy(); }, 1500); } } }); var InstructionsButton = Container.expand(function () { var self = Container.call(this); var instructionsButtonGraphics = self.attachAsset('InstructionsButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function () { gameLogo.visible = false; if (gameLogo.playButton) { gameLogo.playButton.visible = false; } if (gameLogo.instructionsButton) { gameLogo.instructionsButton.visible = false; } showInstructions(); }; }); var InstructionsScreen = Container.expand(function () { var self = Container.call(this); var instructionsText = new Text2('Swipe up to jump,\ndown to dive,\nand right to dash!', { size: 80, fill: 0xFFFFFF, align: "center" }); instructionsText.anchor.set(0.5, 0); instructionsText.x = 2048 / 2; instructionsText.y = 2732 * 0.15; self.addChild(instructionsText); // Add power-up icons and explanations var powerUpsInfo = [{ type: 'CoinMagnet', text: 'Coin Magnet: Attracts coins' }, { type: 'Shield', text: 'Shield: Protects from one hit' }, { type: 'PhoenixFeather', text: 'Phoenix Feather: Revive once' }, { type: 'PowerDash', text: 'Power Dash: Dash while jumping or diving' }, { type: 'Warning', text: 'Warning: Alerts of upcoming obstacles' }]; powerUpsInfo.forEach(function (info, index) { var icon = LK.getAsset(info.type, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 300 - 2048 * 0.10, // Move icons further left y: 2732 * 0.30 + index * 200 }); self.addChild(icon); var text = new Text2(info.text, { size: 60, fill: 0xFFFFFF, align: "left" }); text.anchor.set(0, 0.5); text.x = 2048 / 2 - 300 + 2048 * 0.035 - 2048 * 0.07; text.y = icon.y + 20; self.addChild(text); }); var instructionDetails = new Text2('Jump over the Duck,\nDive away from the Eagle/Owl,\nDash away from the Fish.\n100 Coot Coins = 1 heart.', { size: 70, fill: 0xFFFFFF, align: "center" }); instructionDetails.anchor.set(0.5, 0); instructionDetails.x = 2048 / 2; instructionDetails.y = 2732 * 0.66; // Move up by 5% from the original position self.addChild(instructionDetails); var backButton = new Text2('Back', { size: 100, fill: 0xFFFFFF, fontWeight: "bold" }); backButton.anchor.set(0.5, 0.5); backButton.x = 2048 / 2; backButton.y = 2732 * 0.88; // Move back button down by 1.5% self.addChild(backButton); backButton.down = function () { self.menuBackground.destroy(); // Remove the MenuBackground self.destroy(); isTitleScreen = true; gameLogo.visible = true; if (gameLogo.playButton) { gameLogo.playButton.visible = true; } if (gameLogo.instructionsButton) { gameLogo.instructionsButton.visible = true; } }; }); // Class for the midgroundtrees var Midgroundtrees = Container.expand(function () { var self = Container.call(this); var midgroundtreesGraphics = self.attachAsset('Midgroundtrees', { anchorX: 0.5, anchorY: 0.7 }); self.speed = 3; self.update = function () { self.x -= self.speed * gameSpeed; // self.y = coot.y; if (self.x <= -self.width / 2) { self.x += self.width * 2; } }; }); var Moon = Container.expand(function () { var self = Container.call(this); var moonGraphics = self.attachAsset('Moon', { anchorX: 0.5, anchorY: 0.5 }); // Initialize moon properties self.startX = -moonGraphics.width / 2; // Start off-screen to the left self.startY = 2732 * 0.25; // Match the Sun's position (25% from the top) self.endX = 2048 + moonGraphics.width / 2; // End off-screen to the right self.arcHeight = 2732 * 0.1; // Match the Sun's arc height self.duration = 2 * 60 * 60; // 2 minutes in ticks (assuming 60 FPS) self.ticks = 0; // For the Moon class, replace the update function with: self.update = function () { if (!self.tweenStarted) { // Set initial position self.x = self.startX; self.y = self.startY; self.tweenStarted = true; // First tween: Move up in an arc tween(self, { x: self.startX + (self.endX - self.startX) * 0.5, y: self.startY - self.arcHeight }, { duration: 60 * 1000, // 1 minute in milliseconds easing: tween.sineInOut, onFinish: function onFinish() { // Second tween: Move down in an arc to end position tween(self, { x: self.endX, y: self.startY }, { duration: 60 * 1000, // 1 minute in milliseconds easing: tween.sineInOut, onFinish: function onFinish() { self.destroy(); // Switch to day state isDay = true; isNight = false; DayCount += 1; dayCountDisplay.show(); // Stop spawning fireflies if (fireflySpawnInterval) { LK.clearInterval(fireflySpawnInterval); fireflySpawnInterval = null; } var newSun = new Sun(); newSun.x = newSun.startX; // Use the sun's defined starting X position newSun.y = newSun.startY; // Set the proper starting Y position game.addChild(newSun); } }); } }); } }; }); // Moved Owl logic into Obstacle class var Obstacle = Container.expand(function (type) { var self = Container.call(this); var graphics; var collisionBlock = self.addChild(new CollisionBlock()); collisionBlock.x = 0; collisionBlock.y = 0; graphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); // Add a Ripple instance to the Duck obstacle if (type === 'Duck') { self.lastRippleTime = Date.now(); var ripple = ObjectPool.get('Ripple', Ripple); ripple.x = 0; // Center the ripple on the Duck ripple.y = graphics.height / 2; // Position the ripple at the bottom of the Duck self.addChildAt(ripple, 0); // Add ripple below the Duck but above the water layer } self.speedX = -6; if (type === 'Fish') { self.isJumping = false; self.pauseTime = 0; graphics.tint = 0x4444ff; graphics.alpha = 0.7; } if (type === 'Fish') { self.speedX = -6; // Back to original fast swimming speed self.jumpSpeed = 0.05; // Slow jump speed control self.isJumping = false; self.isPausing = false; self.pauseTime = 0; self.lastSplashTime = Date.now(); // Add splash timer graphics.tint = 0x4444ff; // Set underwater blue tint initially graphics.alpha = 0.7; // Set underwater opacity initially self.isFalling = false; self.jumpVelocity = 0; self.jumpStartY = self.y; // Store original position self.jumpTime = 0; // Initialize jump time counter self.y = 2732 * 0.90; // Set Fish Y position to the bottom of the Coot's dive } if (type === 'Eagle') { self.lastFeatherTime = Date.now(); self.targetY = coot.isDiving || coot.isReturning ? coot.originalY : coot.y; self.speedY = (self.targetY - self.y) / 100; self.speedX = -8; // Add horizontal speed variable for eagle } if (type === 'Owl') { self.speedX = -6; // Speed of the owl moving left self.speedY = 0; // Initial vertical speed self.x = 2048 + graphics.width / 2; // Spawn at the top right of the screen self.isDiving = false; // Initialize isDiving state self.hasDived = false; // Initialize hasDived state to false by default if (!self.soundPlayed && self.x >= 2048 - 50) { LK.getSound('owl').play(); self.soundPlayed = true; // Set flag to prevent repeating } } self.update = function () { self.x += self.speedX * gameSpeed; if (type === 'Fish') { // Move horizontally self.x += self.speedX; // Generate underwater splash effects if (!self.isJumping && Date.now() - self.lastSplashTime >= 200) { // Generate every 200ms var numSplashes = Math.floor(Math.random() * 2) + 1; // 1-2 splashes for (var i = 0; i < numSplashes; i++) { var splash = ObjectPool.get('Splash', Splash); splash.x = self.x + (Math.random() * graphics.width - graphics.width / 2); // Random position along fish body splash.y = self.y; splash.tint = 0x4444ff; // Match fish's underwater tint game.addChildAt(splash, game.getChildIndex(self) - 1); } self.lastSplashTime = Date.now(); } // Check if crossing under Coot if (self.x <= coot.x && !self.isJumping) { self.speedX = 0; graphics.alpha = 0; self.pauseTime += 0.02; // Add this check for when to reappear if (self.pauseTime >= 1 && !self.isJumping) { LK.getSound('fishsplash').play(); graphics.alpha = 1; graphics.rotation = Math.PI / 2; self.isJumping = true; self.jumpStartY = self.y; // Create splash burst when starting jump var burstSplashes = Math.floor(Math.random() * 4) + 6; for (var i = 0; i < burstSplashes; i++) { var splash = ObjectPool.get('Splash', Splash); splash.x = self.x + (Math.random() * graphics.width - graphics.width / 2); splash.y = self.jumpStartY - Math.random() * 200; game.addChildAt(splash, game.getChildIndex(self) - 1); } // Create jump tween // Change the tint directly at specific points instead of in onUpdate // Create jump tween with faster duration tween(self, { y: self.jumpStartY - 864 // Jump height }, { duration: 350, // 0.4 seconds up easing: tween.sineOut, onFinish: function onFinish() { // Create fall tween with faster duration tween(self, { y: self.jumpStartY + 50 // Go slightly below starting point }, { duration: 300, // 0.4 seconds down easing: tween.sineIn, onFinish: function onFinish() { Obstacle.lastDestroyTime = Date.now(); currentObstacle = null; self.destroy(); } }); } }); } } if (self.isJumping) { // Hardcoded tint change based on absolute position var jumpProgress = Math.abs(self.y - self.jumpStartY) / 864; if (self.y < self.jumpStartY - 100) { graphics.tint = 0xffffff; graphics.alpha = 1.0; } else { graphics.tint = 0x4444ff; graphics.alpha = 0.7; } } } else if (type === 'Eagle') { self.y += self.speedY; if (type === 'Eagle' && !self.soundPlayed && self.x >= 2048 - 50) { LK.getSound('eagle').play(); self.soundPlayed = true; // Set flag to prevent repeating } if (Date.now() - self.lastFeatherTime >= 900) { // Feather spawn every 900ms var numFeathers = Math.floor(Math.random() * 2) + 2; // Spawn 2-3 feathers for (var i = 0; i < numFeathers; i++) { var feather = ObjectPool.get('EagleFeather', EagleFeather); feather.x = self.x + (Math.random() * 20 - 10); // Slight horizontal variation feather.y = self.y + graphics.height / 2; game.addChildAt(feather, game.getChildIndex(self) - 1); } self.lastFeatherTime = Date.now(); } if (self.x <= -self.width / 2) { self.destroy(); // Destroy the obstacle when it moves off-screen Obstacle.lastDestroyTime = Date.now(); // Set lastDestroyTime when destroyed console.log("Obstacle destroyed at " + Obstacle.lastDestroyTime); } if (type === 'Eagle') { self.targetY = coot.originalY - coot.height / 2; // Aim slightly higher on the coot self.speedY = (self.targetY - self.y) / (50 / gameSpeed); self.lastWasSwooping = self.y > self.targetY; } } else if (type === 'Duck') { // Add sinusoidal wave pattern travel for Duck if (type === 'Duck') { self.y += Math.sin(self.x * 0.00625) * 2.7; // Adjusted sinusoidal wave pattern with further reduced frequency and increased amplitude } if (type === 'Duck') { // Play duck sound every 2 seconds if (LK.ticks % 100 == 0) { // 120 frames = 2 seconds at 60 FPS LK.getSound('duck').play(); } } // Ripple spawn logic if (Date.now() - self.lastRippleTime >= 500) { var ripple = ObjectPool.get('Ripple', Ripple); ripple.x = self.x; ripple.y = self.y + graphics.height / 2; game.addChildAt(ripple, game.getChildIndex(self) - 1); self.lastRippleTime = Date.now(); } // Existing destroy logic if (self.x <= -self.width / 2) { self.destroy(); Obstacle.lastDestroyTime = Date.now(); console.log("Obstacle destroyed at " + Obstacle.lastDestroyTime); } } else if (type === 'Owl') { if (coot) { if (!self.isDiving && self.x > coot.x) { self.x += self.speedX * gameSpeed; // Move Owl left until it reaches Coot's X position } else { if (!self.hasDived) { self.isDiving = true; // Set isDiving state if (coot.intersects(collisionBlock)) { self.hasDived = true; // Set hasDived state only on intersection with Coot } self.speedX = 0; // Stop left movement if (!coot.isDiving) { self.speedY = (coot.y - self.y) / 40; // Adjust speed to track Coot's Y position at half speed self.y += self.speedY * gameSpeed; // Move Owl towards Coot self.x += (coot.x - self.x) / 20 * gameSpeed; // Move Owl towards Coot's X position } if (self.y >= coot.originalY) { self.isDiving = false; // Remove isDiving state self.speedX = -6; // Set speed to fly away to the left self.speedY = -3; // Add upward movement } else if (self.isDiving) { var shadowClone = ObjectPool.get('ShadowClone', ShadowClone); shadowClone.x = self.x; shadowClone.y = self.y; game.addChild(shadowClone); } } } // Check if Coot's state requires Owl to fly off if (self.isDiving && (coot.isDiving || coot.isReturning || coot.returnDelay > 0 || coot.intersects(collisionBlock))) { self.isDiving = false; // Remove isDiving state self.speedX = -6; // Set speed to fly away to the left self.speedY = -3; // Add upward movement self.x += self.speedX * gameSpeed; self.y += self.speedY * gameSpeed; // Move Owl upwards as it flies away if (self.x < -self.width / 2) { self.destroy(); // Remove Owl from the game when off-screen } } } } collisionBlock.x = 0; collisionBlock.y = 0; }; }); var OwlWarningIcon = Container.expand(function () { var self = Container.call(this); var iconGraphics = self.attachAsset('OwlIcon', { anchorX: 0.5, anchorY: 0.5, alpha: 0.75 }); self.flashInterval = 0; self.update = function () { self.flashInterval++; if (coot.isWarningActive) { if (self.flashInterval % 30 < 15) { iconGraphics.alpha = 0.75; } else { iconGraphics.alpha = 0.5; } } else { iconGraphics.alpha = 0; } }; }); var PhoenixFeatherIcon = Container.expand(function () { var self = Container.call(this); var iconGraphics = self.attachAsset('PhoenixFeatherIcon', { anchorX: 0.5, anchorY: 0.5, alpha: 0.2 // Start dim, not opaque }); self.update = function () { iconGraphics.alpha = coot && coot.hasPhoenixFeather ? 1 : 0.2; // Set alpha based on possession }; }); var PlayButton = Container.expand(function () { var self = Container.call(this); var playButtonGraphics = self.attachAsset('PlayButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function () { // Exit title screen LK.getSound('powerup').play(); // Play coothurt sound LK.effects.flashScreen(0xFFFFFF, 300); // Flash screen red for 100ms LK.setTimeout(function () { // Slide out all elements isTitleScreen = false; var slideOutInterval = LK.setInterval(function () { gameLogo.x += 50; self.x += 50; if (gameLogo.instructionsButton) { gameLogo.instructionsButton.x += 50; } // Make sure to include the hat shop button here if (gameLogo.hatShopButton) { gameLogo.hatShopButton.x += 50; } if (gameLogo.x > 2048 + gameLogo.width / 2) { LK.clearInterval(slideOutInterval); self.destroy(); if (gameLogo.instructionsButton) { gameLogo.instructionsButton.destroy(); } if (gameLogo.hatShopButton) { gameLogo.hatShopButton.destroy(); } // Start game after animations startGame(); } }, 16); }, 500); }; }); var PowerUp = Container.expand(function (type) { var self = Container.call(this); var powerUpGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); // Initialize power-up properties self.speedX = -5; // Speed of the power-up moving left self.collected = false; // Flag to check if the power-up is collected self.update = function () { // Add pulsating effect var pulseScale = 0.05 * Math.sin(LK.ticks * 0.1) + 1; powerUpGraphics.scale.set(pulseScale); // Add bobbing effect self.y += Math.sin(LK.ticks * 0.05) * 0.5; // Move the power-up left self.x += self.speedX * gameSpeed; // Check for collection by the Coot if (coot && !self.collected && coot.intersects(self)) { if (type === 'PhoenixFeather' && coot.hasPhoenixFeather || type === 'Shield' && coot.isShielded) { return; // Do not collect if already active } self.collected = true; activatePowerUp(type); self.destroy(); } // Destroy the power-up if it goes off screen if (self.x < -powerUpGraphics.width / 2) { self.destroy(); } }; function activatePowerUp(type) { LK.getSound('powerup').play(); // Play powerup sound effect when a power-up is collected var powerUpConfig = { 'CoinMagnet': { duration: 15000, state: 'isMagnetActive' }, 'PowerDash': { duration: 30000, state: 'isPowerDashActive' }, 'Warning': { duration: 30000, state: 'isWarningActive' }, 'Shield': { duration: 0, // Shield is instant and doesn't have a duration state: 'isShielded' }, 'PhoenixFeather': { duration: 0, // Phoenix Feather is instant and doesn't have a duration state: 'hasPhoenixFeather' } }; var config = powerUpConfig[type]; var startTime = Date.now(); if (config) { // Removed interval-based state management if (type === 'Shield') { coot.isShielded = true; coot.shieldGraphics = coot.addChild(LK.getAsset('Shield', { anchorX: 0.5, anchorY: 0.5, scaleX: coot.width / 200, // Scale to cover Coot scaleY: coot.height / 204.2, // Scale to cover Coot alpha: 0.5 // Set opacity to 50% })); return; // Exit early as Shield doesn't need a timer } if (type === 'PhoenixFeather') { coot.hasPhoenixFeather = true; return; // Exit early as Phoenix Feather doesn't need a timer } coot[config.state] = true; // Ensure state is set to true coot.powerUpTimers[type].endTime = Date.now() + config.duration; // Set power-up end time var existingPowerUp = powerUpDisplay.activePowerUps.find(function (p) { return p.type === type; }); if (existingPowerUp) { // Calculate remaining time in milliseconds var timeRemaining = existingPowerUp.startTime + existingPowerUp.duration - Date.now(); if (timeRemaining > 0) { config.duration += timeRemaining; // Add remaining time to new duration startTime = Date.now(); // Reset start time to now for accurate duration } LK.clearInterval(existingPowerUp.interval); existingPowerUp.startTime = Date.now(); // Update startTime to reflect new total duration existingPowerUp.duration = config.duration; // Update duration existingPowerUp.interval = createInterval(config, existingPowerUp.startTime); existingPowerUp.timer = config.duration / 1000; // Update visual timer return; // Exit early as we have updated the existing power-up } powerUpDisplay.addPowerUp(type, config.duration / 1000, startTime); // Include startTime for accurate remaining time } } }); var PowerUpDisplay = Container.expand(function () { var self = Container.call(this); self.x = 2048 / 2; // Center horizontally self.y = 2732 * 0.9; // Position at bottom center self.activePowerUps = []; self.update = function () { // Update each power-up display self.activePowerUps.forEach(function (powerUp, index) { powerUp.timer -= (Date.now() - powerUp.lastUpdateTime) / 1000; // Decrease timer based on real time powerUp.lastUpdateTime = Date.now(); // Update the last update time powerUp.text.setText(Math.max(0, Math.ceil(powerUp.timer)) + 's'); // Ensure timer doesn't show negative values // Remove power-up if timer reaches 0 if (powerUp.timer <= 0) { powerUp.icon.destroy(); powerUp.text.destroy(); self.activePowerUps.splice(index, 1); self.repositionPowerUps(); } }); }; self.addPowerUp = function (type, duration) { var existingPowerUp = self.activePowerUps.find(function (p) { return p.type === type; }); if (existingPowerUp) { existingPowerUp.timer += duration; existingPowerUp.lastUpdateTime = Date.now(); existingPowerUp.text.setText(Math.max(0, Math.ceil(existingPowerUp.timer)) + 's'); // Update visual timer return; } var iconAssetMap = { 'CoinMagnet': 'CoinMagnet', 'PowerDash': 'PowerDash', 'Warning': 'Warning', 'Shield': 'Shield', 'PhoenixFeather': 'PhoenixFeather' }; if (iconAssetMap[type]) { var icon = LK.getAsset(iconAssetMap[type], { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); } else { console.error("Power-up type not found in iconAssetMap: ", type); return; } var text = new Text2(duration + 's', { size: 100, fill: 0xFFFFFF }); text.anchor.set(0.5, 0.5); self.addChild(icon); self.addChild(text); self.activePowerUps.push({ icon: icon, text: text, timer: duration, type: type, lastUpdateTime: Date.now() }); self.repositionPowerUps(); }; self.repositionPowerUps = function () { var totalWidth = self.activePowerUps.reduce(function (acc, powerUp) { return acc + powerUp.icon.width + powerUp.text.width + 40; // 40 is the new spacing }, 0); var startX = -totalWidth / 2; self.activePowerUps.forEach(function (powerUp) { powerUp.icon.x = startX + powerUp.icon.width / 2; powerUp.text.x = powerUp.icon.x + powerUp.icon.width / 2 + 40; // 40 is the new spacing between icon and text startX += powerUp.icon.width + powerUp.text.width + 20; }); }; }); var Ripple = Container.expand(function () { var self = Container.call(this); var rippleGraphics; self.initialScale = 0.05; self.growthRate = 0.02; self.fadeRate = 0.01; self.maxScale = 2.0; self.init = function () { if (!rippleGraphics) { rippleGraphics = self.attachAsset('Ripple', { anchorX: 0.5, anchorY: 0.5 }); } rippleGraphics.scaleX = self.initialScale; rippleGraphics.scaleY = self.initialScale; rippleGraphics.alpha = 1; return self; }; self.reset = function () { rippleGraphics.scaleX = self.initialScale; rippleGraphics.scaleY = self.initialScale; rippleGraphics.alpha = 1; return self; }; self.destroy = function () { if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('Ripple', self); }; self.update = function () { rippleGraphics.scaleX += self.growthRate; rippleGraphics.scaleY += self.growthRate; rippleGraphics.alpha -= self.fadeRate; if (rippleGraphics.scaleX >= self.maxScale || rippleGraphics.alpha <= 0) { self.destroy(); } }; return self.init(); }); var ShadowClone = Container.expand(function () { var self = Container.call(this); var cloneGraphics; self.fadeRate = 0.05; self.init = function () { if (!cloneGraphics) { cloneGraphics = self.attachAsset('Owl', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } else { cloneGraphics.alpha = 0.5; } return self; }; self.reset = function () { if (cloneGraphics) { cloneGraphics.alpha = 0.5; } return self; }; self.destroy = function () { if (self.parent) { self.parent.removeChild(self); } ObjectPool.recycle('ShadowClone', self); }; self.update = function () { cloneGraphics.alpha -= self.fadeRate; if (cloneGraphics.alpha <= 0) { self.destroy(); } }; return self.init(); }); // Static respawn delay property // Class for the water splash particles var Splash = Container.expand(function () { var self = Container.call(this); var splashGraphics; var scale; // Initialize variables but don't create graphics self.speedX = 0; self.speedY = 0; self.gravity = 0.1; self.init = function () { // Only create graphics if they don't exist if (!splashGraphics) { scale = Math.random() * 0.75 + 0.25; splashGraphics = self.attachAsset('Watersplash', { anchorX: 0.5, anchorY: 0.5, scaleX: scale, scaleY: scale }); } // Set initial properties self.speedX = Math.random() * 2 - 1; self.speedY = -Math.random() * 5; splashGraphics.alpha = 1; return self; }; self.reset = function () { // Reset properties without recreating the graphics self.speedX = Math.random() * 2 - 1; self.speedY = -Math.random() * 5; if (splashGraphics) { splashGraphics.alpha = 1; splashGraphics.rotation = 0; } return self; }; self.cleanup = function () { // Clear any references to other objects self.coin = null; }; self.destroy = function () { // Instead of destroying, return to pool self.parent.removeChild(self); ObjectPool.recycle('Splash', self); }; self.update = function () { self.x += self.speedX * gameSpeed; self.y += self.speedY * gameSpeed; self.speedY += self.gravity; // Add rotation based on the speed of the particle self.rotation += self.speedX / 10; if (self.y > 2732) { // If the particle is below the screen self.destroy(); // This now recycles instead of destroying } }; return self.init(); // Initialize on creation }); var Sun = Container.expand(function () { var self = Container.call(this); var sunGraphics = self.attachAsset('Sun', { anchorX: 0.5, anchorY: 0.5 }); // Initialize sun properties self.startX = -sunGraphics.width / 2; // Start off-screen to the left self.startY = 2732 * 0.25; // 25% from the top self.endX = 2048 + sunGraphics.width / 2; // End off-screen to the right self.arcHeight = 2732 * 0.1; // Arc height self.duration = 2 * 60 * 60; // 2 minutes in ticks (assuming 60 FPS) self.ticks = 0; // For the Sun class, replace the update function with: self.update = function () { if (!self.tweenStarted) { self.tweenStarted = true; // Create path tween for the arc motion tween(self, { x: self.endX, y: self.startY - self.arcHeight }, { duration: 2 * 60 * 1000, // 2 minutes in milliseconds easing: tween.sineInOut, onFinish: function onFinish() { self.destroy(); isDay = false; isNight = true; // Start spawning fireflies fireflySpawnInterval = LK.setInterval(function () { var newFirefly = new Firefly(); newFirefly.x = Math.random() * 2048; newFirefly.y = Math.random() * 2732; game.addChild(newFirefly); }, 1000); game.addChild(new Moon()); } }); } }; }); // Class for the water var Water = Container.expand(function () { var self = Container.call(this); var waterGraphics = self.attachAsset('Water', { anchorX: 0.5, anchorY: 0.7 }); self.speed = 2; self.update = function () { self.x -= self.speed * gameSpeed; // self.y = midgroundtrees1.y + midgroundtrees1.height / 2; if (self.x <= -self.width / 2) { self.x += self.width * 2; } }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ function savePurchasedHats(hatsArray) { if (Array.isArray(hatsArray)) { storage.purchasedHats = hatsArray.join(","); } } function getPurchasedHats() { if (!storage.purchasedHats) { return []; } return storage.purchasedHats.split ? storage.purchasedHats.split(",") : storage.purchasedHats; } var cootGraphics = { width: 550, height: 423.5 }; // Define cootGraphics with default dimensions var availableHats = [{ id: 'TopHat', name: 'Top Hat', price: 100, x: cootGraphics.width / 2.65, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.35 }, { id: 'Cowboy', name: 'Cowboy Hat', price: 200, x: cootGraphics.width / 2.4, y: -cootGraphics.height / 3 + cootGraphics.height / 2.6, rotation: -0.35 }, { id: 'Crown', name: 'Royal Crown', price: 800, x: cootGraphics.width / 2.65, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.35 }, { id: 'Beanie', name: 'Toque', price: 200, x: cootGraphics.width / 2.65, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.35 }, { id: 'Captain', name: 'Captain Hat', price: 500, x: cootGraphics.width / 2.65, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.35 }, { id: 'Sockhat', name: 'Cap of Legend', price: 700, x: cootGraphics.width / 3, y: -cootGraphics.height / 3 + cootGraphics.height / 2.4, rotation: 0.25 }, { id: 'Propeller', name: 'Propeller Cap', price: 1000, x: cootGraphics.width / 2.65, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.35 }, { id: 'Sombrero', name: 'Sombrero', price: 300, x: cootGraphics.width / 2.65, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.35 }, { id: 'Knight', name: 'Knight Helmet', price: 500, x: cootGraphics.width / 2.8, y: -cootGraphics.height / 3 + cootGraphics.height / 1.95, rotation: 0.27 }, { id: 'Viking', name: 'Viking Helmet', price: 600, x: cootGraphics.width / 2.7, y: -cootGraphics.height / 3 + cootGraphics.height / 2.6, rotation: -0.35 }, { id: 'Astronaut', name: 'Astronaut Helmet', price: 600, x: cootGraphics.width / 2.95, y: -cootGraphics.height / 3 + cootGraphics.height / 2, rotation: 0.27 }, { id: 'Fedora', name: 'Fedora', price: 100, x: cootGraphics.width / 2.6, y: -cootGraphics.height / 3 + cootGraphics.height / 2.7, rotation: -0.15 }]; availableHats.sort(function (a, b) { return a.price - b.price; }); function showHatShop() { var menuBackground = LK.getAsset('MenuBackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(menuBackground); var hatShopScreen = new HatShopScreen(); game.addChild(hatShopScreen); hatShopScreen.menuBackground = menuBackground; } function updateBackgroundFade() { // Check for day to night transition (Sun) if (isDay && !isNight) { game.children.forEach(function (child) { if (child instanceof Sun) { // Use x position to determine fade progress // When sun is halfway across screen, start fading if (child.x > 2048 * 0.85) { var fadeProgress = (child.x - 2048 * 0.85) / (2048 * 0.25); nightBackground.alpha = Math.min(fadeProgress, 1); } } }); } // Check for night to day transition (Moon) if (isNight && !isDay) { game.children.forEach(function (child) { if (child instanceof Moon) { // Use x position to determine fade progress // When moon is halfway across screen, start fading out if (child.x > 2048 * 0.85) { var fadeProgress = (child.x - 2048 * 0.85) / (2048 * 0.25); nightBackground.alpha = Math.max(1 - fadeProgress, 0); } } }); } } // Define createInterval function to fix ReferenceError var ObjectPool = { pools: {}, getPool: function getPool(type) { if (!this.pools[type]) { this.pools[type] = []; } return this.pools[type]; }, get: function get(type, Constructor, initParams) { var pool = this.getPool(type); var obj; if (pool.length > 0) { obj = pool.pop(); if (typeof obj.reset === 'function') { obj.reset(initParams); } return obj; } else { return new Constructor(initParams); } }, recycle: function recycle(type, object) { // Don't store null or undefined objects if (!object) { return; } var pool = this.getPool(type); // Limit pool size to prevent memory issues if (pool.length < 50) { // Clear any references that might cause memory leaks if (typeof object.cleanup === 'function') { object.cleanup(); } pool.push(object); } } }; function createInterval(config, startTime) { return LK.setInterval(function () { var timeRemaining = config.duration - (Date.now() - startTime); if (timeRemaining <= 0) { LK.clearInterval(this); } }, 1000); } function showInstructions() { var menuBackground = LK.getAsset('MenuBackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(menuBackground); var instructionsScreen = new InstructionsScreen(); game.addChild(instructionsScreen); instructionsScreen.menuBackground = menuBackground; // Store reference for later removal } function startGame() { // Fade in background music LK.playMusic('backgroundmusic', { fade: { start: 0, end: 0.5, duration: 1500 } }); gameActive = true; Obstacle.lastDestroyTime = Date.now(); // Create coot but start off-screen coot = new Coot(); coot.x = -400; // Start off-screen left coot.y = 2732 * 0.75 - 25; game.addChild(coot); // Add coot normally coot.updateHat(); game.setChildIndex(foreground1, game.children.length - 1); game.setChildIndex(foreground2, game.children.length - 1); // Initialize other game elements if (powerUpDisplay && powerUpDisplay.parent) { game.setChildIndex(powerUpDisplay, game.children.length - 1); } coot.phoenixFeatherIcon = phoenixFeatherIcon; heartIcons.forEach(function (icon, index) { icon.alpha = index < coot.lives ? 1 : 0.2; }); dayCountDisplay = new DayCountDisplay(); LK.gui.top.addChild(dayCountDisplay); dayCountDisplay.y = 2732 * 0.25; sun = game.addChild(new Sun()); sun.x = sun.startX; sun.y = sun.startY; // Play whistle and start game sequence LK.getSound('whistle').play(); LK.setTimeout(function () { gameSpeed = 1.5; // Animate coot running in tween(coot, { x: 2048 * 0.20 }, { duration: 1000, easing: tween.quadOut, onFinish: function onFinish() { // Store final positions after coot reaches destination coot.originalX = coot.x; coot.originalY = coot.y; coot.y = coot.y || 0; // Initialize coot.y if undefined coot.originalY = coot.originalY || 0; // Initialize coot.originalY if undefined } }); }, 1000); // Wait for whistle sound to finish } function handleShieldHit() { // Remove shield asset if (coot.shieldGraphics) { coot.shieldGraphics.destroy(); coot.shieldGraphics = null; } coot.isShielded = false; coot.isInvincible = true; // Set Coot to invincible state LK.getSound('coothurt').play(); // Play coothurt sound effect when the shield is removed // Flash effect for invincibility var flashInterval = LK.setInterval(function () { coot.children[0].alpha = coot.children[0].alpha === 1 ? 0.5 : 1; }, 100); LK.setTimeout(function () { LK.clearInterval(flashInterval); coot.children[0].alpha = 1; coot.isInvincible = false; }, 1500); } // Define a single obstacleTypes array as a constant var obstacleTypes = ['Duck', 'Eagle', 'Fish', 'Owl']; var obstacleSpawnChances = { Duck: 1, Eagle: 1, Fish: 1, Owl: 1 }; Obstacle.getRandomDelay = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; Obstacle.spawnDelay = 6000; // Further reduce default spawn delay to 6 seconds Obstacle.respawnDelay = { Eagle: Obstacle.getRandomDelay(2250, 3750), // Reduce Eagle respawn delay by 25% Duck: Obstacle.getRandomDelay(2250, 3750), // Reduce Duck respawn delay by 25% Fish: Obstacle.getRandomDelay(2250, 3750), // Reduce Fish respawn delay by 25% Owl: Obstacle.getRandomDelay(2250, 3750) // Add Owl respawn delay }; Obstacle.lastDestroyTime = Date.now() - 5000; // Initialize to ensure first spawn check passes var background = game.addChild(LK.getAsset('Background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2048 / 2500, scaleY: 2732 / 2500 })); var nightBackground = game.addChild(LK.getAsset('NightBackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2048 / 2500, scaleY: 2732 / 2500, alpha: 0 })); var DayCount = 1; // Global variable to keep track of the number of days, initialized to 1 at game start // Initialize the sun after title screen var sun; var isDay = true; // Initialize day state var isNight = false; // Initialize night state // Initialize the midgroundtrees var midgroundtrees1 = game.addChild(new Midgroundtrees()); midgroundtrees1.x = 2048 / 2; midgroundtrees1.y = 2732 * 0.7; var midgroundtrees2 = game.addChild(new Midgroundtrees()); midgroundtrees2.x = 2048 / 2 + midgroundtrees2.width; midgroundtrees2.y = 2732 * 0.7; // Initialize the water var water1 = game.addChild(new Water()); water1.x = 2048 / 2; water1.y = midgroundtrees1.y + midgroundtrees1.height / 2; var water2 = game.addChild(new Water()); water2.x = 2048 / 2 + water2.width; water2.y = midgroundtrees2.y + midgroundtrees2.height / 2; // Initialize game logo var gameLogo = LK.getAsset('GameIcon', { anchorX: 0.5, anchorY: 0.5, x: -100, // Start off-screen to the left y: 2732 * 0.4 // Move up by 10% of the screen height }); game.addChild(gameLogo); // Initialize game variables var coot; var dragStartY = null; // Initialize dragStartY to null var dragStartX = null; // Initialize dragStartX to null var gameSpeed = 0; // Global variable for game speed, set to 0 during title screen var isTitleScreen = true; // Flag to indicate if the game is in the title screen state var gameActive = false; // Flag to indicate if the game is actively being played var speedIncreaseInterval = 30000; // 30 seconds in milliseconds var maxGameSpeed = 5.0; // Maximum game speed var lastSpeedIncreaseTime = Date.now(); // Track the last time speed was increased var score = 0; var coinCount = storage.coins || 0; // Initialize coinCount from storage var coinCounter = new Text2(Math.min(coinCount, 999).toString(), { size: 150, fill: 0xFFFFFF }); coinCounter.anchor.set(1, 0); // Anchor to the top right corner var currentObstacle = null; var warningIcon = null; // Initialize the foreground var foreground1 = new Foreground(); var foreground2 = new Foreground(); // Removed duplicate addChild calls for foregrounds game.addChild(foreground1); game.addChild(foreground2); foreground1.x = 2048 / 2; foreground1.y = 2732 * 0.9; foreground2.x = foreground1.x + foreground1.width; foreground2.y = 2732 * 0.9; foreground1.isFirst = true; foreground1.other = foreground2; foreground2.other = foreground1; // Validate positioning if (Math.abs(foreground2.x - (foreground1.x + foreground1.width)) > 1) { console.error("Foreground pieces are not correctly positioned!"); } // Add coin counter display var coinCounter = new Text2('0', { size: 150, // Increased size for better visibility fill: 0xFFFFFF }); coinCounter.anchor.set(1, 0); // Anchor to the top right corner // Add coin asset beside the coin counter var coinIcon = LK.getAsset('Coin', { anchorX: 1, anchorY: 0, x: -coinCounter.width - 10, // Position to the left of the counter with some padding y: 0 }); LK.gui.topRight.addChild(coinIcon); LK.gui.topRight.addChild(coinCounter); // Add heart icons to represent Coot's lives var heartIcons = []; for (var i = 0; i < 3; i++) { // Always create 3 heart icons var heartIcon = LK.getAsset('HeartLife', { anchorX: 0, anchorY: 0, x: -coinCounter.width - 10 - i * 110, y: coinIcon.height + 10 }); LK.gui.topRight.addChild(heartIcon); heartIcons.push(heartIcon); } // Update heart icons based on remaining lives heartIcons.forEach(function (icon, index) { icon.alpha = coot && index < coot.lives ? 1 : 0.2; // Dim the heart if life is lost }); // Initialize PowerUpDisplay after foregrounds are set up var powerUpDisplay = new PowerUpDisplay(); game.addChild(powerUpDisplay); // Initialize Phoenix Feather icon at the start of the game var phoenixFeatherIcon = new PhoenixFeatherIcon(); // coot.phoenixFeatherIcon will be set after coot initialization phoenixFeatherIcon.x = heartIcons[0].x + heartIcons[0].width / 2 - phoenixFeatherIcon.width / 2; // Center below the leftmost heart icon phoenixFeatherIcon.y = heartIcons[0].y + heartIcons[0].height + 70; // Increase padding below the heart icon LK.gui.topRight.addChild(phoenixFeatherIcon); var dayCountDisplay; game.update = function () { if (DayCount > 1 && !dayCountDisplay.visible) { dayCountDisplay.show(); } updateBackgroundFade(); if (isTitleScreen) { // Update coinCounter text on the title screen coinCounter.setText(Math.min(coinCount, 9999).toString()); coinIcon.x = -coinCounter.width - 10; // Update coin icon position to align with the coin counter // Only update background, midground trees, water, and foreground during title screen [midgroundtrees1, midgroundtrees2, water1, water2, foreground1, foreground2].forEach(function (element) { element.update(); }); // Animate game logo sliding in from the left if (gameLogo.x < 2048 / 2) { // Move logo gameLogo.x += 30; // Slide in quickly // Move buttons at the same time if (gameLogo.playButton) { // Calculate how far along the animation we are (0-1) var progress = (gameLogo.x + 100) / (2048 / 2 + 100); // Position playButton in the center gameLogo.playButton.x = -100 + progress * (2048 / 2 + 100); // Position other buttons relative to playButton gameLogo.instructionsButton.x = gameLogo.playButton.x - 320; gameLogo.hatShopButton.x = gameLogo.playButton.x + 350; } } else { // Ensure everything is at final position gameLogo.x = 2048 / 2; if (gameLogo.playButton) { gameLogo.playButton.x = 2048 / 2; gameLogo.instructionsButton.x = 2048 / 2 - 320; gameLogo.hatShopButton.x = 2048 / 2 + 350; } } if (!gameLogo.playButton && !gameLogo.instructionsButton && !gameLogo.hatShopButton) { var playButton = new PlayButton(); playButton.x = -100; // Start off-screen to the left, like the logo playButton.y = gameLogo.y + gameLogo.height / 2 + 2732 * 0.06; game.addChild(playButton); gameLogo.playButton = playButton; var instructionsButton = new InstructionsButton(); instructionsButton.x = -100; // Start off-screen to the left instructionsButton.y = playButton.y + playButton.height; game.addChild(instructionsButton); gameLogo.instructionsButton = instructionsButton; var hatShopButton = new HatShopButton(); hatShopButton.x = -100; // Start off-screen to the left hatShopButton.y = playButton.y + playButton.height; game.addChild(hatShopButton); gameLogo.hatShopButton = hatShopButton; } return; // Exit update function to prevent further updates } if (coot) { coot.update(); } phoenixFeatherIcon.update(); // Increase game speed every 20 seconds if (!isTitleScreen && Date.now() - lastSpeedIncreaseTime >= speedIncreaseInterval) { if (gameSpeed < maxGameSpeed) { gameSpeed = Math.min(gameSpeed + 0.1, maxGameSpeed); // Decrease respawn delay for all obstacles Obstacle.respawnDelay.Eagle = Math.max(Obstacle.respawnDelay.Eagle - 500, 1000); Obstacle.respawnDelay.Duck = Math.max(Obstacle.respawnDelay.Duck - 500, 1000); Obstacle.respawnDelay.Fish = Math.max(Obstacle.respawnDelay.Fish - 500, 1000); Obstacle.respawnDelay.Owl = Math.max(Obstacle.respawnDelay.Owl - 500, 1000); } lastSpeedIncreaseTime = Date.now(); } // Define createInterval function to fix ReferenceError // Removed the timer counter increment and display logic // Check for collision between the Coot and the Collision Block of the current obstacle if (currentObstacle && coot.intersects(currentObstacle.children[0])) { if (coot.isShielded) { handleShieldHit(); } else if (coot.isInvincible) { // Do nothing, invincible state } else { coot.lives -= 1; LK.getSound('coothurt').play(); // Play coothurt sound when Coot gets hit if (coot.lives <= 0 && coot.hasPhoenixFeather) { LK.getSound('phoenix').play(); // Play phoenix sound effect when lives are refilled coot.hasPhoenixFeather = false; // Remove Phoenix Feather phoenixFeatherIcon.update(); // Update Phoenix Feather icon coot.lives = 3; // Refill all lives heartIcons.forEach(function (icon) { icon.alpha = 1; // Restore all heart icons }); // Add Phoenix effect coot.isInvincible = true; // Set Coot to invincible state LK.effects.flashScreen(0xff0000, 1000); // Flash screen red for 1 second var phoenix = LK.getAsset('Phoenix', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 // Set initial opacity to 50% }); phoenix.x = 2048 / 2; phoenix.y = 2732 / 2; game.addChild(phoenix); LK.setTimeout(function () { phoenix.destroy(); // Destroy the Phoenix asset coot.isInvincible = false; // Remove invincibility after effect }, 1500); // Wait for 1.5 seconds } else if (coot.lives <= 0) { coot.isFalling = true; coot.fallStartY = coot.y; coot.fallRotation = 0; coot.fallSpeed = 5; heartIcons[0].alpha = 0.2; // Dim the last heart icon to indicate all lives lost } else { coot.isInvincible = true; heartIcons[coot.lives].alpha = 0.2; // Dim the heart icon to indicate a lost life // Flash effect for invincibility LK.effects.flashScreen(0xff0000, 100); // Flash screen red for 100ms var flashInterval = LK.setInterval(function () { coot.children[0].alpha = coot.children[0].alpha === 1 ? 0.5 : 1; }, 100); LK.setTimeout(function () { LK.clearInterval(flashInterval); coot.children[0].alpha = 1; coot.isInvincible = false; }, 1500); } } } // Update PowerUpDisplay powerUpDisplay.update(); // Update the midgroundtrees midgroundtrees1.update(); midgroundtrees2.update(); // Update the water water1.update(); water2.update(); // Update the current obstacle // Check if the current obstacle needs destruction if (currentObstacle && currentObstacle.x < -currentObstacle.width / 2) { currentObstacle.destroy(); Obstacle.lastDestroyTime = Date.now(); currentObstacle = null; } // Check if it's time to spawn a new obstacle if (gameActive && !currentObstacle) { var timeSinceLastDestroy = Date.now() - Obstacle.lastDestroyTime; if (timeSinceLastDestroy >= Obstacle.spawnDelay - 1000 && !warningIcon) { if (coot.isWarningActive) { LK.getSound('alert').play(); // Play alert sound when warning icon is displayed and player has the warning power up } var totalChance = obstacleSpawnChances.Duck + obstacleSpawnChances.Fish; if (isDay) { totalChance += obstacleSpawnChances.Eagle; } else if (isNight) { totalChance += obstacleSpawnChances.Owl; } var randomChance = Math.random() * totalChance; var cumulativeChance = 0; for (var i = 0; i < obstacleTypes.length; i++) { if (obstacleTypes[i] === 'Eagle' && isDay || obstacleTypes[i] === 'Owl' && isNight || obstacleTypes[i] !== 'Eagle' && obstacleTypes[i] !== 'Owl') { cumulativeChance += obstacleSpawnChances[obstacleTypes[i]]; if (randomChance < cumulativeChance) { currentObstacleType = obstacleTypes[i]; obstacleSpawnChances[currentObstacleType] = 1; // Reset chance on spawn break; } } } var warningIconClassMap = { 'Duck': DuckWarningIcon, 'Eagle': EagleWarningIcon, 'Fish': FishWarningIcon, 'Owl': OwlWarningIcon // Add OwlIcon to warning icons }; warningIcon = game.addChild(new warningIconClassMap[currentObstacleType]()); warningIcon.x = 2048 / 2; warningIcon.y = 2732 / 2; } if (timeSinceLastDestroy >= Obstacle.spawnDelay) { if (warningIcon) { warningIcon.destroy(); warningIcon = null; } currentObstacle = game.addChild(new Obstacle(currentObstacleType)); currentObstacle.x = 2048 + currentObstacle.width / 2; // Ensure it starts off-screen currentObstacle.y = currentObstacleType === 'Duck' ? 2732 * 0.80 : currentObstacleType === 'Eagle' ? 2732 * 0.25 : currentObstacleType === 'Fish' ? 2732 * 0.85 : 2732 * 0.10; // Owl positioned at 10% from the top // Increase spawn chance for obstacles not selected obstacleTypes.forEach(function (type) { if (type !== currentObstacleType) { obstacleSpawnChances[type] += 0.5; // Increase chance by 0.5 for each non-selected obstacle } }); } } if (currentObstacle) { currentObstacle.update(); } // Check for collision between the Coot and Coins game.children.forEach(function (child) { if (child instanceof Coin && coot && coot.intersects(child) && !child.collecting) { LK.getSound('coin').play(); // Play coin sound effect when coot touches the coin child.collecting = true; child.targetX = 2048 + child.children[0].width; // Target off-screen to the right child.targetY = -child.children[0].height; // Target off-screen to the top } }); // Update the foreground foreground1.update(); foreground2.update(); // Spawn butterflies randomly if (isDay && LK.ticks % 720 == 0) { // Every 3 seconds at 60 FPS var newButterfly = ObjectPool.get('Butterfly', Butterfly); newButterfly.x = 2048 + newButterfly.width / 2; // Start off-screen to the right newButterfly.y = Math.random() * (2732 * 0.6) + 2732 * 0.2; // Random Y position within midground tree layer game.addChild(newButterfly); } // Calculate spawn interval based on coin magnet state var baseSpawnRate = 120; // Normal 2-second spawn rate var magnetSpawnRate = 30; // 25% faster (120 * 0.75 = 90) var currentSpawnRate = coot && coot.hasCoinMagnet ? magnetSpawnRate : baseSpawnRate; if (LK.ticks % currentSpawnRate == 0) { var newCoin = new Coin(); newCoin.x = 2048 + newCoin.width / 2; newCoin.y = Math.random() * (2732 * 0.45) + 2732 * 0.35; game.addChild(newCoin); } // Spawn power ups randomly if (LK.ticks % 1080 == 0) { // Every 3 seconds at 60 FPS var powerUpTypes = [{ type: 'Shield', weight: 20 }, { type: 'PowerDash', weight: 25 }, { type: 'CoinMagnet', weight: 25 }, { type: 'Warning', weight: 20 }, { type: 'PhoenixFeather', weight: 10 }]; var totalWeight = powerUpTypes.reduce(function (acc, powerUp) { return acc + powerUp.weight; }, 0); var randomWeight = Math.random() * totalWeight; var cumulativeWeight = 0; var selectedPowerUpType; for (var i = 0; i < powerUpTypes.length; i++) { cumulativeWeight += powerUpTypes[i].weight; if (randomWeight < cumulativeWeight) { selectedPowerUpType = powerUpTypes[i].type; break; } } // Check if Coot already has a shield or Phoenix feather if (selectedPowerUpType === 'Shield' && coot.isShielded || selectedPowerUpType === 'PhoenixFeather' && coot.hasPhoenixFeather) { // Skip spawning this power-up return; } var newPowerup = new PowerUp(selectedPowerUpType); newPowerup.x = 2048 + newPowerup.width / 2; // Start off-screen to the right newPowerup.y = Math.random() * (2732 * 0.45) + 2732 * 0.35; // Random Y position between 35% and 80% of the screen height game.addChild(newPowerup); } }; // Handle touch events for jumping and diving game.down = function (x, y, obj) { dragStartY = y; // Record the initial y position when touch starts dragStartX = x; // Record the initial x position when touch starts }; game.move = function (x, y, obj) { if (!isTitleScreen && dragStartY !== null && dragStartX !== null) { if (x - dragStartX > 50) { // Only allow dash during these states if PowerDash is active if (coot.isJumping || coot.isFalling || coot.isDiving || coot.isReturning || coot.returnDelay > 0) { // Check for PowerDash before allowing if (coot.isPowerDashActive) { coot.isDashing = true; } } else { // Normal dash on ground, no PowerDash needed coot.isDashing = true; } dragStartX = null; // Reset dragStartX to prevent repeated dashes } if (y - dragStartY > 50 && coot && coot.originalY !== undefined && coot.y !== undefined && coot.y === coot.originalY) { // Check if the drag is downward and significant coot.dive(); dragStartY = null; // Reset dragStartY to prevent repeated dives } else if (dragStartY - y > 50 && coot.y === coot.originalY) { // Check if the drag is upward and significant coot.jump(); dragStartY = null; // Reset dragStartY to prevent repeated jumps } } }; game.up = function (x, y, obj) { dragStartY = null; // Reset dragStartY when touch ends dragStartX = null; // Reset dragStartX when touch ends };
===================================================================
--- original.js
+++ change.js
@@ -1,180 +1,2650 @@
/****
+* Plugins
+****/
+var storage = LK.import("@upit/storage.v1", {
+ coins: 0
+});
+var tween = LK.import("@upit/tween.v1");
+
+/****
* Classes
****/
-// Boat class
-var Boat = Container.expand(function () {
+// Import tween plugin
+// Initialize with default coins value
+var Butterfly = Container.expand(function () {
var self = Container.call(this);
- var boatGraphics = self.attachAsset('Speedboat', {
+ var butterflyGraphics;
+ var selectedType;
+ // Initialize butterfly properties
+ self.speedX = -2;
+ self.flitAmplitude = 20;
+ self.flitFrequency = 0.1;
+ self.startY = 0;
+ self.init = function () {
+ var butterflyTypes = ['GreenButterfly', 'PinkButterfly', 'YellowButterfly'];
+ selectedType = butterflyTypes[Math.floor(Math.random() * butterflyTypes.length)];
+ if (!butterflyGraphics || butterflyGraphics.assetId !== selectedType) {
+ if (butterflyGraphics) {
+ self.removeChild(butterflyGraphics);
+ }
+ butterflyGraphics = self.attachAsset(selectedType, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ self.startY = Math.random() * (2732 * 0.6) + 2732 * 0.2;
+ return self;
+ };
+ self.reset = function () {
+ var butterflyTypes = ['GreenButterfly', 'PinkButterfly', 'YellowButterfly'];
+ var newType = butterflyTypes[Math.floor(Math.random() * butterflyTypes.length)];
+ if (newType !== selectedType) {
+ selectedType = newType;
+ if (butterflyGraphics) {
+ self.removeChild(butterflyGraphics);
+ }
+ butterflyGraphics = self.attachAsset(selectedType, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ self.startY = Math.random() * (2732 * 0.6) + 2732 * 0.2;
+ return self;
+ };
+ self.destroy = function () {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('Butterfly', self);
+ };
+ self.update = function () {
+ // Move the butterfly left
+ self.x += self.speedX * gameSpeed;
+ // Apply flitting motion
+ self.y = self.startY + Math.sin(self.x * self.flitFrequency) * self.flitAmplitude;
+ // Simulate wing flapping by adjusting scale
+ var flapScale = 0.2 * Math.sin(LK.ticks * 0.3) + 1;
+ butterflyGraphics.scale.set(flapScale);
+ // Destroy the butterfly if it goes off screen
+ if (self.x < -butterflyGraphics.width / 2) {
+ self.destroy();
+ }
+ };
+ return self.init();
+});
+var Coin = Container.expand(function () {
+ var self = Container.call(this);
+ var coinGraphics = self.attachAsset('Coin', {
anchorX: 0.5,
anchorY: 0.5
});
+ // Initialize coin properties
+ self.rotationSpeed = 0.05; // Rotation speed for the coin
+ self.speedX = -5; // Speed of the coin moving left
+ self.collecting = false; // Flag to check if the coin is being collected
+ self.targetX = 0; // Target X position for collection animation
+ self.targetY = 0; // Target Y position for collection animation
+ self.update = function () {
+ // Generate GoldSparkle particles
+ if (Math.random() < 0.0525) {
+ var sparkle = ObjectPool.get('GoldSparkle', GoldSparkle);
+ sparkle.x = self.x + (Math.random() * coinGraphics.width - coinGraphics.width / 2);
+ sparkle.y = self.y + (Math.random() * coinGraphics.height - coinGraphics.height / 2);
+ sparkle.coin = self; // Associate sparkle with the coin
+ game.addChild(sparkle);
+ }
+ // Move the coin left
+ self.x += self.speedX * gameSpeed;
+ // Apply spin effect over Y axis
+ coinGraphics.scale.x = Math.sin(self.x * 0.015);
+ if (coot && coot.isMagnetActive && !self.collecting && self.x < 2048 * 0.9) {
+ // Set initial target and mark as magnetized
+ self.targetX = coot.x;
+ self.targetY = coot.y;
+ self.magnetized = true;
+ }
+ if (self.magnetized && !self.collecting) {
+ // Continuously update target position to track Coot
+ self.targetX = coot.x;
+ self.targetY = coot.y;
+ // Move directly toward Coot with increasing speed as it gets closer
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ // Calculate movement speed based on distance
+ var speed = Math.max(5, 20 - distance / 30);
+ // Move coin toward Coot
+ self.x += dx / distance * speed * gameSpeed;
+ self.y += dy / distance * speed * gameSpeed;
+ // If very close to Coot, complete collection
+ if (distance < 30) {
+ self.collecting = true; // Mark as being collected to prevent double counting
+ LK.getSound('coin').play();
+ coinCount++;
+ storage.coins = coinCount;
+ coinCounter.setText(Math.min(coinCount, 9999).toString());
+ coinIcon.x = -coinCounter.width - 10;
+ // Check for life addition
+ if (coinCount % 100 === 0 && coot && coot.lives < 3) {
+ coot.lives++;
+ heartIcons[coot.lives - 1].alpha = 1;
+ }
+ // Clean up sparkles
+ game.children.forEach(function (child) {
+ if (child instanceof GoldSparkle && child.coin === self) {
+ child.destroy();
+ }
+ });
+ // Remove from game
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ }
+ }
+ if (self.collecting && !self.tweenStarted) {
+ // Set flag to prevent multiple tweens
+ self.tweenStarted = true;
+ // Create collection tween
+ tween(self, {
+ x: self.targetX,
+ y: self.targetY
+ }, {
+ duration: 500,
+ easing: tween.quartOut,
+ onUpdate: function onUpdate(progress) {
+ coinGraphics.scale.set(1 - progress * 0.9);
+ },
+ onFinish: function onFinish() {
+ if (self.targetX === coot.x && self.targetY === coot.y) {
+ LK.getSound('coin').play(); // Play sound effect if the target is coot
+ }
+ // Count coin and update display
+ coinCount++;
+ storage.coins = coinCount;
+ coinCounter.setText(Math.min(coinCount, 999).toString());
+ coinIcon.x = -coinCounter.width - 10;
+ // Check for life addition
+ if (coinCount % 100 === 0 && coot && coot.lives < 3) {
+ coot.lives++;
+ heartIcons[coot.lives - 1].alpha = 1;
+ }
+ // Clean up
+ game.children.forEach(function (child) {
+ if (child instanceof GoldSparkle && child.coin === self) {
+ child.destroy();
+ }
+ });
+ // Remove from game
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ }
+ });
+ } else if (self.x < -coinGraphics.width / 2) {
+ // Destroy the coin if it goes off screen
+ self.destroy();
+ }
+ };
+});
+var CollisionBlock = Container.expand(function () {
+ var self = Container.call(this);
+ var collisionBlockGraphics = self.attachAsset('Collisionblock', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0
+ });
+});
+// Assets will be automatically created and loaded by the LK engine based on their usage in the code.
+// Example assets: 'coot', 'obstacle', 'background'
+// Class for the main character, the American coot
+var Coot = Container.expand(function () {
+ var self = Container.call(this);
+ var cootGraphics = self.attachAsset('coot', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Add this to ensure cootGraphics is always at bottom
+ self.ensureGraphicsOrder = function () {
+ self.setChildIndex(cootGraphics, 0);
+ if (cootGraphics.children.length > 0) {
+ // Find hat if it exists
+ for (var i = 0; i < cootGraphics.children.length; i++) {
+ if (cootGraphics.children[i].isHat) {
+ cootGraphics.setChildIndex(cootGraphics.children[i], cootGraphics.children.length - 1);
+ break;
+ }
+ }
+ }
+ };
+ self.hasHat = false; // Flag to track if a hat is equipped
+ // Add hat update method
+ self.updateHat = function () {
+ // Remove existing hat
+ for (var i = 0; i < cootGraphics.children.length; i++) {
+ if (cootGraphics.children[i].isHat) {
+ cootGraphics.removeChild(cootGraphics.children[i]);
+ break;
+ self.ensureGraphicsOrder();
+ }
+ ;
+ }
+ // Check if a hat is equipped
+ var hatId = storage.equippedHat || null;
+ if (hatId) {
+ try {
+ // Attach hat to cootGraphics for movement
+ var hatId = storage.equippedHat || null;
+ if (hatId) {
+ try {
+ // Find hat config
+ var hatConfig = availableHats.find(function (hat) {
+ return hat.id === hatId;
+ });
+ if (hatConfig) {
+ var hatGraphics = cootGraphics.attachAsset(hatId, {
+ anchorX: 0.5,
+ anchorY: 1.0,
+ x: hatConfig.x,
+ y: hatConfig.y,
+ rotation: hatConfig.rotation
+ });
+ hatGraphics.isHat = true;
+ self.setChildIndex(cootGraphics, 0);
+ cootGraphics.setChildIndex(hatGraphics, cootGraphics.children.length - 1);
+ self.hasHat = true;
+ }
+ } catch (e) {
+ console.error("Could not load hat asset: " + hatId);
+ storage.equippedHat = null;
+ self.hasHat = false;
+ }
+ }
+ // Mark as hat
+ hatGraphics.isHat = true;
+ // Make sure cootGraphics is at the bottom of main container
+ self.setChildIndex(cootGraphics, 0);
+ // Set hat to top within cootGraphics
+ cootGraphics.setChildIndex(hatGraphics, cootGraphics.children.length - 1);
+ self.hasHat = true;
+ } catch (e) {
+ console.error("Could not load hat asset: " + hatId);
+ storage.equippedHat = null;
+ self.hasHat = false;
+ }
+ } else {
+ self.hasHat = false;
+ }
+ };
+ self.originalX = self.x; // Store original X position
self.speed = 6.5;
self.dashSpeed = 15;
- self.lives = 3;
+ self.lives = 3; // Initialize Coot with three lives
+ self.dashDelay = 30;
self.isFalling = false;
self.isDashing = false;
+ self.fallRotation = 0; // Initialize fall rotation
+ self.dashTimer = 0;
+ self.jumpVelocity = 40; // Increased initial upward velocity for jump
+ self.gravity = 1.0; // Gravity to apply during jump
+ self.jumpHeight = 105;
+ self.isJumping = false;
+ self.isReturning = false; // New state to handle returning to top after diving
+ self.isInvincible = false; // Initialize invincible state
+ self.isShielded = false; // Initialize shielded state
+ self.isMagnetActive = false; // Initialize magnet state
+ self.isWarningActive = false; // Initialize warning state
+ self.isPowerDashActive = false; // Initialize PowerDash state
+ self.hasPhoenixFeather = false; // Initialize Phoenix Feather state
+ self.powerUpTimers = {
+ 'CoinMagnet': {
+ endTime: 0
+ },
+ 'PowerDash': {
+ endTime: 0
+ },
+ 'Warning': {
+ endTime: 0
+ }
+ };
self.update = function () {
- // Boat movement logic
- if (keys['ArrowLeft']) {
- self.x -= self.speed;
+ if (self.isFalling) {
+ handleFalling();
+ } else if (self.isDiving) {
+ handleDiving();
+ } else if (self.returnDelay > 0) {
+ handleReturnDelay();
+ } else if (self.isReturning) {
+ handleReturning();
}
- if (keys['ArrowRight']) {
- self.x += self.speed;
+ // Define state key mapping for power-ups
+ var stateKeyMap = {
+ 'CoinMagnet': 'isMagnetActive',
+ 'PowerDash': 'isPowerDashActive',
+ 'Warning': 'isWarningActive'
+ };
+ // Check power-up timers
+ for (var powerUpType in self.powerUpTimers) {
+ if (self.powerUpTimers.hasOwnProperty(powerUpType)) {
+ var timer = self.powerUpTimers[powerUpType];
+ if (Date.now() >= timer.endTime) {
+ var stateKey = stateKeyMap[powerUpType];
+ if (self[stateKey]) {
+ self[stateKey] = false; // Deactivate the power-up
+ }
+ }
+ }
}
- // Keep boat within screen bounds
- if (self.x < 50) {
- self.x = 50;
+ function handleFalling() {
+ if (self.lives <= 0) {
+ self.y -= self.fallSpeed;
+ self.fallRotation += 0.05;
+ cootGraphics.rotation = -self.fallRotation;
+ if (self.y <= self.fallStartY - 50) {
+ self.fallSpeed = -10;
+ }
+ if (self.y > 2732) {
+ LK.showGameOver();
+ }
+ } else {
+ self.y += self.gravity * 10; // Increase gravity effect during fall
+ if (self.y >= self.originalY) {
+ self.y = self.originalY;
+ self.isFalling = false;
+ self.jumpVelocity = 40;
+ self.isJumping = false;
+ }
+ cootGraphics.rotation = 0;
+ }
}
- if (self.x > 1998) {
- self.x = 1998;
+ function handleDiving() {
+ self.y += self.speed * 1.5;
+ cootGraphics.alpha = Math.max(0.5, cootGraphics.alpha - 0.05);
+ cootGraphics.tint = 0x0000ff;
+ if (self.y >= 2732 * 0.90) {
+ self.y = 2732 * 0.90;
+ self.isDiving = false;
+ self.returnDelay = Date.now() + 1000;
+ }
}
+ function handleReturnDelay() {
+ if (Date.now() >= self.returnDelay) {
+ self.returnDelay = 0;
+ if (self.y >= 2732 * 0.90) {
+ self.isReturning = true;
+ }
+ }
+ }
+ function handleReturning() {
+ self.y -= self.speed * 1.5;
+ var transitionFactor = 1 - (self.y - self.originalY) / (2732 * 0.90 - self.originalY);
+ cootGraphics.alpha = 0.5 + 0.5 * transitionFactor;
+ var startTint = self.underwaterTint;
+ var endTint = 0xffffff;
+ var r = (startTint >> 16 & 0xff) + ((endTint >> 16 & 0xff) - (startTint >> 16 & 0xff)) * transitionFactor;
+ var g = (startTint >> 8 & 0xff) + ((endTint >> 8 & 0xff) - (startTint >> 8 & 0xff)) * transitionFactor;
+ var b = (startTint & 0xff) + ((endTint & 0xff) - (startTint & 0xff)) * transitionFactor;
+ cootGraphics.tint = (r << 16) + (g << 8) + b;
+ if (self.y <= self.originalY) {
+ self.y = self.originalY;
+ self.isReturning = false;
+ cootGraphics.alpha = 1.0;
+ cootGraphics.tint = 0xffffff;
+ }
+ if (self.isReturning) {
+ self.x += (self.originalX - self.x) * 0.1;
+ }
+ }
+ // Add wobble effect to the coot while running
+ if (!self.isJumping && !self.isDiving && !self.isReturning && !self.isFalling) {
+ cootGraphics.rotation = Math.sin(LK.ticks / 5) * 0.1; // Increase wobble speed by reducing the divisor
+ // Generate 1-2 water splash particles every 60 ticks (1 second) only when not jumping, diving, or falling
+ if (!self.isJumping && !self.isDiving && !self.isFalling && LK.ticks % 60 == 0) {
+ var numParticles = Math.floor(Math.random() * 2) + 1;
+ for (var i = 0; i < numParticles; i++) {
+ var splashLeft = ObjectPool.get('Splash', Splash);
+ splashLeft.x = self.x - cootGraphics.width / 2;
+ splashLeft.y = self.y + cootGraphics.height / 2;
+ game.addChildAt(splashLeft, game.getChildIndex(foreground1) - 1);
+ var splashRight = ObjectPool.get('Splash', Splash);
+ splashRight.x = self.x + cootGraphics.width / 2;
+ splashRight.y = self.y + cootGraphics.height / 2;
+ game.addChildAt(splashRight, game.getChildIndex(foreground1) - 1);
+ }
+ }
+ }
+ // Handle dash state
+ if (self.isDashing) {
+ if (self.dashTimer === 0) {
+ LK.getSound('dashsound').play(); // Play dashsound when dash starts
+ }
+ if (self.dashTimer < self.dashDelay) {
+ // Dash forward
+ if (self.x < 2048 * 0.75) {
+ // Stop at 3/4 of screen width
+ self.x += self.dashSpeed * 1.1;
+ }
+ // Create echo trail effect only if PowerDash is active
+ if (self.isPowerDashActive) {
+ var echo = ObjectPool.get('EchoTrail', EchoTrail);
+ echo.x = self.x;
+ echo.y = self.y;
+ game.addChild(echo);
+ }
+ self.dashTimer++;
+ } else {
+ var returnSpeed = 10; // Fixed return speed
+ self.x += Math.sign(self.originalX - self.x) * Math.min(returnSpeed, Math.abs(self.originalX - self.x));
+ if (Math.abs(self.x - self.originalX) < returnSpeed) {
+ self.x = self.originalX;
+ self.isDashing = false;
+ self.dashTimer = 0;
+ }
+ }
+ }
+ // Ensure smooth return to original position if falling and returning from a dash
+ if (self.isFalling && self.isReturning) {
+ var returnSpeed = 10; // Fixed return speed
+ self.x += Math.sign(self.originalX - self.x) * Math.min(returnSpeed, Math.abs(self.originalX - self.x));
+ if (Math.abs(self.x - self.originalX) < returnSpeed) {
+ self.x = self.originalX;
+ self.isReturning = false;
+ }
+ }
+ self.ensureGraphicsOrder();
};
+ self.isDiving = false;
+ self.isDashing = false;
+ self.dashSpeed = 15;
+ self.dashDelay = 60;
+ self.dashTimer = 0;
+ self.originalX = self.x;
+ self.jump = function () {
+ if (canPerformAction()) {
+ // Cancel any existing tweens on this object
+ tween.stop(self);
+ self.isJumping = true;
+ LK.getSound('jumpsound').play();
+ self.originalX = self.x;
+ self.isReturning = false;
+ self.originalY = self.y;
+ // Fixed jump height - much higher than before
+ var jumpHeight = 805; // Try with a specific large value
+ // Jump tween with steep curve
+ tween(self, {
+ y: self.y - jumpHeight
+ }, {
+ duration: 450,
+ // Longer duration
+ easing: tween.backOut,
+ onFinish: function onFinish() {
+ // Fall tween back to original position
+ tween(self, {
+ y: self.originalY
+ }, {
+ duration: 600,
+ // Longer duration down too
+ easing: tween.backIn,
+ onFinish: function onFinish() {
+ self.isJumping = false;
+ }
+ });
+ }
+ });
+ }
+ };
+ self.dash = function () {
+ if (canPerformAction()) {
+ self.isDashing = true;
+ self.originalX = self.x;
+ self.dashTimer = 0;
+ }
+ };
+ self.dive = function () {
+ if (canPerformAction()) {
+ LK.getSound('cootdive').play(); // Play cootdive sound effect when the coot starts to dive
+ self.isDiving = true;
+ self.returnDelay = Date.now() + 5000;
+ self.isReturning = false;
+ self.underwaterTint = 0x4444ff;
+ self.originalX = self.x;
+ self.originalY = self.y;
+ self.y += self.speed * 2;
+ generateSplashParticles(2, 4);
+ }
+ };
+ function canPerformAction() {
+ return !self.isJumping && !self.isDiving && !self.isReturning && !self.isDashing;
+ }
+ function generateSplashParticles(min, max) {
+ var numParticles = Math.floor(Math.random() * (max - min + 1)) + min;
+ for (var i = 0; i < numParticles; i++) {
+ var splash = ObjectPool.get('Splash', Splash);
+ splash.x = self.x;
+ splash.y = self.y + cootGraphics.height / 2;
+ game.addChildAt(splash, game.getChildIndex(foreground1) - 1);
+ }
+ }
});
-// Floating Log class
-var FloatingLog = Container.expand(function () {
+var DayCountDisplay = Container.expand(function () {
var self = Container.call(this);
- var logGraphics = self.attachAsset('FloatingLog', {
+ var dayText = new Text2('Day ' + DayCount, {
+ size: 100,
+ fill: 0xFFFFFF
+ });
+ dayText.anchor.set(0.5, 0.5);
+ dayText.alpha = 0; // Set alpha to 0 by default
+ self.addChild(dayText);
+ self.show = function () {
+ dayText.setText('Day ' + DayCount);
+ dayText.alpha = 1;
+ LK.setTimeout(function () {
+ dayText.alpha = 0; // Set alpha back to 0 instead of destroying
+ }, 1500);
+ // Set a timer to make the day count display visible for 3 seconds every time the day count increases
+ LK.setTimeout(function () {
+ dayText.alpha = 1;
+ LK.setTimeout(function () {
+ dayText.alpha = 0;
+ }, 1500);
+ }, 1500);
+ };
+});
+var DuckWarningIcon = Container.expand(function () {
+ var self = Container.call(this);
+ var iconGraphics = self.attachAsset('DuckIcon', {
anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.75
+ });
+ self.flashInterval = 0;
+ self.update = function () {
+ self.flashInterval++;
+ if (coot.isWarningActive) {
+ if (self.flashInterval % 30 < 15) {
+ iconGraphics.alpha = 0.75;
+ } else {
+ iconGraphics.alpha = 0.5;
+ }
+ } else {
+ iconGraphics.alpha = 0;
+ }
+ };
+});
+var EagleFeather = Container.expand(function () {
+ var self = Container.call(this);
+ var featherGraphics;
+ self.rotationSpeed = 0;
+ self.driftX = 0;
+ self.driftY = 0;
+ self.fadeRate = 0.005;
+ self.init = function () {
+ if (!featherGraphics) {
+ featherGraphics = self.attachAsset('Eaglefeather', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ // Initialize feather properties
+ self.rotationSpeed = Math.random() * 0.02 - 0.01;
+ self.driftX = Math.random() * 2 - 1;
+ self.driftY = Math.random() * -1 - 0.5;
+ featherGraphics.alpha = 1;
+ return self;
+ };
+ self.reset = function () {
+ self.rotationSpeed = Math.random() * 0.02 - 0.01;
+ self.driftX = Math.random() * 2 - 1;
+ self.driftY = Math.random() * -1 - 0.5;
+ featherGraphics.alpha = 1;
+ featherGraphics.rotation = 0;
+ return self;
+ };
+ self.destroy = function () {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('EagleFeather', self);
+ };
+ self.update = function () {
+ self.x += self.driftX * gameSpeed;
+ self.y += self.driftY * gameSpeed;
+ featherGraphics.rotation += self.rotationSpeed;
+ featherGraphics.alpha -= self.fadeRate;
+ // Destroy feather when fully faded
+ if (featherGraphics.alpha <= 0) {
+ self.destroy();
+ }
+ };
+ return self.init();
+});
+var EagleWarningIcon = Container.expand(function () {
+ var self = Container.call(this);
+ var iconGraphics = self.attachAsset('EagleIcon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.75
+ });
+ self.flashInterval = 0;
+ self.update = function () {
+ self.flashInterval++;
+ if (coot.isWarningActive) {
+ if (self.flashInterval % 30 < 15) {
+ iconGraphics.alpha = 0.75;
+ } else {
+ iconGraphics.alpha = 0.5;
+ }
+ } else {
+ iconGraphics.alpha = 0;
+ }
+ };
+});
+var EchoTrail = Container.expand(function () {
+ var self = Container.call(this);
+ var echoGraphics;
+ self.fadeRate = 0.05;
+ self.init = function () {
+ if (!echoGraphics) {
+ echoGraphics = self.attachAsset('coot', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ });
+ } else {
+ echoGraphics.alpha = 0.5;
+ }
+ return self;
+ };
+ self.reset = function () {
+ if (echoGraphics) {
+ echoGraphics.alpha = 0.5;
+ }
+ return self;
+ };
+ self.destroy = function () {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('EchoTrail', self);
+ };
+ self.update = function () {
+ echoGraphics.alpha -= self.fadeRate;
+ if (echoGraphics.alpha <= 0) {
+ self.destroy();
+ }
+ };
+ return self.init();
+});
+var Firefly = Container.expand(function () {
+ var self = Container.call(this);
+ var fireflyGraphics = self.attachAsset('Firefly', {
+ anchorX: 0.5,
anchorY: 0.5
});
- self.speedX = -5;
+ // Initialize firefly properties
+ self.speedX = Math.random() * 8 - 4; // Further increased random horizontal speed
+ self.speedY = Math.random() * 8 - 4; // Further increased random vertical speed
+ self.fadeRate = 0.005; // Much slower fade rate for slow pulsing
+ self.flickerTimer = Math.random() * 240 + 120; // Random flicker timer between 2 to 4 seconds
+ self.alphaDirection = 1; // Direction of alpha change (1 for fade in, -1 for fade out)
+ self.lifetime = Math.random() * 180 + 180; // Random lifetime between 3 to 5 seconds
self.update = function () {
+ // Move the firefly
self.x += self.speedX;
- if (self.x < -logGraphics.width / 2) {
+ self.y += self.speedY;
+ // Create trail effect
+ var trail = ObjectPool.get('FireflyTrail', FireflyTrail);
+ trail.x = self.x;
+ trail.y = self.y;
+ game.addChild(trail);
+ // Loop around the screen
+ if (self.x < 0) {
+ self.x = 2048;
+ }
+ if (self.x > 2048) {
+ self.x = 0;
+ }
+ if (self.y < 0) {
+ self.y = 2732;
+ }
+ if (self.y > 2732) {
+ self.y = 0;
+ }
+ // Flicker effect
+ self.flickerTimer--;
+ if (self.flickerTimer <= 0) {
+ fireflyGraphics.alpha = Math.random(); // Random alpha for flicker
+ self.flickerTimer = Math.random() * 60 + 30; // Reset flicker timer
+ }
+ // Fade in and out
+ fireflyGraphics.alpha += self.fadeRate * self.alphaDirection;
+ if (fireflyGraphics.alpha <= 0 || fireflyGraphics.alpha >= 1) {
+ self.alphaDirection *= -1; // Reverse fade direction
+ }
+ // Destroy firefly after its lifetime
+ self.lifetime--;
+ if (self.lifetime <= 0) {
self.destroy();
}
};
});
-// Storm Cloud class
-var StormCloud = Container.expand(function () {
+var FireflyTrail = Container.expand(function () {
var self = Container.call(this);
- var cloudGraphics = self.attachAsset('StormCloud', {
+ var trailGraphics;
+ self.fadeRate = 0.02;
+ self.init = function () {
+ if (!trailGraphics) {
+ trailGraphics = self.attachAsset('FireflyTrail', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 1
+ });
+ } else {
+ trailGraphics.alpha = 1;
+ }
+ return self;
+ };
+ self.reset = function () {
+ if (trailGraphics) {
+ trailGraphics.alpha = 1;
+ }
+ return self;
+ };
+ self.destroy = function () {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('FireflyTrail', self);
+ };
+ self.update = function () {
+ trailGraphics.alpha -= self.fadeRate;
+ if (trailGraphics.alpha <= 0) {
+ self.destroy();
+ }
+ };
+ return self.init();
+});
+var FishWarningIcon = Container.expand(function () {
+ var self = Container.call(this);
+ var iconGraphics = self.attachAsset('FishIcon', {
anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.75
+ });
+ self.flashInterval = 0;
+ self.update = function () {
+ self.flashInterval++;
+ if (coot.isWarningActive) {
+ if (self.flashInterval % 30 < 15) {
+ iconGraphics.alpha = 0.75;
+ } else {
+ iconGraphics.alpha = 0.5;
+ }
+ } else {
+ iconGraphics.alpha = 0;
+ }
+ };
+});
+// Define a single obstacleTypes array as a constant
+// Class for the foreground
+var Foreground = Container.expand(function () {
+ var self = Container.call(this);
+ var foregroundGraphics = self.attachAsset('Foreground', {
+ anchorX: 0.5,
anchorY: 0.5
});
- self.speedX = -6;
+ self.speed = 5;
+ self.isFirst = false; // Will be set during initialization
self.update = function () {
+ // Only move the first piece
+ if (self.isFirst) {
+ self.x -= self.speed * gameSpeed; // Apply gameSpeed to movement
+ // Move second piece to maintain fixed distance
+ self.other.x = self.x + self.width;
+ // Reset both pieces when first goes off screen
+ if (self.x < -self.width / 1.5) {
+ // Reset earlier - when piece is mostly off screen
+ self.x += self.width;
+ self.other.x = self.x + self.width;
+ }
+ }
+ };
+});
+var GoldSparkle = Container.expand(function () {
+ var self = Container.call(this);
+ var sparkleGraphics;
+ // Initialize variables but don't create graphics yet
+ self.speedX = 0;
+ self.speedY = 0;
+ self.fadeRate = 0.02;
+ self.coin = null; // Reference to associated coin
+ self.init = function () {
+ // Only create graphics if they don't exist
+ if (!sparkleGraphics) {
+ sparkleGraphics = self.attachAsset('GoldSparkle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ // Set initial properties
+ self.speedX = (Math.random() * 2 - 1) * 0.75;
+ self.speedY = (Math.random() * 2 - 1) * 0.75;
+ sparkleGraphics.alpha = 1;
+ return self;
+ };
+ self.reset = function () {
+ // Reset properties without recreating the graphics
+ self.speedX = (Math.random() * 2 - 1) * 0.75;
+ self.speedY = (Math.random() * 2 - 1) * 0.75;
+ self.coin = null;
+ if (sparkleGraphics) {
+ sparkleGraphics.alpha = 1;
+ }
+ return self;
+ };
+ self.cleanup = function () {
+ // Clear any references to other objects
+ self.coin = null;
+ };
+ self.destroy = function () {
+ // Instead of destroying, return to pool
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('GoldSparkle', self);
+ };
+ self.update = function () {
self.x += self.speedX;
- if (self.x < -cloudGraphics.width / 2) {
+ self.y += self.speedY;
+ sparkleGraphics.alpha -= self.fadeRate;
+ if (sparkleGraphics.alpha <= 0) {
+ self.destroy(); // This now recycles instead of destroying
+ }
+ };
+ return self.init(); // Initialize on creation
+});
+var HatShopButton = Container.expand(function () {
+ var self = Container.call(this);
+ var hatShopButtonGraphics = self.attachAsset('HatShopButton', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.down = function () {
+ gameLogo.visible = false;
+ if (gameLogo.playButton) {
+ gameLogo.playButton.visible = false;
+ }
+ if (gameLogo.instructionsButton) {
+ gameLogo.instructionsButton.visible = false;
+ }
+ if (gameLogo.hatShopButton) {
+ gameLogo.hatShopButton.visible = false;
+ }
+ showHatShop();
+ };
+});
+var HatShopScreen = Container.expand(function () {
+ var self = Container.call(this);
+ // Title
+ var shopTitle = new Text2('Hat Shop', {
+ size: 100,
+ fill: 0xFFFFFF,
+ fontWeight: "bold"
+ });
+ shopTitle.anchor.set(0.5, 0);
+ shopTitle.x = 2048 / 2;
+ shopTitle.y = 2732 * 0.15;
+ self.addChild(shopTitle);
+ // Initialize purchased hats array if not present
+ if (!storage.purchasedHats) {
+ storage.purchasedHats = [];
+ }
+ // Hat grid
+ var gridItems = [];
+ var itemsPerRow = 3;
+ var itemWidth = 400;
+ var itemHeight = 400;
+ var padding = 50;
+ var startX = 2048 / 2 - (itemWidth + padding) * (itemsPerRow / 2) + itemWidth / 2 + 2048 * 0.01;
+ var startY = 2732 * 0.27;
+ availableHats.forEach(function (hat, index) {
+ var row = Math.floor(index / itemsPerRow);
+ var col = index % itemsPerRow;
+ var itemContainer = new Container();
+ itemContainer.x = startX + col * (itemWidth + padding);
+ itemContainer.y = startY + row * (itemHeight + padding);
+ // Background
+ var bg = LK.getAsset('Collisionblock', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: itemWidth,
+ height: itemHeight,
+ alpha: 0.5
+ });
+ itemContainer.addChild(bg);
+ // Hat image
+ var hatImg = LK.getAsset(hat.id, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: -50,
+ scaleX: 1.35,
+ // Increase width by 25%
+ scaleY: 1.35 // Increase height by 25%
+ });
+ itemContainer.addChild(hatImg);
+ // Hat name
+ var nameText = new Text2(hat.name, {
+ size: 50,
+ // Increased by 15%
+ fill: 0xFFFFFF
+ });
+ nameText.anchor.set(0.5, 0);
+ nameText.y = 50;
+ itemContainer.addChild(nameText);
+ // Price or status
+ var isPurchased = storage.purchasedHats && storage.purchasedHats.indexOf(hat.id) !== -1;
+ var isEquipped = storage.equippedHat === hat.id;
+ var statusText;
+ if (isEquipped) {
+ statusText = new Text2('EQUIPPED', {
+ size: 40,
+ fill: 0x00FF00
+ });
+ } else if (isPurchased) {
+ statusText = new Text2('OWNED', {
+ size: 40,
+ fill: 0xAAAAAA
+ });
+ } else {
+ statusText = new Text2(hat.price + ' coins', {
+ size: 40,
+ // Increased by 15%
+ fill: 0xFFD700
+ });
+ }
+ statusText.anchor.set(0.5, 0);
+ statusText.y = 100;
+ itemContainer.addChild(statusText);
+ // Add interaction
+ itemContainer.down = function () {
+ handleHatSelection(hat, statusText);
+ };
+ self.addChild(itemContainer);
+ gridItems.push(itemContainer);
+ });
+ // Back button
+ var backButton = new Text2('Back', {
+ size: 100,
+ fill: 0xFFFFFF,
+ fontWeight: "bold"
+ });
+ backButton.anchor.set(0.5, 0.5);
+ backButton.x = 2048 / 2;
+ backButton.y = 2732 * 0.875;
+ self.addChild(backButton);
+ backButton.down = function () {
+ self.menuBackground.destroy();
+ self.destroy();
+ isTitleScreen = true;
+ gameLogo.visible = true;
+ if (gameLogo.playButton) {
+ gameLogo.playButton.visible = true;
+ }
+ if (gameLogo.instructionsButton) {
+ gameLogo.instructionsButton.visible = true;
+ }
+ if (gameLogo.hatShopButton) {
+ gameLogo.hatShopButton.visible = true;
+ }
+ };
+ function handleHatSelection(hat, statusText) {
+ var isPurchased = storage.purchasedHats && storage.purchasedHats.indexOf(hat.id) !== -1;
+ var isEquipped = storage.equippedHat === hat.id;
+ if (isEquipped) {
+ // Unequip hat
+ storage.equippedHat = null;
+ // Update UI
+ self.menuBackground.destroy();
self.destroy();
+ showHatShop();
+ } else if (isPurchased) {
+ // Equip hat
+ storage.equippedHat = hat.id;
+ // Update UI
+ self.menuBackground.destroy();
+ self.destroy();
+ showHatShop();
+ } else if (storage.coins >= hat.price) {
+ // Purchase hat
+ storage.coins -= hat.price;
+ // Initialize array if needed
+ if (!storage.purchasedHats) {
+ storage.purchasedHats = [];
+ }
+ // Get current purchased hats as array
+ var currentHats = getPurchasedHats();
+ // Add new hat
+ currentHats.push(hat.id);
+ // Save back to storage
+ savePurchasedHats(currentHats);
+ storage.equippedHat = hat.id;
+ // Update UI
+ if (typeof coinDisplay !== 'undefined') {
+ coinDisplay.setText('Coins: ' + storage.coins);
+ }
+ // Update coin counter in game
+ coinCount = storage.coins;
+ coinCounter.setText(Math.min(coinCount, 9999).toString());
+ // Refresh shop
+ self.menuBackground.destroy();
+ self.destroy();
+ showHatShop();
+ // Show purchase confirmation
+ var confirmText = new Text2('Purchased ' + hat.name + '!', {
+ size: 100,
+ fill: 0x00FF00
+ });
+ confirmText.anchor.set(0.5, 0.5);
+ confirmText.x = 2048 / 2;
+ confirmText.y = 2732 / 2;
+ game.addChild(confirmText);
+ LK.setTimeout(function () {
+ confirmText.destroy();
+ }, 1500);
+ // Play purchase sound
+ LK.getSound('coin').play();
+ } else {
+ // Not enough coins
+ var errorText = new Text2('Not enough coins!', {
+ size: 100,
+ fill: 0xFF0000
+ });
+ errorText.anchor.set(0.5, 0.5);
+ errorText.x = 2048 / 2;
+ errorText.y = 2732 / 2;
+ game.addChild(errorText);
+ LK.setTimeout(function () {
+ errorText.destroy();
+ }, 1500);
}
+ }
+});
+var InstructionsButton = Container.expand(function () {
+ var self = Container.call(this);
+ var instructionsButtonGraphics = self.attachAsset('InstructionsButton', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.down = function () {
+ gameLogo.visible = false;
+ if (gameLogo.playButton) {
+ gameLogo.playButton.visible = false;
+ }
+ if (gameLogo.instructionsButton) {
+ gameLogo.instructionsButton.visible = false;
+ }
+ showInstructions();
};
});
-// Treasure Chest class
-var TreasureChest = Container.expand(function () {
+var InstructionsScreen = Container.expand(function () {
var self = Container.call(this);
- var chestGraphics = self.attachAsset('TreasureChest', {
+ var instructionsText = new Text2('Swipe up to jump,\ndown to dive,\nand right to dash!', {
+ size: 80,
+ fill: 0xFFFFFF,
+ align: "center"
+ });
+ instructionsText.anchor.set(0.5, 0);
+ instructionsText.x = 2048 / 2;
+ instructionsText.y = 2732 * 0.15;
+ self.addChild(instructionsText);
+ // Add power-up icons and explanations
+ var powerUpsInfo = [{
+ type: 'CoinMagnet',
+ text: 'Coin Magnet: Attracts coins'
+ }, {
+ type: 'Shield',
+ text: 'Shield: Protects from one hit'
+ }, {
+ type: 'PhoenixFeather',
+ text: 'Phoenix Feather: Revive once'
+ }, {
+ type: 'PowerDash',
+ text: 'Power Dash: Dash while jumping or diving'
+ }, {
+ type: 'Warning',
+ text: 'Warning: Alerts of upcoming obstacles'
+ }];
+ powerUpsInfo.forEach(function (info, index) {
+ var icon = LK.getAsset(info.type, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2 - 300 - 2048 * 0.10,
+ // Move icons further left
+ y: 2732 * 0.30 + index * 200
+ });
+ self.addChild(icon);
+ var text = new Text2(info.text, {
+ size: 60,
+ fill: 0xFFFFFF,
+ align: "left"
+ });
+ text.anchor.set(0, 0.5);
+ text.x = 2048 / 2 - 300 + 2048 * 0.035 - 2048 * 0.07;
+ text.y = icon.y + 20;
+ self.addChild(text);
+ });
+ var instructionDetails = new Text2('Jump over the Duck,\nDive away from the Eagle/Owl,\nDash away from the Fish.\n100 Coot Coins = 1 heart.', {
+ size: 70,
+ fill: 0xFFFFFF,
+ align: "center"
+ });
+ instructionDetails.anchor.set(0.5, 0);
+ instructionDetails.x = 2048 / 2;
+ instructionDetails.y = 2732 * 0.66; // Move up by 5% from the original position
+ self.addChild(instructionDetails);
+ var backButton = new Text2('Back', {
+ size: 100,
+ fill: 0xFFFFFF,
+ fontWeight: "bold"
+ });
+ backButton.anchor.set(0.5, 0.5);
+ backButton.x = 2048 / 2;
+ backButton.y = 2732 * 0.88; // Move back button down by 1.5%
+ self.addChild(backButton);
+ backButton.down = function () {
+ self.menuBackground.destroy(); // Remove the MenuBackground
+ self.destroy();
+ isTitleScreen = true;
+ gameLogo.visible = true;
+ if (gameLogo.playButton) {
+ gameLogo.playButton.visible = true;
+ }
+ if (gameLogo.instructionsButton) {
+ gameLogo.instructionsButton.visible = true;
+ }
+ };
+});
+// Class for the midgroundtrees
+var Midgroundtrees = Container.expand(function () {
+ var self = Container.call(this);
+ var midgroundtreesGraphics = self.attachAsset('Midgroundtrees', {
anchorX: 0.5,
+ anchorY: 0.7
+ });
+ self.speed = 3;
+ self.update = function () {
+ self.x -= self.speed * gameSpeed;
+ // self.y = coot.y;
+ if (self.x <= -self.width / 2) {
+ self.x += self.width * 2;
+ }
+ };
+});
+var Moon = Container.expand(function () {
+ var self = Container.call(this);
+ var moonGraphics = self.attachAsset('Moon', {
+ anchorX: 0.5,
anchorY: 0.5
});
- self.speedX = -5;
+ // Initialize moon properties
+ self.startX = -moonGraphics.width / 2; // Start off-screen to the left
+ self.startY = 2732 * 0.25; // Match the Sun's position (25% from the top)
+ self.endX = 2048 + moonGraphics.width / 2; // End off-screen to the right
+ self.arcHeight = 2732 * 0.1; // Match the Sun's arc height
+ self.duration = 2 * 60 * 60; // 2 minutes in ticks (assuming 60 FPS)
+ self.ticks = 0;
+ // For the Moon class, replace the update function with:
self.update = function () {
- self.x += self.speedX;
- if (self.x < -chestGraphics.width / 2) {
+ if (!self.tweenStarted) {
+ // Set initial position
+ self.x = self.startX;
+ self.y = self.startY;
+ self.tweenStarted = true;
+ // First tween: Move up in an arc
+ tween(self, {
+ x: self.startX + (self.endX - self.startX) * 0.5,
+ y: self.startY - self.arcHeight
+ }, {
+ duration: 60 * 1000,
+ // 1 minute in milliseconds
+ easing: tween.sineInOut,
+ onFinish: function onFinish() {
+ // Second tween: Move down in an arc to end position
+ tween(self, {
+ x: self.endX,
+ y: self.startY
+ }, {
+ duration: 60 * 1000,
+ // 1 minute in milliseconds
+ easing: tween.sineInOut,
+ onFinish: function onFinish() {
+ self.destroy();
+ // Switch to day state
+ isDay = true;
+ isNight = false;
+ DayCount += 1;
+ dayCountDisplay.show();
+ // Stop spawning fireflies
+ if (fireflySpawnInterval) {
+ LK.clearInterval(fireflySpawnInterval);
+ fireflySpawnInterval = null;
+ }
+ var newSun = new Sun();
+ newSun.x = newSun.startX; // Use the sun's defined starting X position
+ newSun.y = newSun.startY; // Set the proper starting Y position
+ game.addChild(newSun);
+ }
+ });
+ }
+ });
+ }
+ };
+});
+// Moved Owl logic into Obstacle class
+var Obstacle = Container.expand(function (type) {
+ var self = Container.call(this);
+ var graphics;
+ var collisionBlock = self.addChild(new CollisionBlock());
+ collisionBlock.x = 0;
+ collisionBlock.y = 0;
+ graphics = self.attachAsset(type, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Add a Ripple instance to the Duck obstacle
+ if (type === 'Duck') {
+ self.lastRippleTime = Date.now();
+ var ripple = ObjectPool.get('Ripple', Ripple);
+ ripple.x = 0; // Center the ripple on the Duck
+ ripple.y = graphics.height / 2; // Position the ripple at the bottom of the Duck
+ self.addChildAt(ripple, 0); // Add ripple below the Duck but above the water layer
+ }
+ self.speedX = -6;
+ if (type === 'Fish') {
+ self.isJumping = false;
+ self.pauseTime = 0;
+ graphics.tint = 0x4444ff;
+ graphics.alpha = 0.7;
+ }
+ if (type === 'Fish') {
+ self.speedX = -6; // Back to original fast swimming speed
+ self.jumpSpeed = 0.05; // Slow jump speed control
+ self.isJumping = false;
+ self.isPausing = false;
+ self.pauseTime = 0;
+ self.lastSplashTime = Date.now(); // Add splash timer
+ graphics.tint = 0x4444ff; // Set underwater blue tint initially
+ graphics.alpha = 0.7; // Set underwater opacity initially
+ self.isFalling = false;
+ self.jumpVelocity = 0;
+ self.jumpStartY = self.y; // Store original position
+ self.jumpTime = 0; // Initialize jump time counter
+ self.y = 2732 * 0.90; // Set Fish Y position to the bottom of the Coot's dive
+ }
+ if (type === 'Eagle') {
+ self.lastFeatherTime = Date.now();
+ self.targetY = coot.isDiving || coot.isReturning ? coot.originalY : coot.y;
+ self.speedY = (self.targetY - self.y) / 100;
+ self.speedX = -8; // Add horizontal speed variable for eagle
+ }
+ if (type === 'Owl') {
+ self.speedX = -6; // Speed of the owl moving left
+ self.speedY = 0; // Initial vertical speed
+ self.x = 2048 + graphics.width / 2; // Spawn at the top right of the screen
+ self.isDiving = false; // Initialize isDiving state
+ self.hasDived = false; // Initialize hasDived state to false by default
+ if (!self.soundPlayed && self.x >= 2048 - 50) {
+ LK.getSound('owl').play();
+ self.soundPlayed = true; // Set flag to prevent repeating
+ }
+ }
+ self.update = function () {
+ self.x += self.speedX * gameSpeed;
+ if (type === 'Fish') {
+ // Move horizontally
+ self.x += self.speedX;
+ // Generate underwater splash effects
+ if (!self.isJumping && Date.now() - self.lastSplashTime >= 200) {
+ // Generate every 200ms
+ var numSplashes = Math.floor(Math.random() * 2) + 1; // 1-2 splashes
+ for (var i = 0; i < numSplashes; i++) {
+ var splash = ObjectPool.get('Splash', Splash);
+ splash.x = self.x + (Math.random() * graphics.width - graphics.width / 2); // Random position along fish body
+ splash.y = self.y;
+ splash.tint = 0x4444ff; // Match fish's underwater tint
+ game.addChildAt(splash, game.getChildIndex(self) - 1);
+ }
+ self.lastSplashTime = Date.now();
+ }
+ // Check if crossing under Coot
+ if (self.x <= coot.x && !self.isJumping) {
+ self.speedX = 0;
+ graphics.alpha = 0;
+ self.pauseTime += 0.02;
+ // Add this check for when to reappear
+ if (self.pauseTime >= 1 && !self.isJumping) {
+ LK.getSound('fishsplash').play();
+ graphics.alpha = 1;
+ graphics.rotation = Math.PI / 2;
+ self.isJumping = true;
+ self.jumpStartY = self.y;
+ // Create splash burst when starting jump
+ var burstSplashes = Math.floor(Math.random() * 4) + 6;
+ for (var i = 0; i < burstSplashes; i++) {
+ var splash = ObjectPool.get('Splash', Splash);
+ splash.x = self.x + (Math.random() * graphics.width - graphics.width / 2);
+ splash.y = self.jumpStartY - Math.random() * 200;
+ game.addChildAt(splash, game.getChildIndex(self) - 1);
+ }
+ // Create jump tween
+ // Change the tint directly at specific points instead of in onUpdate
+ // Create jump tween with faster duration
+ tween(self, {
+ y: self.jumpStartY - 864 // Jump height
+ }, {
+ duration: 350,
+ // 0.4 seconds up
+ easing: tween.sineOut,
+ onFinish: function onFinish() {
+ // Create fall tween with faster duration
+ tween(self, {
+ y: self.jumpStartY + 50 // Go slightly below starting point
+ }, {
+ duration: 300,
+ // 0.4 seconds down
+ easing: tween.sineIn,
+ onFinish: function onFinish() {
+ Obstacle.lastDestroyTime = Date.now();
+ currentObstacle = null;
+ self.destroy();
+ }
+ });
+ }
+ });
+ }
+ }
+ if (self.isJumping) {
+ // Hardcoded tint change based on absolute position
+ var jumpProgress = Math.abs(self.y - self.jumpStartY) / 864;
+ if (self.y < self.jumpStartY - 100) {
+ graphics.tint = 0xffffff;
+ graphics.alpha = 1.0;
+ } else {
+ graphics.tint = 0x4444ff;
+ graphics.alpha = 0.7;
+ }
+ }
+ } else if (type === 'Eagle') {
+ self.y += self.speedY;
+ if (type === 'Eagle' && !self.soundPlayed && self.x >= 2048 - 50) {
+ LK.getSound('eagle').play();
+ self.soundPlayed = true; // Set flag to prevent repeating
+ }
+ if (Date.now() - self.lastFeatherTime >= 900) {
+ // Feather spawn every 900ms
+ var numFeathers = Math.floor(Math.random() * 2) + 2; // Spawn 2-3 feathers
+ for (var i = 0; i < numFeathers; i++) {
+ var feather = ObjectPool.get('EagleFeather', EagleFeather);
+ feather.x = self.x + (Math.random() * 20 - 10); // Slight horizontal variation
+ feather.y = self.y + graphics.height / 2;
+ game.addChildAt(feather, game.getChildIndex(self) - 1);
+ }
+ self.lastFeatherTime = Date.now();
+ }
+ if (self.x <= -self.width / 2) {
+ self.destroy(); // Destroy the obstacle when it moves off-screen
+ Obstacle.lastDestroyTime = Date.now(); // Set lastDestroyTime when destroyed
+ console.log("Obstacle destroyed at " + Obstacle.lastDestroyTime);
+ }
+ if (type === 'Eagle') {
+ self.targetY = coot.originalY - coot.height / 2; // Aim slightly higher on the coot
+ self.speedY = (self.targetY - self.y) / (50 / gameSpeed);
+ self.lastWasSwooping = self.y > self.targetY;
+ }
+ } else if (type === 'Duck') {
+ // Add sinusoidal wave pattern travel for Duck
+ if (type === 'Duck') {
+ self.y += Math.sin(self.x * 0.00625) * 2.7; // Adjusted sinusoidal wave pattern with further reduced frequency and increased amplitude
+ }
+ if (type === 'Duck') {
+ // Play duck sound every 2 seconds
+ if (LK.ticks % 100 == 0) {
+ // 120 frames = 2 seconds at 60 FPS
+ LK.getSound('duck').play();
+ }
+ }
+ // Ripple spawn logic
+ if (Date.now() - self.lastRippleTime >= 500) {
+ var ripple = ObjectPool.get('Ripple', Ripple);
+ ripple.x = self.x;
+ ripple.y = self.y + graphics.height / 2;
+ game.addChildAt(ripple, game.getChildIndex(self) - 1);
+ self.lastRippleTime = Date.now();
+ }
+ // Existing destroy logic
+ if (self.x <= -self.width / 2) {
+ self.destroy();
+ Obstacle.lastDestroyTime = Date.now();
+ console.log("Obstacle destroyed at " + Obstacle.lastDestroyTime);
+ }
+ } else if (type === 'Owl') {
+ if (coot) {
+ if (!self.isDiving && self.x > coot.x) {
+ self.x += self.speedX * gameSpeed; // Move Owl left until it reaches Coot's X position
+ } else {
+ if (!self.hasDived) {
+ self.isDiving = true; // Set isDiving state
+ if (coot.intersects(collisionBlock)) {
+ self.hasDived = true; // Set hasDived state only on intersection with Coot
+ }
+ self.speedX = 0; // Stop left movement
+ if (!coot.isDiving) {
+ self.speedY = (coot.y - self.y) / 40; // Adjust speed to track Coot's Y position at half speed
+ self.y += self.speedY * gameSpeed; // Move Owl towards Coot
+ self.x += (coot.x - self.x) / 20 * gameSpeed; // Move Owl towards Coot's X position
+ }
+ if (self.y >= coot.originalY) {
+ self.isDiving = false; // Remove isDiving state
+ self.speedX = -6; // Set speed to fly away to the left
+ self.speedY = -3; // Add upward movement
+ } else if (self.isDiving) {
+ var shadowClone = ObjectPool.get('ShadowClone', ShadowClone);
+ shadowClone.x = self.x;
+ shadowClone.y = self.y;
+ game.addChild(shadowClone);
+ }
+ }
+ }
+ // Check if Coot's state requires Owl to fly off
+ if (self.isDiving && (coot.isDiving || coot.isReturning || coot.returnDelay > 0 || coot.intersects(collisionBlock))) {
+ self.isDiving = false; // Remove isDiving state
+ self.speedX = -6; // Set speed to fly away to the left
+ self.speedY = -3; // Add upward movement
+ self.x += self.speedX * gameSpeed;
+ self.y += self.speedY * gameSpeed; // Move Owl upwards as it flies away
+ if (self.x < -self.width / 2) {
+ self.destroy(); // Remove Owl from the game when off-screen
+ }
+ }
+ }
+ }
+ collisionBlock.x = 0;
+ collisionBlock.y = 0;
+ };
+});
+var OwlWarningIcon = Container.expand(function () {
+ var self = Container.call(this);
+ var iconGraphics = self.attachAsset('OwlIcon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.75
+ });
+ self.flashInterval = 0;
+ self.update = function () {
+ self.flashInterval++;
+ if (coot.isWarningActive) {
+ if (self.flashInterval % 30 < 15) {
+ iconGraphics.alpha = 0.75;
+ } else {
+ iconGraphics.alpha = 0.5;
+ }
+ } else {
+ iconGraphics.alpha = 0;
+ }
+ };
+});
+var PhoenixFeatherIcon = Container.expand(function () {
+ var self = Container.call(this);
+ var iconGraphics = self.attachAsset('PhoenixFeatherIcon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.2 // Start dim, not opaque
+ });
+ self.update = function () {
+ iconGraphics.alpha = coot && coot.hasPhoenixFeather ? 1 : 0.2; // Set alpha based on possession
+ };
+});
+var PlayButton = Container.expand(function () {
+ var self = Container.call(this);
+ var playButtonGraphics = self.attachAsset('PlayButton', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.down = function () {
+ // Exit title screen
+ LK.getSound('powerup').play(); // Play coothurt sound
+ LK.effects.flashScreen(0xFFFFFF, 300); // Flash screen red for 100ms
+ LK.setTimeout(function () {
+ // Slide out all elements
+ isTitleScreen = false;
+ var slideOutInterval = LK.setInterval(function () {
+ gameLogo.x += 50;
+ self.x += 50;
+ if (gameLogo.instructionsButton) {
+ gameLogo.instructionsButton.x += 50;
+ }
+ // Make sure to include the hat shop button here
+ if (gameLogo.hatShopButton) {
+ gameLogo.hatShopButton.x += 50;
+ }
+ if (gameLogo.x > 2048 + gameLogo.width / 2) {
+ LK.clearInterval(slideOutInterval);
+ self.destroy();
+ if (gameLogo.instructionsButton) {
+ gameLogo.instructionsButton.destroy();
+ }
+ if (gameLogo.hatShopButton) {
+ gameLogo.hatShopButton.destroy();
+ }
+ // Start game after animations
+ startGame();
+ }
+ }, 16);
+ }, 500);
+ };
+});
+var PowerUp = Container.expand(function (type) {
+ var self = Container.call(this);
+ var powerUpGraphics = self.attachAsset(type, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Initialize power-up properties
+ self.speedX = -5; // Speed of the power-up moving left
+ self.collected = false; // Flag to check if the power-up is collected
+ self.update = function () {
+ // Add pulsating effect
+ var pulseScale = 0.05 * Math.sin(LK.ticks * 0.1) + 1;
+ powerUpGraphics.scale.set(pulseScale);
+ // Add bobbing effect
+ self.y += Math.sin(LK.ticks * 0.05) * 0.5;
+ // Move the power-up left
+ self.x += self.speedX * gameSpeed;
+ // Check for collection by the Coot
+ if (coot && !self.collected && coot.intersects(self)) {
+ if (type === 'PhoenixFeather' && coot.hasPhoenixFeather || type === 'Shield' && coot.isShielded) {
+ return; // Do not collect if already active
+ }
+ self.collected = true;
+ activatePowerUp(type);
self.destroy();
}
+ // Destroy the power-up if it goes off screen
+ if (self.x < -powerUpGraphics.width / 2) {
+ self.destroy();
+ }
};
+ function activatePowerUp(type) {
+ LK.getSound('powerup').play(); // Play powerup sound effect when a power-up is collected
+ var powerUpConfig = {
+ 'CoinMagnet': {
+ duration: 15000,
+ state: 'isMagnetActive'
+ },
+ 'PowerDash': {
+ duration: 30000,
+ state: 'isPowerDashActive'
+ },
+ 'Warning': {
+ duration: 30000,
+ state: 'isWarningActive'
+ },
+ 'Shield': {
+ duration: 0,
+ // Shield is instant and doesn't have a duration
+ state: 'isShielded'
+ },
+ 'PhoenixFeather': {
+ duration: 0,
+ // Phoenix Feather is instant and doesn't have a duration
+ state: 'hasPhoenixFeather'
+ }
+ };
+ var config = powerUpConfig[type];
+ var startTime = Date.now();
+ if (config) {
+ // Removed interval-based state management
+ if (type === 'Shield') {
+ coot.isShielded = true;
+ coot.shieldGraphics = coot.addChild(LK.getAsset('Shield', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: coot.width / 200,
+ // Scale to cover Coot
+ scaleY: coot.height / 204.2,
+ // Scale to cover Coot
+ alpha: 0.5 // Set opacity to 50%
+ }));
+ return; // Exit early as Shield doesn't need a timer
+ }
+ if (type === 'PhoenixFeather') {
+ coot.hasPhoenixFeather = true;
+ return; // Exit early as Phoenix Feather doesn't need a timer
+ }
+ coot[config.state] = true; // Ensure state is set to true
+ coot.powerUpTimers[type].endTime = Date.now() + config.duration; // Set power-up end time
+ var existingPowerUp = powerUpDisplay.activePowerUps.find(function (p) {
+ return p.type === type;
+ });
+ if (existingPowerUp) {
+ // Calculate remaining time in milliseconds
+ var timeRemaining = existingPowerUp.startTime + existingPowerUp.duration - Date.now();
+ if (timeRemaining > 0) {
+ config.duration += timeRemaining; // Add remaining time to new duration
+ startTime = Date.now(); // Reset start time to now for accurate duration
+ }
+ LK.clearInterval(existingPowerUp.interval);
+ existingPowerUp.startTime = Date.now(); // Update startTime to reflect new total duration
+ existingPowerUp.duration = config.duration; // Update duration
+ existingPowerUp.interval = createInterval(config, existingPowerUp.startTime);
+ existingPowerUp.timer = config.duration / 1000; // Update visual timer
+ return; // Exit early as we have updated the existing power-up
+ }
+ powerUpDisplay.addPowerUp(type, config.duration / 1000, startTime); // Include startTime for accurate remaining time
+ }
+ }
});
+var PowerUpDisplay = Container.expand(function () {
+ var self = Container.call(this);
+ self.x = 2048 / 2; // Center horizontally
+ self.y = 2732 * 0.9; // Position at bottom center
+ self.activePowerUps = [];
+ self.update = function () {
+ // Update each power-up display
+ self.activePowerUps.forEach(function (powerUp, index) {
+ powerUp.timer -= (Date.now() - powerUp.lastUpdateTime) / 1000; // Decrease timer based on real time
+ powerUp.lastUpdateTime = Date.now(); // Update the last update time
+ powerUp.text.setText(Math.max(0, Math.ceil(powerUp.timer)) + 's'); // Ensure timer doesn't show negative values
+ // Remove power-up if timer reaches 0
+ if (powerUp.timer <= 0) {
+ powerUp.icon.destroy();
+ powerUp.text.destroy();
+ self.activePowerUps.splice(index, 1);
+ self.repositionPowerUps();
+ }
+ });
+ };
+ self.addPowerUp = function (type, duration) {
+ var existingPowerUp = self.activePowerUps.find(function (p) {
+ return p.type === type;
+ });
+ if (existingPowerUp) {
+ existingPowerUp.timer += duration;
+ existingPowerUp.lastUpdateTime = Date.now();
+ existingPowerUp.text.setText(Math.max(0, Math.ceil(existingPowerUp.timer)) + 's'); // Update visual timer
+ return;
+ }
+ var iconAssetMap = {
+ 'CoinMagnet': 'CoinMagnet',
+ 'PowerDash': 'PowerDash',
+ 'Warning': 'Warning',
+ 'Shield': 'Shield',
+ 'PhoenixFeather': 'PhoenixFeather'
+ };
+ if (iconAssetMap[type]) {
+ var icon = LK.getAsset(iconAssetMap[type], {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 1.0,
+ scaleY: 1.0
+ });
+ } else {
+ console.error("Power-up type not found in iconAssetMap: ", type);
+ return;
+ }
+ var text = new Text2(duration + 's', {
+ size: 100,
+ fill: 0xFFFFFF
+ });
+ text.anchor.set(0.5, 0.5);
+ self.addChild(icon);
+ self.addChild(text);
+ self.activePowerUps.push({
+ icon: icon,
+ text: text,
+ timer: duration,
+ type: type,
+ lastUpdateTime: Date.now()
+ });
+ self.repositionPowerUps();
+ };
+ self.repositionPowerUps = function () {
+ var totalWidth = self.activePowerUps.reduce(function (acc, powerUp) {
+ return acc + powerUp.icon.width + powerUp.text.width + 40; // 40 is the new spacing
+ }, 0);
+ var startX = -totalWidth / 2;
+ self.activePowerUps.forEach(function (powerUp) {
+ powerUp.icon.x = startX + powerUp.icon.width / 2;
+ powerUp.text.x = powerUp.icon.x + powerUp.icon.width / 2 + 40; // 40 is the new spacing between icon and text
+ startX += powerUp.icon.width + powerUp.text.width + 20;
+ });
+ };
+});
+var Ripple = Container.expand(function () {
+ var self = Container.call(this);
+ var rippleGraphics;
+ self.initialScale = 0.05;
+ self.growthRate = 0.02;
+ self.fadeRate = 0.01;
+ self.maxScale = 2.0;
+ self.init = function () {
+ if (!rippleGraphics) {
+ rippleGraphics = self.attachAsset('Ripple', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ rippleGraphics.scaleX = self.initialScale;
+ rippleGraphics.scaleY = self.initialScale;
+ rippleGraphics.alpha = 1;
+ return self;
+ };
+ self.reset = function () {
+ rippleGraphics.scaleX = self.initialScale;
+ rippleGraphics.scaleY = self.initialScale;
+ rippleGraphics.alpha = 1;
+ return self;
+ };
+ self.destroy = function () {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('Ripple', self);
+ };
+ self.update = function () {
+ rippleGraphics.scaleX += self.growthRate;
+ rippleGraphics.scaleY += self.growthRate;
+ rippleGraphics.alpha -= self.fadeRate;
+ if (rippleGraphics.scaleX >= self.maxScale || rippleGraphics.alpha <= 0) {
+ self.destroy();
+ }
+ };
+ return self.init();
+});
+var ShadowClone = Container.expand(function () {
+ var self = Container.call(this);
+ var cloneGraphics;
+ self.fadeRate = 0.05;
+ self.init = function () {
+ if (!cloneGraphics) {
+ cloneGraphics = self.attachAsset('Owl', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ });
+ } else {
+ cloneGraphics.alpha = 0.5;
+ }
+ return self;
+ };
+ self.reset = function () {
+ if (cloneGraphics) {
+ cloneGraphics.alpha = 0.5;
+ }
+ return self;
+ };
+ self.destroy = function () {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ ObjectPool.recycle('ShadowClone', self);
+ };
+ self.update = function () {
+ cloneGraphics.alpha -= self.fadeRate;
+ if (cloneGraphics.alpha <= 0) {
+ self.destroy();
+ }
+ };
+ return self.init();
+});
+// Static respawn delay property
+// Class for the water splash particles
+var Splash = Container.expand(function () {
+ var self = Container.call(this);
+ var splashGraphics;
+ var scale;
+ // Initialize variables but don't create graphics
+ self.speedX = 0;
+ self.speedY = 0;
+ self.gravity = 0.1;
+ self.init = function () {
+ // Only create graphics if they don't exist
+ if (!splashGraphics) {
+ scale = Math.random() * 0.75 + 0.25;
+ splashGraphics = self.attachAsset('Watersplash', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: scale,
+ scaleY: scale
+ });
+ }
+ // Set initial properties
+ self.speedX = Math.random() * 2 - 1;
+ self.speedY = -Math.random() * 5;
+ splashGraphics.alpha = 1;
+ return self;
+ };
+ self.reset = function () {
+ // Reset properties without recreating the graphics
+ self.speedX = Math.random() * 2 - 1;
+ self.speedY = -Math.random() * 5;
+ if (splashGraphics) {
+ splashGraphics.alpha = 1;
+ splashGraphics.rotation = 0;
+ }
+ return self;
+ };
+ self.cleanup = function () {
+ // Clear any references to other objects
+ self.coin = null;
+ };
+ self.destroy = function () {
+ // Instead of destroying, return to pool
+ self.parent.removeChild(self);
+ ObjectPool.recycle('Splash', self);
+ };
+ self.update = function () {
+ self.x += self.speedX * gameSpeed;
+ self.y += self.speedY * gameSpeed;
+ self.speedY += self.gravity;
+ // Add rotation based on the speed of the particle
+ self.rotation += self.speedX / 10;
+ if (self.y > 2732) {
+ // If the particle is below the screen
+ self.destroy(); // This now recycles instead of destroying
+ }
+ };
+ return self.init(); // Initialize on creation
+});
+var Sun = Container.expand(function () {
+ var self = Container.call(this);
+ var sunGraphics = self.attachAsset('Sun', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Initialize sun properties
+ self.startX = -sunGraphics.width / 2; // Start off-screen to the left
+ self.startY = 2732 * 0.25; // 25% from the top
+ self.endX = 2048 + sunGraphics.width / 2; // End off-screen to the right
+ self.arcHeight = 2732 * 0.1; // Arc height
+ self.duration = 2 * 60 * 60; // 2 minutes in ticks (assuming 60 FPS)
+ self.ticks = 0;
+ // For the Sun class, replace the update function with:
+ self.update = function () {
+ if (!self.tweenStarted) {
+ self.tweenStarted = true;
+ // Create path tween for the arc motion
+ tween(self, {
+ x: self.endX,
+ y: self.startY - self.arcHeight
+ }, {
+ duration: 2 * 60 * 1000,
+ // 2 minutes in milliseconds
+ easing: tween.sineInOut,
+ onFinish: function onFinish() {
+ self.destroy();
+ isDay = false;
+ isNight = true;
+ // Start spawning fireflies
+ fireflySpawnInterval = LK.setInterval(function () {
+ var newFirefly = new Firefly();
+ newFirefly.x = Math.random() * 2048;
+ newFirefly.y = Math.random() * 2732;
+ game.addChild(newFirefly);
+ }, 1000);
+ game.addChild(new Moon());
+ }
+ });
+ }
+ };
+});
+// Class for the water
+var Water = Container.expand(function () {
+ var self = Container.call(this);
+ var waterGraphics = self.attachAsset('Water', {
+ anchorX: 0.5,
+ anchorY: 0.7
+ });
+ self.speed = 2;
+ self.update = function () {
+ self.x -= self.speed * gameSpeed;
+ // self.y = midgroundtrees1.y + midgroundtrees1.height / 2;
+ if (self.x <= -self.width / 2) {
+ self.x += self.width * 2;
+ }
+ };
+});
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x87CEEB // Light blue background for water
+ backgroundColor: 0x000000
});
/****
* Game Code
****/
-var boat = game.addChild(new Boat());
-boat.x = 2048 / 2;
-boat.y = 2732 * 0.8;
-var oceanBackground = LK.getAsset('OceanBackground', {
+function savePurchasedHats(hatsArray) {
+ if (Array.isArray(hatsArray)) {
+ storage.purchasedHats = hatsArray.join(",");
+ }
+}
+function getPurchasedHats() {
+ if (!storage.purchasedHats) {
+ return [];
+ }
+ return storage.purchasedHats.split ? storage.purchasedHats.split(",") : storage.purchasedHats;
+}
+var cootGraphics = {
+ width: 550,
+ height: 423.5
+}; // Define cootGraphics with default dimensions
+var availableHats = [{
+ id: 'TopHat',
+ name: 'Top Hat',
+ price: 100,
+ x: cootGraphics.width / 2.65,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.35
+}, {
+ id: 'Cowboy',
+ name: 'Cowboy Hat',
+ price: 200,
+ x: cootGraphics.width / 2.4,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.6,
+ rotation: -0.35
+}, {
+ id: 'Crown',
+ name: 'Royal Crown',
+ price: 800,
+ x: cootGraphics.width / 2.65,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.35
+}, {
+ id: 'Beanie',
+ name: 'Toque',
+ price: 200,
+ x: cootGraphics.width / 2.65,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.35
+}, {
+ id: 'Captain',
+ name: 'Captain Hat',
+ price: 500,
+ x: cootGraphics.width / 2.65,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.35
+}, {
+ id: 'Sockhat',
+ name: 'Cap of Legend',
+ price: 700,
+ x: cootGraphics.width / 3,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.4,
+ rotation: 0.25
+}, {
+ id: 'Propeller',
+ name: 'Propeller Cap',
+ price: 1000,
+ x: cootGraphics.width / 2.65,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.35
+}, {
+ id: 'Sombrero',
+ name: 'Sombrero',
+ price: 300,
+ x: cootGraphics.width / 2.65,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.35
+}, {
+ id: 'Knight',
+ name: 'Knight Helmet',
+ price: 500,
+ x: cootGraphics.width / 2.8,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 1.95,
+ rotation: 0.27
+}, {
+ id: 'Viking',
+ name: 'Viking Helmet',
+ price: 600,
+ x: cootGraphics.width / 2.7,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.6,
+ rotation: -0.35
+}, {
+ id: 'Astronaut',
+ name: 'Astronaut Helmet',
+ price: 600,
+ x: cootGraphics.width / 2.95,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2,
+ rotation: 0.27
+}, {
+ id: 'Fedora',
+ name: 'Fedora',
+ price: 100,
+ x: cootGraphics.width / 2.6,
+ y: -cootGraphics.height / 3 + cootGraphics.height / 2.7,
+ rotation: -0.15
+}];
+availableHats.sort(function (a, b) {
+ return a.price - b.price;
+});
+function showHatShop() {
+ var menuBackground = LK.getAsset('MenuBackground', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2
+ });
+ game.addChild(menuBackground);
+ var hatShopScreen = new HatShopScreen();
+ game.addChild(hatShopScreen);
+ hatShopScreen.menuBackground = menuBackground;
+}
+function updateBackgroundFade() {
+ // Check for day to night transition (Sun)
+ if (isDay && !isNight) {
+ game.children.forEach(function (child) {
+ if (child instanceof Sun) {
+ // Use x position to determine fade progress
+ // When sun is halfway across screen, start fading
+ if (child.x > 2048 * 0.85) {
+ var fadeProgress = (child.x - 2048 * 0.85) / (2048 * 0.25);
+ nightBackground.alpha = Math.min(fadeProgress, 1);
+ }
+ }
+ });
+ }
+ // Check for night to day transition (Moon)
+ if (isNight && !isDay) {
+ game.children.forEach(function (child) {
+ if (child instanceof Moon) {
+ // Use x position to determine fade progress
+ // When moon is halfway across screen, start fading out
+ if (child.x > 2048 * 0.85) {
+ var fadeProgress = (child.x - 2048 * 0.85) / (2048 * 0.25);
+ nightBackground.alpha = Math.max(1 - fadeProgress, 0);
+ }
+ }
+ });
+ }
+}
+// Define createInterval function to fix ReferenceError
+var ObjectPool = {
+ pools: {},
+ getPool: function getPool(type) {
+ if (!this.pools[type]) {
+ this.pools[type] = [];
+ }
+ return this.pools[type];
+ },
+ get: function get(type, Constructor, initParams) {
+ var pool = this.getPool(type);
+ var obj;
+ if (pool.length > 0) {
+ obj = pool.pop();
+ if (typeof obj.reset === 'function') {
+ obj.reset(initParams);
+ }
+ return obj;
+ } else {
+ return new Constructor(initParams);
+ }
+ },
+ recycle: function recycle(type, object) {
+ // Don't store null or undefined objects
+ if (!object) {
+ return;
+ }
+ var pool = this.getPool(type);
+ // Limit pool size to prevent memory issues
+ if (pool.length < 50) {
+ // Clear any references that might cause memory leaks
+ if (typeof object.cleanup === 'function') {
+ object.cleanup();
+ }
+ pool.push(object);
+ }
+ }
+};
+function createInterval(config, startTime) {
+ return LK.setInterval(function () {
+ var timeRemaining = config.duration - (Date.now() - startTime);
+ if (timeRemaining <= 0) {
+ LK.clearInterval(this);
+ }
+ }, 1000);
+}
+function showInstructions() {
+ var menuBackground = LK.getAsset('MenuBackground', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2
+ });
+ game.addChild(menuBackground);
+ var instructionsScreen = new InstructionsScreen();
+ game.addChild(instructionsScreen);
+ instructionsScreen.menuBackground = menuBackground; // Store reference for later removal
+}
+function startGame() {
+ // Fade in background music
+ LK.playMusic('backgroundmusic', {
+ fade: {
+ start: 0,
+ end: 0.5,
+ duration: 1500
+ }
+ });
+ gameActive = true;
+ Obstacle.lastDestroyTime = Date.now();
+ // Create coot but start off-screen
+ coot = new Coot();
+ coot.x = -400; // Start off-screen left
+ coot.y = 2732 * 0.75 - 25;
+ game.addChild(coot); // Add coot normally
+ coot.updateHat();
+ game.setChildIndex(foreground1, game.children.length - 1);
+ game.setChildIndex(foreground2, game.children.length - 1);
+ // Initialize other game elements
+ if (powerUpDisplay && powerUpDisplay.parent) {
+ game.setChildIndex(powerUpDisplay, game.children.length - 1);
+ }
+ coot.phoenixFeatherIcon = phoenixFeatherIcon;
+ heartIcons.forEach(function (icon, index) {
+ icon.alpha = index < coot.lives ? 1 : 0.2;
+ });
+ dayCountDisplay = new DayCountDisplay();
+ LK.gui.top.addChild(dayCountDisplay);
+ dayCountDisplay.y = 2732 * 0.25;
+ sun = game.addChild(new Sun());
+ sun.x = sun.startX;
+ sun.y = sun.startY;
+ // Play whistle and start game sequence
+ LK.getSound('whistle').play();
+ LK.setTimeout(function () {
+ gameSpeed = 1.5;
+ // Animate coot running in
+ tween(coot, {
+ x: 2048 * 0.20
+ }, {
+ duration: 1000,
+ easing: tween.quadOut,
+ onFinish: function onFinish() {
+ // Store final positions after coot reaches destination
+ coot.originalX = coot.x;
+ coot.originalY = coot.y;
+ coot.y = coot.y || 0; // Initialize coot.y if undefined
+ coot.originalY = coot.originalY || 0; // Initialize coot.originalY if undefined
+ }
+ });
+ }, 1000); // Wait for whistle sound to finish
+}
+function handleShieldHit() {
+ // Remove shield asset
+ if (coot.shieldGraphics) {
+ coot.shieldGraphics.destroy();
+ coot.shieldGraphics = null;
+ }
+ coot.isShielded = false;
+ coot.isInvincible = true; // Set Coot to invincible state
+ LK.getSound('coothurt').play(); // Play coothurt sound effect when the shield is removed
+ // Flash effect for invincibility
+ var flashInterval = LK.setInterval(function () {
+ coot.children[0].alpha = coot.children[0].alpha === 1 ? 0.5 : 1;
+ }, 100);
+ LK.setTimeout(function () {
+ LK.clearInterval(flashInterval);
+ coot.children[0].alpha = 1;
+ coot.isInvincible = false;
+ }, 1500);
+}
+// Define a single obstacleTypes array as a constant
+var obstacleTypes = ['Duck', 'Eagle', 'Fish', 'Owl'];
+var obstacleSpawnChances = {
+ Duck: 1,
+ Eagle: 1,
+ Fish: 1,
+ Owl: 1
+};
+Obstacle.getRandomDelay = function (min, max) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+};
+Obstacle.spawnDelay = 6000; // Further reduce default spawn delay to 6 seconds
+Obstacle.respawnDelay = {
+ Eagle: Obstacle.getRandomDelay(2250, 3750),
+ // Reduce Eagle respawn delay by 25%
+ Duck: Obstacle.getRandomDelay(2250, 3750),
+ // Reduce Duck respawn delay by 25%
+ Fish: Obstacle.getRandomDelay(2250, 3750),
+ // Reduce Fish respawn delay by 25%
+ Owl: Obstacle.getRandomDelay(2250, 3750) // Add Owl respawn delay
+};
+Obstacle.lastDestroyTime = Date.now() - 5000; // Initialize to ensure first spawn check passes
+var background = game.addChild(LK.getAsset('Background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
- y: 2732 / 2
-});
-game.addChild(oceanBackground);
-var waves = LK.getAsset('OceanWaves', {
+ y: 2732 / 2,
+ scaleX: 2048 / 2500,
+ scaleY: 2732 / 2500
+}));
+var nightBackground = game.addChild(LK.getAsset('NightBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
- y: 2732 * 0.9
+ y: 2732 / 2,
+ scaleX: 2048 / 2500,
+ scaleY: 2732 / 2500,
+ alpha: 0
+}));
+var DayCount = 1; // Global variable to keep track of the number of days, initialized to 1 at game start
+// Initialize the sun after title screen
+var sun;
+var isDay = true; // Initialize day state
+var isNight = false; // Initialize night state
+// Initialize the midgroundtrees
+var midgroundtrees1 = game.addChild(new Midgroundtrees());
+midgroundtrees1.x = 2048 / 2;
+midgroundtrees1.y = 2732 * 0.7;
+var midgroundtrees2 = game.addChild(new Midgroundtrees());
+midgroundtrees2.x = 2048 / 2 + midgroundtrees2.width;
+midgroundtrees2.y = 2732 * 0.7;
+// Initialize the water
+var water1 = game.addChild(new Water());
+water1.x = 2048 / 2;
+water1.y = midgroundtrees1.y + midgroundtrees1.height / 2;
+var water2 = game.addChild(new Water());
+water2.x = 2048 / 2 + water2.width;
+water2.y = midgroundtrees2.y + midgroundtrees2.height / 2;
+// Initialize game logo
+var gameLogo = LK.getAsset('GameIcon', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: -100,
+ // Start off-screen to the left
+ y: 2732 * 0.4 // Move up by 10% of the screen height
});
-game.addChild(waves);
-var obstacles = [];
-var powerups = [];
+game.addChild(gameLogo);
+// Initialize game variables
+var coot;
+var dragStartY = null; // Initialize dragStartY to null
+var dragStartX = null; // Initialize dragStartX to null
+var gameSpeed = 0; // Global variable for game speed, set to 0 during title screen
+var isTitleScreen = true; // Flag to indicate if the game is in the title screen state
+var gameActive = false; // Flag to indicate if the game is actively being played
+var speedIncreaseInterval = 30000; // 30 seconds in milliseconds
+var maxGameSpeed = 5.0; // Maximum game speed
+var lastSpeedIncreaseTime = Date.now(); // Track the last time speed was increased
var score = 0;
-var coinCount = 0;
-function spawnObstacle() {
- var obstacleTypes = [FloatingLog, StormCloud];
- var obstacle = new obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)]();
- obstacle.x = 2048 + obstacle.width / 2;
- obstacle.y = Math.random() * (2732 * 0.6) + 2732 * 0.2;
- obstacles.push(obstacle);
- game.addChild(obstacle);
+var coinCount = storage.coins || 0; // Initialize coinCount from storage
+var coinCounter = new Text2(Math.min(coinCount, 999).toString(), {
+ size: 150,
+ fill: 0xFFFFFF
+});
+coinCounter.anchor.set(1, 0); // Anchor to the top right corner
+var currentObstacle = null;
+var warningIcon = null;
+// Initialize the foreground
+var foreground1 = new Foreground();
+var foreground2 = new Foreground();
+// Removed duplicate addChild calls for foregrounds
+game.addChild(foreground1);
+game.addChild(foreground2);
+foreground1.x = 2048 / 2;
+foreground1.y = 2732 * 0.9;
+foreground2.x = foreground1.x + foreground1.width;
+foreground2.y = 2732 * 0.9;
+foreground1.isFirst = true;
+foreground1.other = foreground2;
+foreground2.other = foreground1;
+// Validate positioning
+if (Math.abs(foreground2.x - (foreground1.x + foreground1.width)) > 1) {
+ console.error("Foreground pieces are not correctly positioned!");
}
-function spawnPowerUp() {
- var powerUpTypes = [TreasureChest];
- var powerUp = new powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)]();
- powerUp.x = 2048 + powerUp.width / 2;
- powerUp.y = Math.random() * (2732 * 0.6) + 2732 * 0.2;
- powerups.push(powerUp);
- game.addChild(powerUp);
-}
-function updateScore() {
- score += 1;
- coinCounter.setText('SCORE: ' + score);
-}
+// Add coin counter display
var coinCounter = new Text2('0', {
size: 150,
+ // Increased size for better visibility
fill: 0xFFFFFF
});
-coinCounter.anchor.set(1, 0);
+coinCounter.anchor.set(1, 0); // Anchor to the top right corner
+// Add coin asset beside the coin counter
+var coinIcon = LK.getAsset('Coin', {
+ anchorX: 1,
+ anchorY: 0,
+ x: -coinCounter.width - 10,
+ // Position to the left of the counter with some padding
+ y: 0
+});
+LK.gui.topRight.addChild(coinIcon);
LK.gui.topRight.addChild(coinCounter);
+// Add heart icons to represent Coot's lives
+var heartIcons = [];
+for (var i = 0; i < 3; i++) {
+ // Always create 3 heart icons
+ var heartIcon = LK.getAsset('HeartLife', {
+ anchorX: 0,
+ anchorY: 0,
+ x: -coinCounter.width - 10 - i * 110,
+ y: coinIcon.height + 10
+ });
+ LK.gui.topRight.addChild(heartIcon);
+ heartIcons.push(heartIcon);
+}
+// Update heart icons based on remaining lives
+heartIcons.forEach(function (icon, index) {
+ icon.alpha = coot && index < coot.lives ? 1 : 0.2; // Dim the heart if life is lost
+});
+// Initialize PowerUpDisplay after foregrounds are set up
+var powerUpDisplay = new PowerUpDisplay();
+game.addChild(powerUpDisplay);
+// Initialize Phoenix Feather icon at the start of the game
+var phoenixFeatherIcon = new PhoenixFeatherIcon();
+// coot.phoenixFeatherIcon will be set after coot initialization
+phoenixFeatherIcon.x = heartIcons[0].x + heartIcons[0].width / 2 - phoenixFeatherIcon.width / 2; // Center below the leftmost heart icon
+phoenixFeatherIcon.y = heartIcons[0].y + heartIcons[0].height + 70; // Increase padding below the heart icon
+LK.gui.topRight.addChild(phoenixFeatherIcon);
+var dayCountDisplay;
game.update = function () {
- boat.update();
- // Update obstacles
- for (var i = obstacles.length - 1; i >= 0; i--) {
- obstacles[i].update();
- if (boat.intersects(obstacles[i])) {
- LK.effects.flashScreen(0xff0000, 1000);
- LK.showGameOver();
+ if (DayCount > 1 && !dayCountDisplay.visible) {
+ dayCountDisplay.show();
+ }
+ updateBackgroundFade();
+ if (isTitleScreen) {
+ // Update coinCounter text on the title screen
+ coinCounter.setText(Math.min(coinCount, 9999).toString());
+ coinIcon.x = -coinCounter.width - 10; // Update coin icon position to align with the coin counter
+ // Only update background, midground trees, water, and foreground during title screen
+ [midgroundtrees1, midgroundtrees2, water1, water2, foreground1, foreground2].forEach(function (element) {
+ element.update();
+ });
+ // Animate game logo sliding in from the left
+ if (gameLogo.x < 2048 / 2) {
+ // Move logo
+ gameLogo.x += 30; // Slide in quickly
+ // Move buttons at the same time
+ if (gameLogo.playButton) {
+ // Calculate how far along the animation we are (0-1)
+ var progress = (gameLogo.x + 100) / (2048 / 2 + 100);
+ // Position playButton in the center
+ gameLogo.playButton.x = -100 + progress * (2048 / 2 + 100);
+ // Position other buttons relative to playButton
+ gameLogo.instructionsButton.x = gameLogo.playButton.x - 320;
+ gameLogo.hatShopButton.x = gameLogo.playButton.x + 350;
+ }
+ } else {
+ // Ensure everything is at final position
+ gameLogo.x = 2048 / 2;
+ if (gameLogo.playButton) {
+ gameLogo.playButton.x = 2048 / 2;
+ gameLogo.instructionsButton.x = 2048 / 2 - 320;
+ gameLogo.hatShopButton.x = 2048 / 2 + 350;
+ }
}
- if (obstacles[i].x < -obstacles[i].width / 2) {
- obstacles[i].destroy();
- obstacles.splice(i, 1);
+ if (!gameLogo.playButton && !gameLogo.instructionsButton && !gameLogo.hatShopButton) {
+ var playButton = new PlayButton();
+ playButton.x = -100; // Start off-screen to the left, like the logo
+ playButton.y = gameLogo.y + gameLogo.height / 2 + 2732 * 0.06;
+ game.addChild(playButton);
+ gameLogo.playButton = playButton;
+ var instructionsButton = new InstructionsButton();
+ instructionsButton.x = -100; // Start off-screen to the left
+ instructionsButton.y = playButton.y + playButton.height;
+ game.addChild(instructionsButton);
+ gameLogo.instructionsButton = instructionsButton;
+ var hatShopButton = new HatShopButton();
+ hatShopButton.x = -100; // Start off-screen to the left
+ hatShopButton.y = playButton.y + playButton.height;
+ game.addChild(hatShopButton);
+ gameLogo.hatShopButton = hatShopButton;
}
+ return; // Exit update function to prevent further updates
}
- // Update power-ups
- for (var i = powerups.length - 1; i >= 0; i--) {
- powerups[i].update();
- if (boat.intersects(powerups[i])) {
- LK.getSound('treasure_collect').play();
- coinCount += 10;
- updateScore();
- powerups[i].destroy();
- powerups.splice(i, 1);
+ if (coot) {
+ coot.update();
+ }
+ phoenixFeatherIcon.update();
+ // Increase game speed every 20 seconds
+ if (!isTitleScreen && Date.now() - lastSpeedIncreaseTime >= speedIncreaseInterval) {
+ if (gameSpeed < maxGameSpeed) {
+ gameSpeed = Math.min(gameSpeed + 0.1, maxGameSpeed);
+ // Decrease respawn delay for all obstacles
+ Obstacle.respawnDelay.Eagle = Math.max(Obstacle.respawnDelay.Eagle - 500, 1000);
+ Obstacle.respawnDelay.Duck = Math.max(Obstacle.respawnDelay.Duck - 500, 1000);
+ Obstacle.respawnDelay.Fish = Math.max(Obstacle.respawnDelay.Fish - 500, 1000);
+ Obstacle.respawnDelay.Owl = Math.max(Obstacle.respawnDelay.Owl - 500, 1000);
}
- if (powerups[i] && powerups[i].x < -powerups[i].width / 2) {
- powerups[i].destroy();
- powerups.splice(i, 1);
+ lastSpeedIncreaseTime = Date.now();
+ }
+ // Define createInterval function to fix ReferenceError
+ // Removed the timer counter increment and display logic
+ // Check for collision between the Coot and the Collision Block of the current obstacle
+ if (currentObstacle && coot.intersects(currentObstacle.children[0])) {
+ if (coot.isShielded) {
+ handleShieldHit();
+ } else if (coot.isInvincible) {
+ // Do nothing, invincible state
+ } else {
+ coot.lives -= 1;
+ LK.getSound('coothurt').play(); // Play coothurt sound when Coot gets hit
+ if (coot.lives <= 0 && coot.hasPhoenixFeather) {
+ LK.getSound('phoenix').play(); // Play phoenix sound effect when lives are refilled
+ coot.hasPhoenixFeather = false; // Remove Phoenix Feather
+ phoenixFeatherIcon.update(); // Update Phoenix Feather icon
+ coot.lives = 3; // Refill all lives
+ heartIcons.forEach(function (icon) {
+ icon.alpha = 1; // Restore all heart icons
+ });
+ // Add Phoenix effect
+ coot.isInvincible = true; // Set Coot to invincible state
+ LK.effects.flashScreen(0xff0000, 1000); // Flash screen red for 1 second
+ var phoenix = LK.getAsset('Phoenix', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5 // Set initial opacity to 50%
+ });
+ phoenix.x = 2048 / 2;
+ phoenix.y = 2732 / 2;
+ game.addChild(phoenix);
+ LK.setTimeout(function () {
+ phoenix.destroy(); // Destroy the Phoenix asset
+ coot.isInvincible = false; // Remove invincibility after effect
+ }, 1500); // Wait for 1.5 seconds
+ } else if (coot.lives <= 0) {
+ coot.isFalling = true;
+ coot.fallStartY = coot.y;
+ coot.fallRotation = 0;
+ coot.fallSpeed = 5;
+ heartIcons[0].alpha = 0.2; // Dim the last heart icon to indicate all lives lost
+ } else {
+ coot.isInvincible = true;
+ heartIcons[coot.lives].alpha = 0.2; // Dim the heart icon to indicate a lost life
+ // Flash effect for invincibility
+ LK.effects.flashScreen(0xff0000, 100); // Flash screen red for 100ms
+ var flashInterval = LK.setInterval(function () {
+ coot.children[0].alpha = coot.children[0].alpha === 1 ? 0.5 : 1;
+ }, 100);
+ LK.setTimeout(function () {
+ LK.clearInterval(flashInterval);
+ coot.children[0].alpha = 1;
+ coot.isInvincible = false;
+ }, 1500);
+ }
}
}
- // Spawn obstacles and power-ups
- if (LK.ticks % 120 == 0) {
- spawnObstacle();
+ // Update PowerUpDisplay
+ powerUpDisplay.update();
+ // Update the midgroundtrees
+ midgroundtrees1.update();
+ midgroundtrees2.update();
+ // Update the water
+ water1.update();
+ water2.update();
+ // Update the current obstacle
+ // Check if the current obstacle needs destruction
+ if (currentObstacle && currentObstacle.x < -currentObstacle.width / 2) {
+ currentObstacle.destroy();
+ Obstacle.lastDestroyTime = Date.now();
+ currentObstacle = null;
}
- if (LK.ticks % 240 == 0) {
- spawnPowerUp();
+ // Check if it's time to spawn a new obstacle
+ if (gameActive && !currentObstacle) {
+ var timeSinceLastDestroy = Date.now() - Obstacle.lastDestroyTime;
+ if (timeSinceLastDestroy >= Obstacle.spawnDelay - 1000 && !warningIcon) {
+ if (coot.isWarningActive) {
+ LK.getSound('alert').play(); // Play alert sound when warning icon is displayed and player has the warning power up
+ }
+ var totalChance = obstacleSpawnChances.Duck + obstacleSpawnChances.Fish;
+ if (isDay) {
+ totalChance += obstacleSpawnChances.Eagle;
+ } else if (isNight) {
+ totalChance += obstacleSpawnChances.Owl;
+ }
+ var randomChance = Math.random() * totalChance;
+ var cumulativeChance = 0;
+ for (var i = 0; i < obstacleTypes.length; i++) {
+ if (obstacleTypes[i] === 'Eagle' && isDay || obstacleTypes[i] === 'Owl' && isNight || obstacleTypes[i] !== 'Eagle' && obstacleTypes[i] !== 'Owl') {
+ cumulativeChance += obstacleSpawnChances[obstacleTypes[i]];
+ if (randomChance < cumulativeChance) {
+ currentObstacleType = obstacleTypes[i];
+ obstacleSpawnChances[currentObstacleType] = 1; // Reset chance on spawn
+ break;
+ }
+ }
+ }
+ var warningIconClassMap = {
+ 'Duck': DuckWarningIcon,
+ 'Eagle': EagleWarningIcon,
+ 'Fish': FishWarningIcon,
+ 'Owl': OwlWarningIcon // Add OwlIcon to warning icons
+ };
+ warningIcon = game.addChild(new warningIconClassMap[currentObstacleType]());
+ warningIcon.x = 2048 / 2;
+ warningIcon.y = 2732 / 2;
+ }
+ if (timeSinceLastDestroy >= Obstacle.spawnDelay) {
+ if (warningIcon) {
+ warningIcon.destroy();
+ warningIcon = null;
+ }
+ currentObstacle = game.addChild(new Obstacle(currentObstacleType));
+ currentObstacle.x = 2048 + currentObstacle.width / 2; // Ensure it starts off-screen
+ currentObstacle.y = currentObstacleType === 'Duck' ? 2732 * 0.80 : currentObstacleType === 'Eagle' ? 2732 * 0.25 : currentObstacleType === 'Fish' ? 2732 * 0.85 : 2732 * 0.10; // Owl positioned at 10% from the top
+ // Increase spawn chance for obstacles not selected
+ obstacleTypes.forEach(function (type) {
+ if (type !== currentObstacleType) {
+ obstacleSpawnChances[type] += 0.5; // Increase chance by 0.5 for each non-selected obstacle
+ }
+ });
+ }
}
+ if (currentObstacle) {
+ currentObstacle.update();
+ }
+ // Check for collision between the Coot and Coins
+ game.children.forEach(function (child) {
+ if (child instanceof Coin && coot && coot.intersects(child) && !child.collecting) {
+ LK.getSound('coin').play(); // Play coin sound effect when coot touches the coin
+ child.collecting = true;
+ child.targetX = 2048 + child.children[0].width; // Target off-screen to the right
+ child.targetY = -child.children[0].height; // Target off-screen to the top
+ }
+ });
+ // Update the foreground
+ foreground1.update();
+ foreground2.update();
+ // Spawn butterflies randomly
+ if (isDay && LK.ticks % 720 == 0) {
+ // Every 3 seconds at 60 FPS
+ var newButterfly = ObjectPool.get('Butterfly', Butterfly);
+ newButterfly.x = 2048 + newButterfly.width / 2; // Start off-screen to the right
+ newButterfly.y = Math.random() * (2732 * 0.6) + 2732 * 0.2; // Random Y position within midground tree layer
+ game.addChild(newButterfly);
+ }
+ // Calculate spawn interval based on coin magnet state
+ var baseSpawnRate = 120; // Normal 2-second spawn rate
+ var magnetSpawnRate = 30; // 25% faster (120 * 0.75 = 90)
+ var currentSpawnRate = coot && coot.hasCoinMagnet ? magnetSpawnRate : baseSpawnRate;
+ if (LK.ticks % currentSpawnRate == 0) {
+ var newCoin = new Coin();
+ newCoin.x = 2048 + newCoin.width / 2;
+ newCoin.y = Math.random() * (2732 * 0.45) + 2732 * 0.35;
+ game.addChild(newCoin);
+ }
+ // Spawn power ups randomly
+ if (LK.ticks % 1080 == 0) {
+ // Every 3 seconds at 60 FPS
+ var powerUpTypes = [{
+ type: 'Shield',
+ weight: 20
+ }, {
+ type: 'PowerDash',
+ weight: 25
+ }, {
+ type: 'CoinMagnet',
+ weight: 25
+ }, {
+ type: 'Warning',
+ weight: 20
+ }, {
+ type: 'PhoenixFeather',
+ weight: 10
+ }];
+ var totalWeight = powerUpTypes.reduce(function (acc, powerUp) {
+ return acc + powerUp.weight;
+ }, 0);
+ var randomWeight = Math.random() * totalWeight;
+ var cumulativeWeight = 0;
+ var selectedPowerUpType;
+ for (var i = 0; i < powerUpTypes.length; i++) {
+ cumulativeWeight += powerUpTypes[i].weight;
+ if (randomWeight < cumulativeWeight) {
+ selectedPowerUpType = powerUpTypes[i].type;
+ break;
+ }
+ }
+ // Check if Coot already has a shield or Phoenix feather
+ if (selectedPowerUpType === 'Shield' && coot.isShielded || selectedPowerUpType === 'PhoenixFeather' && coot.hasPhoenixFeather) {
+ // Skip spawning this power-up
+ return;
+ }
+ var newPowerup = new PowerUp(selectedPowerUpType);
+ newPowerup.x = 2048 + newPowerup.width / 2; // Start off-screen to the right
+ newPowerup.y = Math.random() * (2732 * 0.45) + 2732 * 0.35; // Random Y position between 35% and 80% of the screen height
+ game.addChild(newPowerup);
+ }
};
-// Handle keyboard input
-var keys = {};
-game.on('keydown', function (event) {
- keys[event.code] = true;
-});
-game.on('keyup', function (event) {
- keys[event.code] = false;
-});
\ No newline at end of file
+// Handle touch events for jumping and diving
+game.down = function (x, y, obj) {
+ dragStartY = y; // Record the initial y position when touch starts
+ dragStartX = x; // Record the initial x position when touch starts
+};
+game.move = function (x, y, obj) {
+ if (!isTitleScreen && dragStartY !== null && dragStartX !== null) {
+ if (x - dragStartX > 50) {
+ // Only allow dash during these states if PowerDash is active
+ if (coot.isJumping || coot.isFalling || coot.isDiving || coot.isReturning || coot.returnDelay > 0) {
+ // Check for PowerDash before allowing
+ if (coot.isPowerDashActive) {
+ coot.isDashing = true;
+ }
+ } else {
+ // Normal dash on ground, no PowerDash needed
+ coot.isDashing = true;
+ }
+ dragStartX = null; // Reset dragStartX to prevent repeated dashes
+ }
+ if (y - dragStartY > 50 && coot && coot.originalY !== undefined && coot.y !== undefined && coot.y === coot.originalY) {
+ // Check if the drag is downward and significant
+ coot.dive();
+ dragStartY = null; // Reset dragStartY to prevent repeated dives
+ } else if (dragStartY - y > 50 && coot.y === coot.originalY) {
+ // Check if the drag is upward and significant
+ coot.jump();
+ dragStartY = null; // Reset dragStartY to prevent repeated jumps
+ }
+ }
+};
+game.up = function (x, y, obj) {
+ dragStartY = null; // Reset dragStartY when touch ends
+ dragStartX = null; // Reset dragStartX when touch ends
+};
\ No newline at end of file
shining moon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a single shining yellowish golden coin with the boat on it. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a colorful, cartoon style boat with an orange and blue color scheme. the boat has a small flag on top, round windows and a curved hull , with the BOAT text on it with bold letters. the design is vibrant, playful and optimized for a mobile game. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
white water bubble. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
single rock. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
gold sparkle. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
single gold sparkle. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
red shining heart symbol. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
whale head in octogonal box with green background asset. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
orange life rings asset that revive from water. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
single rounded white bubble firefly trail. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
shining sun cartoon style. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
flying owl with blue gold color mix asset. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
coin magnet white blue red in color. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
warning asset. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows