/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BigFish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('largeFish', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1.5 - Math.random() * 0.8;
self.damage = 20;
self.waveAmplitude = Math.random() * 80 + 40;
self.waveFrequency = Math.random() * 0.04 + 0.02;
self.waveOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.movePattern = Math.random() < 0.8 ? 'straight' : 'wave';
self.update = function () {
self.x += self.speed;
if (self.movePattern === 'wave') {
self.y = self.startY + Math.sin(self.x * self.waveFrequency + self.waveOffset) * self.waveAmplitude;
}
};
return self;
});
var Coral = Container.expand(function (type) {
var self = Container.call(this);
var coralType = type || 'coral1';
var coralGraphics = self.attachAsset(coralType, {
anchorX: 0.5,
anchorY: 1.0
});
self.coralType = coralType;
self.pulseScale = 1.0;
self.pulseDirection = 1;
self.pulseSpeed = Math.random() * 0.005 + 0.002;
self.update = function () {
// Gentle pulsing motion
self.pulseScale += self.pulseDirection * self.pulseSpeed;
if (self.pulseScale > 1.1) {
self.pulseScale = 1.1;
self.pulseDirection = -1;
} else if (self.pulseScale < 0.9) {
self.pulseScale = 0.9;
self.pulseDirection = 1;
}
coralGraphics.scaleX = self.pulseScale;
coralGraphics.scaleY = self.pulseScale;
};
return self;
});
var Fish = Container.expand(function (type) {
var self = Container.call(this);
var fishType = type || 'small';
var fishGraphics = self.attachAsset(fishType + 'Fish', {
anchorX: 0.5,
anchorY: 0.5
});
self.fishType = fishType;
self.speed = -1 - Math.random() * 0.5;
self.points = fishType === 'small' ? 10 : fishType === 'medium' ? 25 : 50;
self.waveAmplitude = Math.random() * 100 + 50;
self.waveFrequency = Math.random() * 0.05 + 0.02;
self.waveOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.movePattern = Math.random() < 0.7 ? 'straight' : 'wave';
self.update = function () {
self.x += self.speed;
if (self.movePattern === 'wave') {
self.y = self.startY + Math.sin(self.x * self.waveFrequency + self.waveOffset) * self.waveAmplitude;
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -5;
self.animationDirection = 1;
self.baseY = self.y;
self.animationRange = 150;
self.update = function () {
self.x += self.speed;
};
return self;
});
var SeaweedPlant = Container.expand(function (type) {
var self = Container.call(this);
var plantType = type || 'seaweed1';
var plantGraphics = self.attachAsset(plantType, {
anchorX: 0.5,
anchorY: 1.0
});
self.plantType = plantType;
self.baseX = self.x;
self.swayAmount = Math.random() * 10 + 5;
self.swaySpeed = Math.random() * 0.02 + 0.01;
self.swayOffset = Math.random() * Math.PI * 2;
self.update = function () {
// Gentle swaying motion
self.x = self.baseX + Math.sin(LK.ticks * self.swaySpeed + self.swayOffset) * self.swayAmount;
};
return self;
});
var Shark = Container.expand(function () {
var self = Container.call(this);
var sharkGraphics = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetY = 2732 / 2;
self.targetX = 300;
self.speed = 3;
self.scaleX = 1.0;
self.scaleY = 1.0;
self.update = function () {
// Smooth movement towards target Y position
var diffY = self.targetY - self.y;
self.y += diffY * 0.05;
// Smooth movement towards target X position
var diffX = self.targetX - self.x;
self.x += diffX * 0.05;
// Keep shark within map boundaries
if (self.x < 75) self.x = 75;
if (self.x > 1973) self.x = 1973;
if (self.y < 75) self.y = 75;
if (self.y > 2657) self.y = 2657;
};
return self;
});
var Shell = Container.expand(function () {
var self = Container.call(this);
var shellGraphics = self.attachAsset('shell', {
anchorX: 0.5,
anchorY: 1.0
});
self.pulseScale = 1.0;
self.pulseDirection = 1;
self.pulseSpeed = Math.random() * 0.003 + 0.001;
self.update = function () {
// Very gentle pulsing motion for shells
self.pulseScale += self.pulseDirection * self.pulseSpeed;
if (self.pulseScale > 1.05) {
self.pulseScale = 1.05;
self.pulseDirection = -1;
} else if (self.pulseScale < 0.95) {
self.pulseScale = 0.95;
self.pulseDirection = 1;
}
shellGraphics.scaleX = self.pulseScale;
shellGraphics.scaleY = self.pulseScale;
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -0.8 - Math.random() * 0.4;
self.points = 150;
self.bobAmplitude = Math.random() * 8 + 5;
self.bobFrequency = Math.random() * 0.02 + 0.01;
self.bobOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.update = function () {
self.x += self.speed;
// Gentle bobbing motion on water surface
self.y = self.startY + Math.sin(self.x * self.bobFrequency + self.bobOffset) * self.bobAmplitude;
};
return self;
});
var Swimmer = Container.expand(function () {
var self = Container.call(this);
var swimmerGraphics = self.attachAsset('swimmer', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -0.5 - Math.random() * 0.3;
self.points = 100;
self.waveAmplitude = Math.random() * 20 + 10;
self.waveFrequency = Math.random() * 0.03 + 0.01;
self.waveOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.update = function () {
self.x += self.speed;
// Swimming motion with small waves
self.y = self.startY + Math.sin(self.x * self.waveFrequency + self.waveOffset) * self.waveAmplitude;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001a33
});
/****
* Game Code
****/
// Create beach at the top of the screen
var beach = LK.getAsset('beach', {
anchorX: 0,
anchorY: 0
});
beach.x = 0;
beach.y = 0;
beach.scaleX = 20.48; // Scale to cover full width (2048/100)
beach.scaleY = 1.5; // Make it taller for better visual
game.addChild(beach);
// Create ocean floor that spans the entire screen width
var oceanFloor = LK.getAsset('oceanFloor', {
anchorX: 0,
anchorY: 1.0
});
oceanFloor.x = 0;
oceanFloor.y = 2732;
oceanFloor.scaleX = 20.48; // Scale to cover full width (2048/100)
oceanFloor.scaleY = 2; // Make it taller for better visual
game.addChild(oceanFloor);
// Create background plants and corals
var plants = [];
var corals = [];
var shells = [];
// Add seaweed plants
for (var p = 0; p < 15; p++) {
var plantTypes = ['seaweed1', 'seaweed2', 'seaweed3'];
var plantType = plantTypes[Math.floor(Math.random() * plantTypes.length)];
var plant = new SeaweedPlant(plantType);
plant.x = Math.random() * 2048;
plant.y = 2732 - Math.random() * 50;
plant.baseX = plant.x;
plants.push(plant);
game.addChild(plant);
}
// Add coral decorations
for (var c = 0; c < 8; c++) {
var coralTypes = ['coral1', 'coral2'];
var coralType = coralTypes[Math.floor(Math.random() * coralTypes.length)];
var coral = new Coral(coralType);
coral.x = Math.random() * 2048;
coral.y = 2732 - Math.random() * 30;
corals.push(coral);
game.addChild(coral);
}
// Add shell decorations
for (var s = 0; s < 12; s++) {
var shell = new Shell();
shell.x = Math.random() * 2048;
shell.y = 2732 - Math.random() * 20;
shells.push(shell);
game.addChild(shell);
}
var shark = game.addChild(new Shark());
shark.x = 300;
shark.y = 2732 / 2;
var maxHealth = 100;
var currentHealth = 100;
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -20;
scoreTxt.y = 20;
// Create health bar background
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBarBg);
healthBarBg.x = 120;
healthBarBg.y = 20;
// Create health bar foreground
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBar);
healthBar.x = 120;
healthBar.y = 20;
// Create health text
var healthTxt = new Text2('Health: 100', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthTxt);
healthTxt.x = 120;
healthTxt.y = 50;
var fish = [];
var bigFish = [];
var obstacles = [];
var swimmers = [];
var ships = [];
var gameSpeed = 1;
var spawnTimer = 0;
var bigFishTimer = 0;
var obstacleTimer = 0;
var speedIncreaseTimer = 0;
var swimmerTimer = 0;
var shipTimer = 0;
// Mouse/finger tracking variables
var mouseY = 2732 / 2;
var mouseX = 300;
function takeDamage(amount) {
currentHealth -= amount;
if (currentHealth < 0) currentHealth = 0;
// Add damage points to score
var currentScore = LK.getScore();
var newScore = currentScore + amount;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
// Update health bar
var healthPercent = currentHealth / maxHealth;
healthBar.scaleX = healthPercent;
healthBar.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
healthTxt.setText('Health: ' + currentHealth);
// Flash screen red when taking damage
LK.effects.flashScreen(0xff0000, 300);
LK.getSound('damage').play();
// Check for game over
if (currentHealth <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
function spawnFish() {
var fishTypes = ['small', 'small', 'small', 'medium', 'medium', 'large'];
var type = fishTypes[Math.floor(Math.random() * fishTypes.length)];
var newFish = new Fish(type);
newFish.x = 2048 + 50;
newFish.y = Math.random() * (2732 - 200) + 100;
newFish.startY = newFish.y;
fish.push(newFish);
game.addChild(newFish);
}
function spawnBigFish() {
var newBigFish = new BigFish();
newBigFish.x = 2048 + 75;
newBigFish.y = Math.random() * (2732 - 200) + 100;
newBigFish.startY = newBigFish.y;
bigFish.push(newBigFish);
game.addChild(newBigFish);
}
function spawnSwimmer() {
var newSwimmer = new Swimmer();
newSwimmer.x = 2048 + 50;
newSwimmer.y = Math.random() * 150 + 100; // Stay near the beach/surface
newSwimmer.startY = newSwimmer.y;
swimmers.push(newSwimmer);
game.addChild(newSwimmer);
}
function spawnShip() {
var newShip = new Ship();
newShip.x = 2048 + 60;
newShip.y = Math.random() * 80 + 180; // Stay at water surface level
newShip.startY = newShip.y;
ships.push(newShip);
game.addChild(newShip);
}
function createBloodEffect(x, y) {
// Create multiple blood particles
for (var p = 0; p < 8; p++) {
var bloodParticle = LK.getAsset('bloodParticle', {
anchorX: 0.5,
anchorY: 0.5
});
bloodParticle.x = x + (Math.random() - 0.5) * 40;
bloodParticle.y = y + (Math.random() - 0.5) * 40;
game.addChild(bloodParticle);
// Animate blood particle with random direction and fade out
var targetX = bloodParticle.x + (Math.random() - 0.5) * 150;
var targetY = bloodParticle.y + (Math.random() - 0.5) * 150;
tween(bloodParticle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
bloodParticle.destroy();
}
});
}
}
function spawnObstacle() {
var newObstacle = new Obstacle();
newObstacle.x = 2048 + 50;
newObstacle.y = Math.random() * (2732 - 200) + 100;
newObstacle.baseY = newObstacle.y;
// Start up and down animation
function animateObstacle() {
var targetY = newObstacle.baseY + newObstacle.animationDirection * newObstacle.animationRange;
tween(newObstacle, {
y: targetY
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
newObstacle.animationDirection *= -1;
animateObstacle();
}
});
}
animateObstacle();
obstacles.push(newObstacle);
game.addChild(newObstacle);
}
game.down = function (x, y, obj) {
mouseY = Math.max(75, Math.min(y, 2657));
mouseX = Math.max(75, Math.min(x, 1973));
shark.targetY = mouseY;
shark.targetX = mouseX;
};
game.move = function (x, y, obj) {
mouseY = Math.max(75, Math.min(y, 2657));
mouseX = Math.max(75, Math.min(x, 1973));
shark.targetY = mouseY;
shark.targetX = mouseX;
};
game.update = function () {
spawnTimer++;
bigFishTimer++;
obstacleTimer++;
speedIncreaseTimer++;
swimmerTimer++;
shipTimer++;
// Spawn fish
if (spawnTimer >= Math.max(30 - Math.floor(gameSpeed), 15)) {
spawnFish();
spawnTimer = 0;
}
// Spawn big fish occasionally
if (bigFishTimer >= Math.max(450 - Math.floor(gameSpeed * 25), 250)) {
if (Math.random() < 0.6) {
spawnBigFish();
}
bigFishTimer = 0;
}
// Spawn swimmers occasionally
if (swimmerTimer >= Math.max(400 - Math.floor(gameSpeed * 20), 200)) {
if (Math.random() < 0.4) {
spawnSwimmer();
}
swimmerTimer = 0;
}
// Spawn ships occasionally
if (shipTimer >= Math.max(600 - Math.floor(gameSpeed * 30), 300)) {
if (Math.random() < 0.3) {
spawnShip();
}
shipTimer = 0;
}
// Spawn obstacles occasionally
if (obstacleTimer >= Math.max(200 - Math.floor(gameSpeed * 10), 100)) {
if (Math.random() < 0.3) {
spawnObstacle();
}
obstacleTimer = 0;
}
// Increase game speed over time
if (speedIncreaseTimer >= 300) {
gameSpeed += 0.1;
speedIncreaseTimer = 0;
}
// Update and check fish
for (var i = fish.length - 1; i >= 0; i--) {
var currentFish = fish[i];
// Initialize tracking variables
if (currentFish.lastX === undefined) currentFish.lastX = currentFish.x;
if (currentFish.lastIntersecting === undefined) currentFish.lastIntersecting = false;
// Check if fish went off screen
if (currentFish.lastX >= -100 && currentFish.x < -100) {
currentFish.destroy();
fish.splice(i, 1);
continue;
}
// Check collision with shark
var currentIntersecting = shark.intersects(currentFish);
if (!currentFish.lastIntersecting && currentIntersecting) {
var currentScore = LK.getScore();
var canEat = false;
// Check if shark can eat this fish type based on score
if (currentFish.fishType === 'small') {
canEat = true; // Can always eat small fish
} else if (currentFish.fishType === 'medium') {
canEat = currentScore >= 200; // Can eat medium fish after 200 points
} else if (currentFish.fishType === 'large') {
canEat = currentScore >= 500; // Can eat large fish after 500 points
}
if (canEat) {
// Fish eaten
var newScore = currentScore + currentFish.points;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
LK.getSound('eat').play();
// Scale shark based on score milestones
var newScale = 1.0;
if (newScore >= 500) {
newScale = 1.5;
} else if (newScore >= 200) {
newScale = 1.25;
}
// Animate shark scaling if it changed
if (shark.scaleX !== newScale) {
tween(shark, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 300,
easing: tween.easeOut
});
}
// Create blood effect at fish position
createBloodEffect(currentFish.x, currentFish.y);
// Flash effect
LK.effects.flashObject(currentFish, 0x00ff00, 200);
currentFish.destroy();
fish.splice(i, 1);
continue;
} else {
// Can't eat this fish - take damage and bounce back effect
if (currentFish.fishType === 'medium' && currentScore < 200) {
takeDamage(15); // Take damage from medium fish when score is under 200
} else if (currentFish.fishType === 'large' && currentScore < 500) {
takeDamage(25); // Take damage from large fish when score is under 500
}
LK.effects.flashObject(currentFish, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
}
}
// Update tracking variables
currentFish.lastX = currentFish.x;
currentFish.lastIntersecting = currentIntersecting;
}
// Update and check big fish
for (var b = bigFish.length - 1; b >= 0; b--) {
var currentBigFish = bigFish[b];
// Initialize tracking variables
if (currentBigFish.lastX === undefined) currentBigFish.lastX = currentBigFish.x;
if (currentBigFish.lastIntersecting === undefined) currentBigFish.lastIntersecting = false;
// Check if big fish went off screen
if (currentBigFish.lastX >= -120 && currentBigFish.x < -120) {
currentBigFish.destroy();
bigFish.splice(b, 1);
continue;
}
// Check collision with shark - big fish damage shark
var currentIntersecting = shark.intersects(currentBigFish);
if (!currentBigFish.lastIntersecting && currentIntersecting) {
// Take damage from big fish
takeDamage(currentBigFish.damage);
// Flash both objects red
LK.effects.flashObject(currentBigFish, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
// Create blood effect at collision
createBloodEffect(currentBigFish.x, currentBigFish.y);
// Remove big fish after collision
currentBigFish.destroy();
bigFish.splice(b, 1);
continue;
}
// Update tracking variables
currentBigFish.lastX = currentBigFish.x;
currentBigFish.lastIntersecting = currentIntersecting;
}
// Update and check swimmers
for (var s = swimmers.length - 1; s >= 0; s--) {
var currentSwimmer = swimmers[s];
// Initialize tracking variables
if (currentSwimmer.lastX === undefined) currentSwimmer.lastX = currentSwimmer.x;
if (currentSwimmer.lastIntersecting === undefined) currentSwimmer.lastIntersecting = false;
// Check if swimmer went off screen
if (currentSwimmer.lastX >= -100 && currentSwimmer.x < -100) {
currentSwimmer.destroy();
swimmers.splice(s, 1);
continue;
}
// Check collision with shark - only if score >= 1000
var currentIntersecting = shark.intersects(currentSwimmer);
if (!currentSwimmer.lastIntersecting && currentIntersecting) {
var currentScore = LK.getScore();
if (currentScore >= 1000) {
// Can eat swimmer
var newScore = currentScore + currentSwimmer.points;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
LK.getSound('eat').play();
// Create blood effect at swimmer position
createBloodEffect(currentSwimmer.x, currentSwimmer.y);
// Flash effect
LK.effects.flashObject(currentSwimmer, 0x00ff00, 200);
currentSwimmer.destroy();
swimmers.splice(s, 1);
continue;
} else {
// Can't eat swimmer yet - bounce back effect
LK.effects.flashObject(currentSwimmer, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
}
}
// Update tracking variables
currentSwimmer.lastX = currentSwimmer.x;
currentSwimmer.lastIntersecting = currentIntersecting;
}
// Update and check ships
for (var h = ships.length - 1; h >= 0; h--) {
var currentShip = ships[h];
// Initialize tracking variables
if (currentShip.lastX === undefined) currentShip.lastX = currentShip.x;
if (currentShip.lastIntersecting === undefined) currentShip.lastIntersecting = false;
// Check if ship went off screen
if (currentShip.lastX >= -120 && currentShip.x < -120) {
currentShip.destroy();
ships.splice(h, 1);
continue;
}
// Check collision with shark - only if score >= 1500
var currentIntersecting = shark.intersects(currentShip);
if (!currentShip.lastIntersecting && currentIntersecting) {
var currentScore = LK.getScore();
if (currentScore >= 1500) {
// Can eat ship
var newScore = currentScore + currentShip.points;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
LK.getSound('eat').play();
// Create blood effect at ship position
createBloodEffect(currentShip.x, currentShip.y);
// Flash effect
LK.effects.flashObject(currentShip, 0x00ff00, 200);
currentShip.destroy();
ships.splice(h, 1);
continue;
} else {
// Can't eat ship yet - bounce back effect
LK.effects.flashObject(currentShip, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
}
}
// Update tracking variables
currentShip.lastX = currentShip.x;
currentShip.lastIntersecting = currentIntersecting;
}
// Update and check obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
var currentObstacle = obstacles[j];
// Initialize tracking variables
if (currentObstacle.lastX === undefined) currentObstacle.lastX = currentObstacle.x;
if (currentObstacle.lastIntersecting === undefined) currentObstacle.lastIntersecting = false;
// Check if obstacle went off screen
if (currentObstacle.lastX >= -100 && currentObstacle.x < -100) {
currentObstacle.destroy();
obstacles.splice(j, 1);
continue;
}
// Check collision with shark
var currentIntersecting = shark.intersects(currentObstacle);
if (!currentObstacle.lastIntersecting && currentIntersecting) {
// Hit obstacle - game over
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Update tracking variables
currentObstacle.lastX = currentObstacle.x;
currentObstacle.lastIntersecting = currentIntersecting;
}
// Allow shark to move anywhere on the map - no bounds constraints
};
// Play background music
LK.playMusic('ocean'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BigFish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('largeFish', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1.5 - Math.random() * 0.8;
self.damage = 20;
self.waveAmplitude = Math.random() * 80 + 40;
self.waveFrequency = Math.random() * 0.04 + 0.02;
self.waveOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.movePattern = Math.random() < 0.8 ? 'straight' : 'wave';
self.update = function () {
self.x += self.speed;
if (self.movePattern === 'wave') {
self.y = self.startY + Math.sin(self.x * self.waveFrequency + self.waveOffset) * self.waveAmplitude;
}
};
return self;
});
var Coral = Container.expand(function (type) {
var self = Container.call(this);
var coralType = type || 'coral1';
var coralGraphics = self.attachAsset(coralType, {
anchorX: 0.5,
anchorY: 1.0
});
self.coralType = coralType;
self.pulseScale = 1.0;
self.pulseDirection = 1;
self.pulseSpeed = Math.random() * 0.005 + 0.002;
self.update = function () {
// Gentle pulsing motion
self.pulseScale += self.pulseDirection * self.pulseSpeed;
if (self.pulseScale > 1.1) {
self.pulseScale = 1.1;
self.pulseDirection = -1;
} else if (self.pulseScale < 0.9) {
self.pulseScale = 0.9;
self.pulseDirection = 1;
}
coralGraphics.scaleX = self.pulseScale;
coralGraphics.scaleY = self.pulseScale;
};
return self;
});
var Fish = Container.expand(function (type) {
var self = Container.call(this);
var fishType = type || 'small';
var fishGraphics = self.attachAsset(fishType + 'Fish', {
anchorX: 0.5,
anchorY: 0.5
});
self.fishType = fishType;
self.speed = -1 - Math.random() * 0.5;
self.points = fishType === 'small' ? 10 : fishType === 'medium' ? 25 : 50;
self.waveAmplitude = Math.random() * 100 + 50;
self.waveFrequency = Math.random() * 0.05 + 0.02;
self.waveOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.movePattern = Math.random() < 0.7 ? 'straight' : 'wave';
self.update = function () {
self.x += self.speed;
if (self.movePattern === 'wave') {
self.y = self.startY + Math.sin(self.x * self.waveFrequency + self.waveOffset) * self.waveAmplitude;
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -5;
self.animationDirection = 1;
self.baseY = self.y;
self.animationRange = 150;
self.update = function () {
self.x += self.speed;
};
return self;
});
var SeaweedPlant = Container.expand(function (type) {
var self = Container.call(this);
var plantType = type || 'seaweed1';
var plantGraphics = self.attachAsset(plantType, {
anchorX: 0.5,
anchorY: 1.0
});
self.plantType = plantType;
self.baseX = self.x;
self.swayAmount = Math.random() * 10 + 5;
self.swaySpeed = Math.random() * 0.02 + 0.01;
self.swayOffset = Math.random() * Math.PI * 2;
self.update = function () {
// Gentle swaying motion
self.x = self.baseX + Math.sin(LK.ticks * self.swaySpeed + self.swayOffset) * self.swayAmount;
};
return self;
});
var Shark = Container.expand(function () {
var self = Container.call(this);
var sharkGraphics = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetY = 2732 / 2;
self.targetX = 300;
self.speed = 3;
self.scaleX = 1.0;
self.scaleY = 1.0;
self.update = function () {
// Smooth movement towards target Y position
var diffY = self.targetY - self.y;
self.y += diffY * 0.05;
// Smooth movement towards target X position
var diffX = self.targetX - self.x;
self.x += diffX * 0.05;
// Keep shark within map boundaries
if (self.x < 75) self.x = 75;
if (self.x > 1973) self.x = 1973;
if (self.y < 75) self.y = 75;
if (self.y > 2657) self.y = 2657;
};
return self;
});
var Shell = Container.expand(function () {
var self = Container.call(this);
var shellGraphics = self.attachAsset('shell', {
anchorX: 0.5,
anchorY: 1.0
});
self.pulseScale = 1.0;
self.pulseDirection = 1;
self.pulseSpeed = Math.random() * 0.003 + 0.001;
self.update = function () {
// Very gentle pulsing motion for shells
self.pulseScale += self.pulseDirection * self.pulseSpeed;
if (self.pulseScale > 1.05) {
self.pulseScale = 1.05;
self.pulseDirection = -1;
} else if (self.pulseScale < 0.95) {
self.pulseScale = 0.95;
self.pulseDirection = 1;
}
shellGraphics.scaleX = self.pulseScale;
shellGraphics.scaleY = self.pulseScale;
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -0.8 - Math.random() * 0.4;
self.points = 150;
self.bobAmplitude = Math.random() * 8 + 5;
self.bobFrequency = Math.random() * 0.02 + 0.01;
self.bobOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.update = function () {
self.x += self.speed;
// Gentle bobbing motion on water surface
self.y = self.startY + Math.sin(self.x * self.bobFrequency + self.bobOffset) * self.bobAmplitude;
};
return self;
});
var Swimmer = Container.expand(function () {
var self = Container.call(this);
var swimmerGraphics = self.attachAsset('swimmer', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -0.5 - Math.random() * 0.3;
self.points = 100;
self.waveAmplitude = Math.random() * 20 + 10;
self.waveFrequency = Math.random() * 0.03 + 0.01;
self.waveOffset = Math.random() * Math.PI * 2;
self.startY = self.y;
self.update = function () {
self.x += self.speed;
// Swimming motion with small waves
self.y = self.startY + Math.sin(self.x * self.waveFrequency + self.waveOffset) * self.waveAmplitude;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001a33
});
/****
* Game Code
****/
// Create beach at the top of the screen
var beach = LK.getAsset('beach', {
anchorX: 0,
anchorY: 0
});
beach.x = 0;
beach.y = 0;
beach.scaleX = 20.48; // Scale to cover full width (2048/100)
beach.scaleY = 1.5; // Make it taller for better visual
game.addChild(beach);
// Create ocean floor that spans the entire screen width
var oceanFloor = LK.getAsset('oceanFloor', {
anchorX: 0,
anchorY: 1.0
});
oceanFloor.x = 0;
oceanFloor.y = 2732;
oceanFloor.scaleX = 20.48; // Scale to cover full width (2048/100)
oceanFloor.scaleY = 2; // Make it taller for better visual
game.addChild(oceanFloor);
// Create background plants and corals
var plants = [];
var corals = [];
var shells = [];
// Add seaweed plants
for (var p = 0; p < 15; p++) {
var plantTypes = ['seaweed1', 'seaweed2', 'seaweed3'];
var plantType = plantTypes[Math.floor(Math.random() * plantTypes.length)];
var plant = new SeaweedPlant(plantType);
plant.x = Math.random() * 2048;
plant.y = 2732 - Math.random() * 50;
plant.baseX = plant.x;
plants.push(plant);
game.addChild(plant);
}
// Add coral decorations
for (var c = 0; c < 8; c++) {
var coralTypes = ['coral1', 'coral2'];
var coralType = coralTypes[Math.floor(Math.random() * coralTypes.length)];
var coral = new Coral(coralType);
coral.x = Math.random() * 2048;
coral.y = 2732 - Math.random() * 30;
corals.push(coral);
game.addChild(coral);
}
// Add shell decorations
for (var s = 0; s < 12; s++) {
var shell = new Shell();
shell.x = Math.random() * 2048;
shell.y = 2732 - Math.random() * 20;
shells.push(shell);
game.addChild(shell);
}
var shark = game.addChild(new Shark());
shark.x = 300;
shark.y = 2732 / 2;
var maxHealth = 100;
var currentHealth = 100;
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -20;
scoreTxt.y = 20;
// Create health bar background
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBarBg);
healthBarBg.x = 120;
healthBarBg.y = 20;
// Create health bar foreground
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBar);
healthBar.x = 120;
healthBar.y = 20;
// Create health text
var healthTxt = new Text2('Health: 100', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthTxt);
healthTxt.x = 120;
healthTxt.y = 50;
var fish = [];
var bigFish = [];
var obstacles = [];
var swimmers = [];
var ships = [];
var gameSpeed = 1;
var spawnTimer = 0;
var bigFishTimer = 0;
var obstacleTimer = 0;
var speedIncreaseTimer = 0;
var swimmerTimer = 0;
var shipTimer = 0;
// Mouse/finger tracking variables
var mouseY = 2732 / 2;
var mouseX = 300;
function takeDamage(amount) {
currentHealth -= amount;
if (currentHealth < 0) currentHealth = 0;
// Add damage points to score
var currentScore = LK.getScore();
var newScore = currentScore + amount;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
// Update health bar
var healthPercent = currentHealth / maxHealth;
healthBar.scaleX = healthPercent;
healthBar.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
healthTxt.setText('Health: ' + currentHealth);
// Flash screen red when taking damage
LK.effects.flashScreen(0xff0000, 300);
LK.getSound('damage').play();
// Check for game over
if (currentHealth <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
function spawnFish() {
var fishTypes = ['small', 'small', 'small', 'medium', 'medium', 'large'];
var type = fishTypes[Math.floor(Math.random() * fishTypes.length)];
var newFish = new Fish(type);
newFish.x = 2048 + 50;
newFish.y = Math.random() * (2732 - 200) + 100;
newFish.startY = newFish.y;
fish.push(newFish);
game.addChild(newFish);
}
function spawnBigFish() {
var newBigFish = new BigFish();
newBigFish.x = 2048 + 75;
newBigFish.y = Math.random() * (2732 - 200) + 100;
newBigFish.startY = newBigFish.y;
bigFish.push(newBigFish);
game.addChild(newBigFish);
}
function spawnSwimmer() {
var newSwimmer = new Swimmer();
newSwimmer.x = 2048 + 50;
newSwimmer.y = Math.random() * 150 + 100; // Stay near the beach/surface
newSwimmer.startY = newSwimmer.y;
swimmers.push(newSwimmer);
game.addChild(newSwimmer);
}
function spawnShip() {
var newShip = new Ship();
newShip.x = 2048 + 60;
newShip.y = Math.random() * 80 + 180; // Stay at water surface level
newShip.startY = newShip.y;
ships.push(newShip);
game.addChild(newShip);
}
function createBloodEffect(x, y) {
// Create multiple blood particles
for (var p = 0; p < 8; p++) {
var bloodParticle = LK.getAsset('bloodParticle', {
anchorX: 0.5,
anchorY: 0.5
});
bloodParticle.x = x + (Math.random() - 0.5) * 40;
bloodParticle.y = y + (Math.random() - 0.5) * 40;
game.addChild(bloodParticle);
// Animate blood particle with random direction and fade out
var targetX = bloodParticle.x + (Math.random() - 0.5) * 150;
var targetY = bloodParticle.y + (Math.random() - 0.5) * 150;
tween(bloodParticle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
bloodParticle.destroy();
}
});
}
}
function spawnObstacle() {
var newObstacle = new Obstacle();
newObstacle.x = 2048 + 50;
newObstacle.y = Math.random() * (2732 - 200) + 100;
newObstacle.baseY = newObstacle.y;
// Start up and down animation
function animateObstacle() {
var targetY = newObstacle.baseY + newObstacle.animationDirection * newObstacle.animationRange;
tween(newObstacle, {
y: targetY
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
newObstacle.animationDirection *= -1;
animateObstacle();
}
});
}
animateObstacle();
obstacles.push(newObstacle);
game.addChild(newObstacle);
}
game.down = function (x, y, obj) {
mouseY = Math.max(75, Math.min(y, 2657));
mouseX = Math.max(75, Math.min(x, 1973));
shark.targetY = mouseY;
shark.targetX = mouseX;
};
game.move = function (x, y, obj) {
mouseY = Math.max(75, Math.min(y, 2657));
mouseX = Math.max(75, Math.min(x, 1973));
shark.targetY = mouseY;
shark.targetX = mouseX;
};
game.update = function () {
spawnTimer++;
bigFishTimer++;
obstacleTimer++;
speedIncreaseTimer++;
swimmerTimer++;
shipTimer++;
// Spawn fish
if (spawnTimer >= Math.max(30 - Math.floor(gameSpeed), 15)) {
spawnFish();
spawnTimer = 0;
}
// Spawn big fish occasionally
if (bigFishTimer >= Math.max(450 - Math.floor(gameSpeed * 25), 250)) {
if (Math.random() < 0.6) {
spawnBigFish();
}
bigFishTimer = 0;
}
// Spawn swimmers occasionally
if (swimmerTimer >= Math.max(400 - Math.floor(gameSpeed * 20), 200)) {
if (Math.random() < 0.4) {
spawnSwimmer();
}
swimmerTimer = 0;
}
// Spawn ships occasionally
if (shipTimer >= Math.max(600 - Math.floor(gameSpeed * 30), 300)) {
if (Math.random() < 0.3) {
spawnShip();
}
shipTimer = 0;
}
// Spawn obstacles occasionally
if (obstacleTimer >= Math.max(200 - Math.floor(gameSpeed * 10), 100)) {
if (Math.random() < 0.3) {
spawnObstacle();
}
obstacleTimer = 0;
}
// Increase game speed over time
if (speedIncreaseTimer >= 300) {
gameSpeed += 0.1;
speedIncreaseTimer = 0;
}
// Update and check fish
for (var i = fish.length - 1; i >= 0; i--) {
var currentFish = fish[i];
// Initialize tracking variables
if (currentFish.lastX === undefined) currentFish.lastX = currentFish.x;
if (currentFish.lastIntersecting === undefined) currentFish.lastIntersecting = false;
// Check if fish went off screen
if (currentFish.lastX >= -100 && currentFish.x < -100) {
currentFish.destroy();
fish.splice(i, 1);
continue;
}
// Check collision with shark
var currentIntersecting = shark.intersects(currentFish);
if (!currentFish.lastIntersecting && currentIntersecting) {
var currentScore = LK.getScore();
var canEat = false;
// Check if shark can eat this fish type based on score
if (currentFish.fishType === 'small') {
canEat = true; // Can always eat small fish
} else if (currentFish.fishType === 'medium') {
canEat = currentScore >= 200; // Can eat medium fish after 200 points
} else if (currentFish.fishType === 'large') {
canEat = currentScore >= 500; // Can eat large fish after 500 points
}
if (canEat) {
// Fish eaten
var newScore = currentScore + currentFish.points;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
LK.getSound('eat').play();
// Scale shark based on score milestones
var newScale = 1.0;
if (newScore >= 500) {
newScale = 1.5;
} else if (newScore >= 200) {
newScale = 1.25;
}
// Animate shark scaling if it changed
if (shark.scaleX !== newScale) {
tween(shark, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 300,
easing: tween.easeOut
});
}
// Create blood effect at fish position
createBloodEffect(currentFish.x, currentFish.y);
// Flash effect
LK.effects.flashObject(currentFish, 0x00ff00, 200);
currentFish.destroy();
fish.splice(i, 1);
continue;
} else {
// Can't eat this fish - take damage and bounce back effect
if (currentFish.fishType === 'medium' && currentScore < 200) {
takeDamage(15); // Take damage from medium fish when score is under 200
} else if (currentFish.fishType === 'large' && currentScore < 500) {
takeDamage(25); // Take damage from large fish when score is under 500
}
LK.effects.flashObject(currentFish, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
}
}
// Update tracking variables
currentFish.lastX = currentFish.x;
currentFish.lastIntersecting = currentIntersecting;
}
// Update and check big fish
for (var b = bigFish.length - 1; b >= 0; b--) {
var currentBigFish = bigFish[b];
// Initialize tracking variables
if (currentBigFish.lastX === undefined) currentBigFish.lastX = currentBigFish.x;
if (currentBigFish.lastIntersecting === undefined) currentBigFish.lastIntersecting = false;
// Check if big fish went off screen
if (currentBigFish.lastX >= -120 && currentBigFish.x < -120) {
currentBigFish.destroy();
bigFish.splice(b, 1);
continue;
}
// Check collision with shark - big fish damage shark
var currentIntersecting = shark.intersects(currentBigFish);
if (!currentBigFish.lastIntersecting && currentIntersecting) {
// Take damage from big fish
takeDamage(currentBigFish.damage);
// Flash both objects red
LK.effects.flashObject(currentBigFish, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
// Create blood effect at collision
createBloodEffect(currentBigFish.x, currentBigFish.y);
// Remove big fish after collision
currentBigFish.destroy();
bigFish.splice(b, 1);
continue;
}
// Update tracking variables
currentBigFish.lastX = currentBigFish.x;
currentBigFish.lastIntersecting = currentIntersecting;
}
// Update and check swimmers
for (var s = swimmers.length - 1; s >= 0; s--) {
var currentSwimmer = swimmers[s];
// Initialize tracking variables
if (currentSwimmer.lastX === undefined) currentSwimmer.lastX = currentSwimmer.x;
if (currentSwimmer.lastIntersecting === undefined) currentSwimmer.lastIntersecting = false;
// Check if swimmer went off screen
if (currentSwimmer.lastX >= -100 && currentSwimmer.x < -100) {
currentSwimmer.destroy();
swimmers.splice(s, 1);
continue;
}
// Check collision with shark - only if score >= 1000
var currentIntersecting = shark.intersects(currentSwimmer);
if (!currentSwimmer.lastIntersecting && currentIntersecting) {
var currentScore = LK.getScore();
if (currentScore >= 1000) {
// Can eat swimmer
var newScore = currentScore + currentSwimmer.points;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
LK.getSound('eat').play();
// Create blood effect at swimmer position
createBloodEffect(currentSwimmer.x, currentSwimmer.y);
// Flash effect
LK.effects.flashObject(currentSwimmer, 0x00ff00, 200);
currentSwimmer.destroy();
swimmers.splice(s, 1);
continue;
} else {
// Can't eat swimmer yet - bounce back effect
LK.effects.flashObject(currentSwimmer, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
}
}
// Update tracking variables
currentSwimmer.lastX = currentSwimmer.x;
currentSwimmer.lastIntersecting = currentIntersecting;
}
// Update and check ships
for (var h = ships.length - 1; h >= 0; h--) {
var currentShip = ships[h];
// Initialize tracking variables
if (currentShip.lastX === undefined) currentShip.lastX = currentShip.x;
if (currentShip.lastIntersecting === undefined) currentShip.lastIntersecting = false;
// Check if ship went off screen
if (currentShip.lastX >= -120 && currentShip.x < -120) {
currentShip.destroy();
ships.splice(h, 1);
continue;
}
// Check collision with shark - only if score >= 1500
var currentIntersecting = shark.intersects(currentShip);
if (!currentShip.lastIntersecting && currentIntersecting) {
var currentScore = LK.getScore();
if (currentScore >= 1500) {
// Can eat ship
var newScore = currentScore + currentShip.points;
LK.setScore(newScore);
scoreTxt.setText('Score: ' + newScore);
LK.getSound('eat').play();
// Create blood effect at ship position
createBloodEffect(currentShip.x, currentShip.y);
// Flash effect
LK.effects.flashObject(currentShip, 0x00ff00, 200);
currentShip.destroy();
ships.splice(h, 1);
continue;
} else {
// Can't eat ship yet - bounce back effect
LK.effects.flashObject(currentShip, 0xff0000, 200);
LK.effects.flashObject(shark, 0xff0000, 200);
}
}
// Update tracking variables
currentShip.lastX = currentShip.x;
currentShip.lastIntersecting = currentIntersecting;
}
// Update and check obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
var currentObstacle = obstacles[j];
// Initialize tracking variables
if (currentObstacle.lastX === undefined) currentObstacle.lastX = currentObstacle.x;
if (currentObstacle.lastIntersecting === undefined) currentObstacle.lastIntersecting = false;
// Check if obstacle went off screen
if (currentObstacle.lastX >= -100 && currentObstacle.x < -100) {
currentObstacle.destroy();
obstacles.splice(j, 1);
continue;
}
// Check collision with shark
var currentIntersecting = shark.intersects(currentObstacle);
if (!currentObstacle.lastIntersecting && currentIntersecting) {
// Hit obstacle - game over
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Update tracking variables
currentObstacle.lastX = currentObstacle.x;
currentObstacle.lastIntersecting = currentIntersecting;
}
// Allow shark to move anywhere on the map - no bounds constraints
};
// Play background music
LK.playMusic('ocean');
big fish. In-Game asset. 2d. High contrast. No shadows
shark. In-Game asset. 2d. High contrast. No shadows
fish. In-Game asset. 2d. High contrast. No shadows
jelly fish. In-Game asset. 2d. High contrast. No shadows
small fish. In-Game asset. 2d. High contrast. No shadows
large coral. In-Game asset. 2d. High contrast. No shadows
seaweed. In-Game asset. 2d. High contrast. No shadows
shell. In-Game asset. 2d. High contrast. No shadows
sky. In-Game asset. 2d. High contrast. No shadows
swimming person. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
person on a cano. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
heart. In-Game asset. 2d. High contrast. No shadows