/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bubble = Container.expand(function () {
var self = Container.call(this);
var size = 20 + Math.random() * 40;
var bubbleGraphic = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size,
alpha: 0.6
});
self.speed = 1 + Math.random() * 2;
self.update = function () {
self.y -= self.speed;
// Add slight horizontal drift
self.x += Math.sin(LK.ticks / 20 + self.y / 100) * 0.5;
// Remove when offscreen
if (self.y < -50) {
self.destroy();
}
};
return self;
});
var Coral = Container.expand(function () {
var self = Container.call(this);
var coralGraphic = self.attachAsset('coral', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Coral does not move, so no update logic is needed
};
return self;
});
var Fish = Container.expand(function (type, size, speed, color) {
var self = Container.call(this);
self.type = type || 'player';
self.fishSize = size || 1;
self.speed = speed || 3;
self.fishColor = color || 0x3498db;
self.direction = 1; // 1 = right, -1 = left
// Create fish body
var fishBody = self.attachAsset(type + 'Fish', {
anchorX: 0.5,
anchorY: 0.5
});
// Add scales to fish body
var scaleCount = Math.floor(self.fishSize * 5);
for (var s = 0; s < scaleCount; s++) {
var scale = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: 5,
height: 5,
tint: 0xFFFFFF
});
scale.x = (Math.random() - 0.5) * fishBody.width * 0.8;
scale.y = (Math.random() - 0.5) * fishBody.height * 0.8;
self.addChild(scale);
}
// Create eye
var eyeSize = self.type === 'large' ? self.fishSize * 5 : self.fishSize * 10;
var eye = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: eyeSize,
height: eyeSize,
tint: 0xffffff
});
eye.x = type === 'player' ? 30 : fishBody.width * 0.3;
eye.y = type === 'player' ? -10 : -fishBody.height * 0.1;
self.addChild(eye);
// Create pupil
var pupil = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: eyeSize * 0.5,
height: eyeSize * 0.5,
tint: 0x000000
});
pupil.x = eye.x + 2;
pupil.y = eye.y;
self.addChild(pupil);
// Create tail
var tail = LK.getAsset('foodParticle', {
anchorX: 0.5,
anchorY: 0.5,
width: fishBody.width * 0.4,
height: fishBody.height * 0.6,
tint: self.fishColor - 0x202020 // Darker shade of the fish color
});
tail.x = type === 'player' ? -40 : -fishBody.width * 0.4;
self.addChild(tail);
// Set fish properties
self.width = fishBody.width;
self.height = fishBody.height;
self.originalWidth = fishBody.width;
self.originalHeight = fishBody.height;
// Movement AI for non-player fish
self.updateMovement = function () {
if (self.type !== 'player') {
// Random direction change
if (self.type !== 'small' && Math.random() < 0.005) {
self.direction = -self.direction;
self.scale.x = -self.direction;
}
// Random vertical movement
if (Math.random() < 0.05) {
self.verticalDirection = Math.random() > 0.5 ? 1 : -1;
}
// Move horizontally
self.x += self.speed * self.direction;
// Move vertically if direction is set
if (self.verticalDirection) {
self.y += self.verticalDirection * (self.speed * 0.5);
// Stop vertical movement randomly
if (Math.random() < 0.1) {
self.verticalDirection = 0;
}
}
// Wrap around screen
if (self.x < -100) {
self.x = 2148;
}
if (self.x > 2148) {
self.x = -100;
}
// Bounce off top and bottom
if (self.y < 100) {
self.y = 100;
self.verticalDirection = 1;
}
if (self.y > 2632) {
self.y = 2632;
self.verticalDirection = -1;
}
}
};
// Fish can eat other fish that are smaller than them
self.canEat = function (otherFish) {
return self.fishSize > otherFish.fishSize * 1.2;
};
// Grow fish size
self.grow = function (amount) {
self.fishSize += amount;
var newScale = 0.5 + self.fishSize * 0.5;
tween(self.scale, {
x: self.direction * newScale,
y: newScale
}, {
duration: 300,
easing: tween.elasticOut
});
if (self.type === 'player') {
LK.getSound('grow').play();
}
};
// Check if this fish is visible on screen
self.isOnScreen = function () {
return self.x >= -100 && self.x <= 2148 && self.y >= -100 && self.y <= 2832;
};
// Update method called every frame
self.update = function () {
self.updateMovement();
if (LK.ticks % 360 === 0) {
// Create a bubble every 360 frames (10 bubbles per minute at 60 FPS)
var bubble = new Bubble();
bubble.x = self.x + (self.direction === 1 ? fishBody.width / 2 : -fishBody.width / 2);
bubble.y = self.y;
game.addChild(bubble);
bubbles.push(bubble);
}
};
// Create size text
var sizeText = new Text2(self.fishSize.toFixed(0), {
// Display size as an integer
size: 50,
// Increase font size
fill: 0xFFFFFF
});
sizeText.anchor.set(0.5, 1);
sizeText.y = -fishBody.height / 2 - 10;
self.addChild(sizeText);
// Update size text when fish grows
self.grow = function (amount) {
self.fishSize += amount;
var newScale = 1 + (self.fishSize - 1) * 0.2;
tween(self.scale, {
x: self.direction * newScale,
y: newScale
}, {
duration: 300,
easing: tween.elasticOut
});
sizeText.setText(self.fishSize.toFixed(1)); // Update size text with one decimal place
sizeText.scale.set(newScale); // Adjust text size based on fish size
if (self.type === 'player') {
LK.getSound('grow').play();
// Display 'Nice' or 'Cool' text randomly
var growText = Math.random() > 0.5 ? 'Nice' : 'Cool';
var growTextDisplay = new Text2(growText, {
size: 100,
fill: 0xFFFFFF
});
growTextDisplay.anchor.set(1, 0); // Set anchor to top-right corner
growTextDisplay.x = self.width / 2; // Position at the top-right corner of the fish
growTextDisplay.y = -self.height / 2;
self.addChild(growTextDisplay);
tween(growTextDisplay, {
alpha: 0,
y: growTextDisplay.y - 50
}, {
duration: 1000,
onComplete: function onComplete() {
growTextDisplay.destroy();
}
});
// Change color based on size
if (self.fishSize < 2) {
self.fishColor = 0x3498db; // Blue
} else if (self.fishSize < 3) {
self.fishColor = 0xe74c3c; // Red
} else {
self.fishColor = 0x9b59b6; // Purple
}
fishBody.tint = self.fishColor;
tail.tint = self.fishColor;
}
};
return self;
});
var FoodParticle = Container.expand(function () {
var self = Container.call(this);
var foodGraphic = self.attachAsset('foodParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 0.1;
self.speed = 0.5 + Math.random() * 1;
// Slowly sink
self.update = function () {
self.y += self.speed;
// Add slight horizontal drift
self.x += Math.sin(LK.ticks / 10 + self.y / 100) * 0.3;
// Remove when offscreen
if (self.y > 2800) {
self.destroy();
}
};
return self;
});
var Powerup = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'speed';
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Different colors for different power-ups
if (self.type === 'speed') {
powerupGraphic.tint = 0xe67e22; // Orange
} else if (self.type === 'invincibility') {
powerupGraphic.tint = 0xe74c3c; // Red
} else if (self.type === 'magnet') {
powerupGraphic.tint = 0x9b59b6; // Purple
}
// Floating animation
self.update = function () {
self.y += Math.sin(LK.ticks / 10) * 0.5;
// Slowly sink
if (LK.ticks % 3 === 0) {
self.y += 0.5;
}
// Remove when offscreen
if (self.y > 2800) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4682B4 // Steel blue color
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var bubbles = [];
var foodParticles = [];
var powerups = [];
var score = 0;
var highScore = storage.highScore || 0;
var playerIsInvincible = false;
var hasMagnet = false;
var isGameActive = true;
// Game difficulty settings
var difficulty = 1;
var maxEnemies = 15;
var enemySpawnRate = 120; // frames between enemy spawns
var foodSpawnRate = 60; // frames between food spawns
var powerupSpawnRate = 600; // frames between powerup spawns
// Track if player is being dragged
var isDragging = false;
// Setup UI elements
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.top.addChild(scoreText);
scoreText.x = 150;
scoreText.y = 50;
var highScoreText = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFFFFF
});
highScoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -50;
highScoreText.y = 120;
var sizeText = new Text2('Size: 1.0', {
size: 60,
fill: 0xFFFFFF
});
sizeText.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(sizeText);
sizeText.x = 50;
sizeText.y = -50;
var statusText = new Text2('', {
size: 45,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
statusText.y = 120;
// Initialize player fish
function initializeGame() {
// Add coral objects to the game
for (var i = 0; i < 5; i++) {
var coral = new Coral();
coral.x = 200 + i * 700; // Further increased spacing between corals
coral.y = 2500;
game.addChild(coral);
}
// Add seaweed and rocks to the game
for (var j = 0; j < 3; j++) {
var seaweed = new Coral();
seaweed.x = 400 + j * 600;
seaweed.y = 2600;
game.addChild(seaweed);
}
for (var k = 0; k < 3; k++) {
var rock = new Coral();
rock.x = 600 + k * 800;
rock.y = 2700;
game.addChild(rock);
}
// Reset game state
player = new Fish('player', 1, 3, 0x3498db); // Reduced speed from 5 to 3 for heavier movement
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Reset game state
enemies = [];
bubbles = [];
foodParticles = [];
powerups = [];
score = 0;
playerIsInvincible = false;
hasMagnet = false;
isGameActive = true;
difficulty = 1;
// Update UI
scoreText.setText('Score: 0');
sizeText.setText('Size: 1.0');
statusText.setText('');
// Start game music
LK.playMusic('oceanTheme');
}
// Initialize the game
initializeGame();
// Function to spawn bubbles
function spawnBubble() {
if (Math.random() < 0.02) {
var bubble = new Bubble();
bubble.x = Math.random() * 2048;
bubble.y = 2732 + 50;
game.addChild(bubble);
bubbles.push(bubble);
}
}
// Function to spawn food particles
function spawnFood() {
if (LK.ticks % foodSpawnRate === 0) {
var food = new FoodParticle();
food.x = Math.random() * 2048;
food.y = -50;
game.addChild(food);
foodParticles.push(food);
}
}
// Function to spawn power-ups
function spawnPowerup() {
if (LK.ticks % powerupSpawnRate === 0 && Math.random() < 0.3) {
var types = ['speed', 'invincibility', 'magnet'];
var type = types[Math.floor(Math.random() * types.length)];
var powerup = new Powerup(type);
powerup.x = 100 + Math.random() * (2048 - 200);
powerup.y = -50;
game.addChild(powerup);
powerups.push(powerup);
}
}
// Function to spawn enemy fish
function spawnEnemy() {
if (LK.ticks % enemySpawnRate === 0 && enemies.length < maxEnemies) {
// Decide fish size relative to player
var sizeFactor;
var rnd = Math.random();
if (rnd < 0.6) {
// 60% chance for smaller fish
sizeFactor = 0.5 + Math.random() * 0.4;
} else if (rnd < 0.85) {
// 25% chance for similar sized fish
sizeFactor = 0.9 + Math.random() * 0.2;
} else {
// 15% chance for larger fish
sizeFactor = 1.2 + Math.random() * (difficulty * 0.5);
}
var fishSize = player.fishSize * sizeFactor;
// Determine fish type based on size
var fishType;
if (fishSize < 1) {
fishType = 'small';
} else if (fishSize < 2) {
fishType = 'medium';
} else {
fishType = 'large';
}
// Create the enemy
var enemy = new Fish(fishType, fishSize, 1 + Math.random() * 3);
// Position on either left or right side of screen
var fromLeft = Math.random() > 0.5;
enemy.x = fromLeft ? -100 : 2148;
enemy.y = 200 + Math.random() * (2732 - 400);
enemy.direction = fromLeft ? 1 : -1;
enemy.scale.x = enemy.direction;
// Add to game
game.addChild(enemy);
enemies.push(enemy);
}
}
// Function to check collisions between player and other entities
function checkCollisions() {
if (!isGameActive) {
return;
}
// Check collisions with enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// If enemy is off-screen for too long, remove it
if (!enemy.isOnScreen() && (enemy.x < -200 || enemy.x > 2248)) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (player.intersects(enemy)) {
if (player.canEat(enemy) || playerIsInvincible) {
// Player eats enemy
var growAmount = enemy.fishSize * 0.1;
player.grow(growAmount);
// Update score
score += Math.floor(enemy.fishSize * 10) + Math.floor(enemy.fishSize);
scoreText.setText('Score: ' + score);
sizeText.setText('Size: ' + player.fishSize.toFixed(1));
// Display 'Kill' text
statusText.setText('Kill');
LK.setTimeout(function () {
statusText.setText('');
}, 1000);
// Check for high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreText.setText('High Score: ' + highScore);
}
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Play eat sound
LK.getSound('eat').play();
// Increase difficulty
if (score > difficulty * 100) {
difficulty++;
enemySpawnRate = Math.max(40, 120 - difficulty * 5);
foodSpawnRate = Math.max(30, 60 - difficulty * 2);
}
} else if (!playerIsInvincible && enemy.fishColor !== 0x2ecc71 && enemy.type !== 'small') {
// Player gets eaten
LK.effects.flashScreen(0xff0000, 1000);
statusText.setText('Kill');
isGameActive = false;
LK.showGameOver(); // End the game and show game over screen
}
}
}
// Check collisions with food particles
for (var j = foodParticles.length - 1; j >= 0; j--) {
var food = foodParticles[j];
// If food is magnet-attracted
if (hasMagnet) {
var dx = player.x - food.x;
var dy = player.y - food.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
var factor = 0.05;
food.x += dx * factor;
food.y += dy * factor;
}
}
// Check collision
if (player.intersects(food)) {
// Player eats food
player.grow(food.value);
score += 1;
scoreText.setText('Score: ' + score);
sizeText.setText('Size: ' + player.fishSize.toFixed(1));
// Check for high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreText.setText('High Score: ' + highScore);
}
// Remove food
food.destroy();
foodParticles.splice(j, 1);
}
}
// Check collisions with powerups
for (var k = powerups.length - 1; k >= 0; k--) {
var powerup = powerups[k];
if (player.intersects(powerup)) {
// Apply powerup effect
if (powerup.type === 'speed') {
// Speed boost
player.speed = 10;
statusText.setText('Speed Boost!');
LK.setTimeout(function () {
player.speed = 5;
statusText.setText('');
}, 5000);
} else if (powerup.type === 'invincibility') {
// Invincibility
playerIsInvincible = true;
statusText.setText('Invincible!');
player.alpha = 0.7;
LK.setTimeout(function () {
playerIsInvincible = false;
statusText.setText('');
player.alpha = 1;
}, 7000);
} else if (powerup.type === 'magnet') {
// Food magnet
hasMagnet = true;
statusText.setText('Food Magnet!');
LK.setTimeout(function () {
hasMagnet = false;
statusText.setText('');
}, 10000);
}
// Remove powerup
powerup.destroy();
powerups.splice(k, 1);
}
}
}
// Update game state
game.update = function () {
if (!isGameActive) {
return;
}
// Spawn entities
spawnBubble();
spawnFood();
spawnEnemy();
spawnPowerup();
// Update entities that don't have auto-update
for (var i = 0; i < bubbles.length; i++) {
if (bubbles[i] && typeof bubbles[i].update === 'function') {
bubbles[i].update();
}
}
for (var j = 0; j < foodParticles.length; j++) {
if (foodParticles[j] && typeof foodParticles[j].update === 'function') {
foodParticles[j].update();
}
}
for (var k = 0; k < powerups.length; k++) {
if (powerups[k] && typeof powerups[k].update === 'function') {
powerups[k].update();
}
}
// Check collisions
checkCollisions();
// Update player direction based on movement
if (isDragging && player.lastX) {
if (player.x > player.lastX + 5) {
player.direction = 1;
player.scale.x = player.direction * (1 + (player.fishSize - 1) * 0.2);
} else if (player.x < player.lastX - 5) {
player.direction = -1;
player.scale.x = player.direction * (1 + (player.fishSize - 1) * 0.2);
}
}
// Store player's last position
player.lastX = player.x;
player.lastY = player.y;
};
// Handle touch/mouse input for player movement
game.down = function (x, y) {
isDragging = true;
player.x = x;
player.y = y;
};
game.move = function (x, y) {
if (isDragging) {
player.x = x;
player.y = y;
}
};
game.up = function () {
isDragging = false;
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bubble = Container.expand(function () {
var self = Container.call(this);
var size = 20 + Math.random() * 40;
var bubbleGraphic = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size,
alpha: 0.6
});
self.speed = 1 + Math.random() * 2;
self.update = function () {
self.y -= self.speed;
// Add slight horizontal drift
self.x += Math.sin(LK.ticks / 20 + self.y / 100) * 0.5;
// Remove when offscreen
if (self.y < -50) {
self.destroy();
}
};
return self;
});
var Coral = Container.expand(function () {
var self = Container.call(this);
var coralGraphic = self.attachAsset('coral', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Coral does not move, so no update logic is needed
};
return self;
});
var Fish = Container.expand(function (type, size, speed, color) {
var self = Container.call(this);
self.type = type || 'player';
self.fishSize = size || 1;
self.speed = speed || 3;
self.fishColor = color || 0x3498db;
self.direction = 1; // 1 = right, -1 = left
// Create fish body
var fishBody = self.attachAsset(type + 'Fish', {
anchorX: 0.5,
anchorY: 0.5
});
// Add scales to fish body
var scaleCount = Math.floor(self.fishSize * 5);
for (var s = 0; s < scaleCount; s++) {
var scale = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: 5,
height: 5,
tint: 0xFFFFFF
});
scale.x = (Math.random() - 0.5) * fishBody.width * 0.8;
scale.y = (Math.random() - 0.5) * fishBody.height * 0.8;
self.addChild(scale);
}
// Create eye
var eyeSize = self.type === 'large' ? self.fishSize * 5 : self.fishSize * 10;
var eye = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: eyeSize,
height: eyeSize,
tint: 0xffffff
});
eye.x = type === 'player' ? 30 : fishBody.width * 0.3;
eye.y = type === 'player' ? -10 : -fishBody.height * 0.1;
self.addChild(eye);
// Create pupil
var pupil = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
width: eyeSize * 0.5,
height: eyeSize * 0.5,
tint: 0x000000
});
pupil.x = eye.x + 2;
pupil.y = eye.y;
self.addChild(pupil);
// Create tail
var tail = LK.getAsset('foodParticle', {
anchorX: 0.5,
anchorY: 0.5,
width: fishBody.width * 0.4,
height: fishBody.height * 0.6,
tint: self.fishColor - 0x202020 // Darker shade of the fish color
});
tail.x = type === 'player' ? -40 : -fishBody.width * 0.4;
self.addChild(tail);
// Set fish properties
self.width = fishBody.width;
self.height = fishBody.height;
self.originalWidth = fishBody.width;
self.originalHeight = fishBody.height;
// Movement AI for non-player fish
self.updateMovement = function () {
if (self.type !== 'player') {
// Random direction change
if (self.type !== 'small' && Math.random() < 0.005) {
self.direction = -self.direction;
self.scale.x = -self.direction;
}
// Random vertical movement
if (Math.random() < 0.05) {
self.verticalDirection = Math.random() > 0.5 ? 1 : -1;
}
// Move horizontally
self.x += self.speed * self.direction;
// Move vertically if direction is set
if (self.verticalDirection) {
self.y += self.verticalDirection * (self.speed * 0.5);
// Stop vertical movement randomly
if (Math.random() < 0.1) {
self.verticalDirection = 0;
}
}
// Wrap around screen
if (self.x < -100) {
self.x = 2148;
}
if (self.x > 2148) {
self.x = -100;
}
// Bounce off top and bottom
if (self.y < 100) {
self.y = 100;
self.verticalDirection = 1;
}
if (self.y > 2632) {
self.y = 2632;
self.verticalDirection = -1;
}
}
};
// Fish can eat other fish that are smaller than them
self.canEat = function (otherFish) {
return self.fishSize > otherFish.fishSize * 1.2;
};
// Grow fish size
self.grow = function (amount) {
self.fishSize += amount;
var newScale = 0.5 + self.fishSize * 0.5;
tween(self.scale, {
x: self.direction * newScale,
y: newScale
}, {
duration: 300,
easing: tween.elasticOut
});
if (self.type === 'player') {
LK.getSound('grow').play();
}
};
// Check if this fish is visible on screen
self.isOnScreen = function () {
return self.x >= -100 && self.x <= 2148 && self.y >= -100 && self.y <= 2832;
};
// Update method called every frame
self.update = function () {
self.updateMovement();
if (LK.ticks % 360 === 0) {
// Create a bubble every 360 frames (10 bubbles per minute at 60 FPS)
var bubble = new Bubble();
bubble.x = self.x + (self.direction === 1 ? fishBody.width / 2 : -fishBody.width / 2);
bubble.y = self.y;
game.addChild(bubble);
bubbles.push(bubble);
}
};
// Create size text
var sizeText = new Text2(self.fishSize.toFixed(0), {
// Display size as an integer
size: 50,
// Increase font size
fill: 0xFFFFFF
});
sizeText.anchor.set(0.5, 1);
sizeText.y = -fishBody.height / 2 - 10;
self.addChild(sizeText);
// Update size text when fish grows
self.grow = function (amount) {
self.fishSize += amount;
var newScale = 1 + (self.fishSize - 1) * 0.2;
tween(self.scale, {
x: self.direction * newScale,
y: newScale
}, {
duration: 300,
easing: tween.elasticOut
});
sizeText.setText(self.fishSize.toFixed(1)); // Update size text with one decimal place
sizeText.scale.set(newScale); // Adjust text size based on fish size
if (self.type === 'player') {
LK.getSound('grow').play();
// Display 'Nice' or 'Cool' text randomly
var growText = Math.random() > 0.5 ? 'Nice' : 'Cool';
var growTextDisplay = new Text2(growText, {
size: 100,
fill: 0xFFFFFF
});
growTextDisplay.anchor.set(1, 0); // Set anchor to top-right corner
growTextDisplay.x = self.width / 2; // Position at the top-right corner of the fish
growTextDisplay.y = -self.height / 2;
self.addChild(growTextDisplay);
tween(growTextDisplay, {
alpha: 0,
y: growTextDisplay.y - 50
}, {
duration: 1000,
onComplete: function onComplete() {
growTextDisplay.destroy();
}
});
// Change color based on size
if (self.fishSize < 2) {
self.fishColor = 0x3498db; // Blue
} else if (self.fishSize < 3) {
self.fishColor = 0xe74c3c; // Red
} else {
self.fishColor = 0x9b59b6; // Purple
}
fishBody.tint = self.fishColor;
tail.tint = self.fishColor;
}
};
return self;
});
var FoodParticle = Container.expand(function () {
var self = Container.call(this);
var foodGraphic = self.attachAsset('foodParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 0.1;
self.speed = 0.5 + Math.random() * 1;
// Slowly sink
self.update = function () {
self.y += self.speed;
// Add slight horizontal drift
self.x += Math.sin(LK.ticks / 10 + self.y / 100) * 0.3;
// Remove when offscreen
if (self.y > 2800) {
self.destroy();
}
};
return self;
});
var Powerup = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'speed';
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Different colors for different power-ups
if (self.type === 'speed') {
powerupGraphic.tint = 0xe67e22; // Orange
} else if (self.type === 'invincibility') {
powerupGraphic.tint = 0xe74c3c; // Red
} else if (self.type === 'magnet') {
powerupGraphic.tint = 0x9b59b6; // Purple
}
// Floating animation
self.update = function () {
self.y += Math.sin(LK.ticks / 10) * 0.5;
// Slowly sink
if (LK.ticks % 3 === 0) {
self.y += 0.5;
}
// Remove when offscreen
if (self.y > 2800) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4682B4 // Steel blue color
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var bubbles = [];
var foodParticles = [];
var powerups = [];
var score = 0;
var highScore = storage.highScore || 0;
var playerIsInvincible = false;
var hasMagnet = false;
var isGameActive = true;
// Game difficulty settings
var difficulty = 1;
var maxEnemies = 15;
var enemySpawnRate = 120; // frames between enemy spawns
var foodSpawnRate = 60; // frames between food spawns
var powerupSpawnRate = 600; // frames between powerup spawns
// Track if player is being dragged
var isDragging = false;
// Setup UI elements
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.top.addChild(scoreText);
scoreText.x = 150;
scoreText.y = 50;
var highScoreText = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFFFFF
});
highScoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -50;
highScoreText.y = 120;
var sizeText = new Text2('Size: 1.0', {
size: 60,
fill: 0xFFFFFF
});
sizeText.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(sizeText);
sizeText.x = 50;
sizeText.y = -50;
var statusText = new Text2('', {
size: 45,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
statusText.y = 120;
// Initialize player fish
function initializeGame() {
// Add coral objects to the game
for (var i = 0; i < 5; i++) {
var coral = new Coral();
coral.x = 200 + i * 700; // Further increased spacing between corals
coral.y = 2500;
game.addChild(coral);
}
// Add seaweed and rocks to the game
for (var j = 0; j < 3; j++) {
var seaweed = new Coral();
seaweed.x = 400 + j * 600;
seaweed.y = 2600;
game.addChild(seaweed);
}
for (var k = 0; k < 3; k++) {
var rock = new Coral();
rock.x = 600 + k * 800;
rock.y = 2700;
game.addChild(rock);
}
// Reset game state
player = new Fish('player', 1, 3, 0x3498db); // Reduced speed from 5 to 3 for heavier movement
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Reset game state
enemies = [];
bubbles = [];
foodParticles = [];
powerups = [];
score = 0;
playerIsInvincible = false;
hasMagnet = false;
isGameActive = true;
difficulty = 1;
// Update UI
scoreText.setText('Score: 0');
sizeText.setText('Size: 1.0');
statusText.setText('');
// Start game music
LK.playMusic('oceanTheme');
}
// Initialize the game
initializeGame();
// Function to spawn bubbles
function spawnBubble() {
if (Math.random() < 0.02) {
var bubble = new Bubble();
bubble.x = Math.random() * 2048;
bubble.y = 2732 + 50;
game.addChild(bubble);
bubbles.push(bubble);
}
}
// Function to spawn food particles
function spawnFood() {
if (LK.ticks % foodSpawnRate === 0) {
var food = new FoodParticle();
food.x = Math.random() * 2048;
food.y = -50;
game.addChild(food);
foodParticles.push(food);
}
}
// Function to spawn power-ups
function spawnPowerup() {
if (LK.ticks % powerupSpawnRate === 0 && Math.random() < 0.3) {
var types = ['speed', 'invincibility', 'magnet'];
var type = types[Math.floor(Math.random() * types.length)];
var powerup = new Powerup(type);
powerup.x = 100 + Math.random() * (2048 - 200);
powerup.y = -50;
game.addChild(powerup);
powerups.push(powerup);
}
}
// Function to spawn enemy fish
function spawnEnemy() {
if (LK.ticks % enemySpawnRate === 0 && enemies.length < maxEnemies) {
// Decide fish size relative to player
var sizeFactor;
var rnd = Math.random();
if (rnd < 0.6) {
// 60% chance for smaller fish
sizeFactor = 0.5 + Math.random() * 0.4;
} else if (rnd < 0.85) {
// 25% chance for similar sized fish
sizeFactor = 0.9 + Math.random() * 0.2;
} else {
// 15% chance for larger fish
sizeFactor = 1.2 + Math.random() * (difficulty * 0.5);
}
var fishSize = player.fishSize * sizeFactor;
// Determine fish type based on size
var fishType;
if (fishSize < 1) {
fishType = 'small';
} else if (fishSize < 2) {
fishType = 'medium';
} else {
fishType = 'large';
}
// Create the enemy
var enemy = new Fish(fishType, fishSize, 1 + Math.random() * 3);
// Position on either left or right side of screen
var fromLeft = Math.random() > 0.5;
enemy.x = fromLeft ? -100 : 2148;
enemy.y = 200 + Math.random() * (2732 - 400);
enemy.direction = fromLeft ? 1 : -1;
enemy.scale.x = enemy.direction;
// Add to game
game.addChild(enemy);
enemies.push(enemy);
}
}
// Function to check collisions between player and other entities
function checkCollisions() {
if (!isGameActive) {
return;
}
// Check collisions with enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// If enemy is off-screen for too long, remove it
if (!enemy.isOnScreen() && (enemy.x < -200 || enemy.x > 2248)) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (player.intersects(enemy)) {
if (player.canEat(enemy) || playerIsInvincible) {
// Player eats enemy
var growAmount = enemy.fishSize * 0.1;
player.grow(growAmount);
// Update score
score += Math.floor(enemy.fishSize * 10) + Math.floor(enemy.fishSize);
scoreText.setText('Score: ' + score);
sizeText.setText('Size: ' + player.fishSize.toFixed(1));
// Display 'Kill' text
statusText.setText('Kill');
LK.setTimeout(function () {
statusText.setText('');
}, 1000);
// Check for high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreText.setText('High Score: ' + highScore);
}
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Play eat sound
LK.getSound('eat').play();
// Increase difficulty
if (score > difficulty * 100) {
difficulty++;
enemySpawnRate = Math.max(40, 120 - difficulty * 5);
foodSpawnRate = Math.max(30, 60 - difficulty * 2);
}
} else if (!playerIsInvincible && enemy.fishColor !== 0x2ecc71 && enemy.type !== 'small') {
// Player gets eaten
LK.effects.flashScreen(0xff0000, 1000);
statusText.setText('Kill');
isGameActive = false;
LK.showGameOver(); // End the game and show game over screen
}
}
}
// Check collisions with food particles
for (var j = foodParticles.length - 1; j >= 0; j--) {
var food = foodParticles[j];
// If food is magnet-attracted
if (hasMagnet) {
var dx = player.x - food.x;
var dy = player.y - food.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
var factor = 0.05;
food.x += dx * factor;
food.y += dy * factor;
}
}
// Check collision
if (player.intersects(food)) {
// Player eats food
player.grow(food.value);
score += 1;
scoreText.setText('Score: ' + score);
sizeText.setText('Size: ' + player.fishSize.toFixed(1));
// Check for high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreText.setText('High Score: ' + highScore);
}
// Remove food
food.destroy();
foodParticles.splice(j, 1);
}
}
// Check collisions with powerups
for (var k = powerups.length - 1; k >= 0; k--) {
var powerup = powerups[k];
if (player.intersects(powerup)) {
// Apply powerup effect
if (powerup.type === 'speed') {
// Speed boost
player.speed = 10;
statusText.setText('Speed Boost!');
LK.setTimeout(function () {
player.speed = 5;
statusText.setText('');
}, 5000);
} else if (powerup.type === 'invincibility') {
// Invincibility
playerIsInvincible = true;
statusText.setText('Invincible!');
player.alpha = 0.7;
LK.setTimeout(function () {
playerIsInvincible = false;
statusText.setText('');
player.alpha = 1;
}, 7000);
} else if (powerup.type === 'magnet') {
// Food magnet
hasMagnet = true;
statusText.setText('Food Magnet!');
LK.setTimeout(function () {
hasMagnet = false;
statusText.setText('');
}, 10000);
}
// Remove powerup
powerup.destroy();
powerups.splice(k, 1);
}
}
}
// Update game state
game.update = function () {
if (!isGameActive) {
return;
}
// Spawn entities
spawnBubble();
spawnFood();
spawnEnemy();
spawnPowerup();
// Update entities that don't have auto-update
for (var i = 0; i < bubbles.length; i++) {
if (bubbles[i] && typeof bubbles[i].update === 'function') {
bubbles[i].update();
}
}
for (var j = 0; j < foodParticles.length; j++) {
if (foodParticles[j] && typeof foodParticles[j].update === 'function') {
foodParticles[j].update();
}
}
for (var k = 0; k < powerups.length; k++) {
if (powerups[k] && typeof powerups[k].update === 'function') {
powerups[k].update();
}
}
// Check collisions
checkCollisions();
// Update player direction based on movement
if (isDragging && player.lastX) {
if (player.x > player.lastX + 5) {
player.direction = 1;
player.scale.x = player.direction * (1 + (player.fishSize - 1) * 0.2);
} else if (player.x < player.lastX - 5) {
player.direction = -1;
player.scale.x = player.direction * (1 + (player.fishSize - 1) * 0.2);
}
}
// Store player's last position
player.lastX = player.x;
player.lastY = player.y;
};
// Handle touch/mouse input for player movement
game.down = function (x, y) {
isDragging = true;
player.x = x;
player.y = y;
};
game.move = function (x, y) {
if (isDragging) {
player.x = x;
player.y = y;
}
};
game.up = function () {
isDragging = false;
};