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;
tween(self, {
x: self.originalX
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
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 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 Rock,\nDive away from the Owl,\nDash away from the Fish.\n100 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 === '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 === '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', 'Fish', 'Owl'];
var obstacleSpawnChances = {
Duck: 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 = {
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 (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
@@ -1092,9 +1092,9 @@
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 Rock,\nDive away from the Owl,\nDash away from the Fish.\n100 Coot Coins = 1 heart.', {
+ var instructionDetails = new Text2('Jump over the Rock,\nDive away from the Owl,\nDash away from the Fish.\n100 Coins = 1 heart.', {
size: 70,
fill: 0xFFFFFF,
align: "center"
});
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