/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1", {
recordScore: 0
});
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Fish = Container.expand(function (type, speed) {
var self = Container.call(this);
self.type = type || 'smallFish';
self.speed = speed || 2;
self.value = 1;
self.lastY = 0;
if (self.type === 'smallFish') {
self.value = 1;
self.danger = 0;
} else if (self.type === 'mediumFish') {
self.value = 2;
self.danger = 0.5;
} else if (self.type === 'largeFish') {
self.value = 4;
self.danger = 1;
} else if (self.type === 'goldenFish') {
self.value = 10;
self.danger = 0;
}
var fishGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = Math.random() > 0.5 ? 1 : -1;
fishGraphics.scale.x = self.direction;
self.update = function () {
self.lastY = self.y;
self.x += self.speed * self.direction;
// Wrap around screen
if (self.x < -100 && self.direction < 0) {
self.x = 2148;
} else if (self.x > 2148 && self.direction > 0) {
self.x = -100;
}
};
return self;
});
var Obstacle = Container.expand(function (speed) {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = speed || 1;
self.damage = 10;
self.lastY = 0;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Remove if off screen
if (self.y > 2832) {
self.shouldRemove = true;
}
};
return self;
});
var OceanBackground = Container.expand(function () {
var self = Container.call(this);
// Main ocean background - blue gradient ocean
var bgGraphics = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
bgGraphics.tint = 0x0066cc; // Deep blue ocean color
// Create gradient effect with multiple layers
var deepLayer = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
deepLayer.tint = 0x003366; // Darker blue for depth
deepLayer.alpha = 0.4;
deepLayer.y = 1500;
var midLayer = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
midLayer.tint = 0x0088dd; // Mid blue
midLayer.alpha = 0.3;
midLayer.y = 800;
var topLayer = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
topLayer.tint = 0x66ccff; // Light blue for surface
topLayer.alpha = 0.2;
topLayer.y = 0;
// Ocean floor with sandy texture
var floorGraphics = self.attachAsset('oceanFloor', {
anchorX: 0,
anchorY: 1
});
floorGraphics.y = 2732;
floorGraphics.tint = 0xd2b48c; // Sandy color
// Water surface with transparency and shimmer
var surfaceGraphics = self.attachAsset('waterSurface', {
anchorX: 0,
anchorY: 0
});
surfaceGraphics.y = 0;
surfaceGraphics.alpha = 0.7;
surfaceGraphics.tint = 0x99ddff; // Light blue surface
// Enhanced light rays for underwater god rays effect
var lights = [];
for (var i = 0; i < 6; i++) {
var light = self.attachAsset('lightRay', {
anchorX: 0.5,
anchorY: 0
});
light.x = 200 + Math.random() * 1600;
light.y = 0;
light.alpha = 0.1 + Math.random() * 0.15;
light.scale.set(0.5 + Math.random() * 0.8);
light.tint = 0xffffcc; // Slight yellow tint for sunlight
lights.push(light);
}
// Bubbles with varied sizes and speeds
var bubbles = [];
for (var i = 0; i < 25; i++) {
spawnBubble();
}
function spawnBubble() {
var bubble = self.attachAsset('bubbles', {
anchorX: 0.5,
anchorY: 0.5
});
bubble.tint = 0xffffff;
bubble.x = Math.random() * 2048;
bubble.y = 500 + Math.random() * 2200;
bubble.alpha = 0.3 + Math.random() * 0.5;
bubble.scale.set(0.2 + Math.random() * 0.5);
bubble.speed = 0.5 + Math.random() * 1.5;
bubble.wobbleSpeed = 0.01 + Math.random() * 0.03;
bubble.wobbleAmount = 0 + Math.random() * 30;
bubble.wobbleOffset = Math.random() * Math.PI * 2;
bubbles.push(bubble);
}
// Create small dust particles for realism
var particles = [];
for (var i = 0; i < 40; i++) {
var particle = self.attachAsset('bubbles', {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = 0xcccccc;
particle.x = Math.random() * 2048;
particle.y = Math.random() * 2732;
particle.alpha = 0.1 + Math.random() * 0.2;
particle.scale.set(0.05 + Math.random() * 0.15);
particle.speed = 0.1 + Math.random() * 0.3;
particle.wobbleSpeed = 0.005 + Math.random() * 0.01;
particle.wobbleOffset = Math.random() * Math.PI * 2;
particles.push(particle);
}
self.update = function () {
// Update bubbles
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
bubble.y -= bubble.speed;
bubble.x += Math.sin(LK.ticks * bubble.wobbleSpeed + bubble.wobbleOffset) * 0.3;
// If bubble reaches surface, respawn it
if (bubble.y < 100) {
bubble.destroy();
bubbles.splice(i, 1);
spawnBubble();
}
}
// Update dust particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
particle.y -= particle.speed;
particle.x += Math.sin(LK.ticks * particle.wobbleSpeed + particle.wobbleOffset) * 0.2;
// Loop particles at the bottom
if (particle.y < 0) {
particle.y = 2732;
particle.x = Math.random() * 2048;
}
}
// Create dynamic water movement
for (var i = 0; i < 4; i++) {
var layer = self.getChildAt(i);
layer.y += Math.sin(LK.ticks * 0.01 + i * 0.5) * 0.2;
}
// Gentle animation for water surface
surfaceGraphics.y = Math.sin(LK.ticks * 0.02) * 5;
surfaceGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.03) * 0.1;
// Animate light rays with movement and intensity changes
for (var i = 0; i < lights.length; i++) {
var light = lights[i];
light.alpha = 0.1 + Math.sin(LK.ticks * 0.01 + i) * 0.1;
light.x += Math.sin(LK.ticks * 0.003 + i * 0.2) * 0.3;
light.width = light.width + Math.sin(LK.ticks * 0.01 + i * 0.5) * 0.4;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.random() > 0.5 ? 'speed' : 'invincibility';
self.speed = 1;
self.lastY = 0;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Simple animation
self.rotation += 0.02;
// Remove if off screen
if (self.y > 2832) {
self.shouldRemove = true;
}
};
return self;
});
// Set ocean blue background
var Shark = Container.expand(function () {
var self = Container.call(this);
var sharkGraphics = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.5
});
self.size = 1;
self.speed = 5;
self.health = 100;
self.oxygen = 100;
self.score = 0;
self.lastX = 0;
self.lastY = 0;
self.facing = 1; // 1 = right, -1 = left
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Reduce oxygen when deep in the ocean (upper part of the screen is surface)
if (self.y > 1000) {
self.oxygen -= 0.2;
if (self.oxygen <= 0) {
self.health -= 0.5;
}
} else {
// Replenish oxygen near the surface
self.oxygen = Math.min(100, self.oxygen + 0.5);
}
// Update scale based on size
self.scale.set(self.size);
// Flip shark graphic based on direction
if (self.facing === 1) {
sharkGraphics.scale.x = Math.abs(sharkGraphics.scale.x);
} else {
sharkGraphics.scale.x = -Math.abs(sharkGraphics.scale.x);
}
};
self.grow = function (amount) {
self.size += amount;
self.score += Math.round(amount * 10);
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.getSound('damage').play();
LK.effects.flashObject(self, 0xff0000, 500);
};
return self;
});
var StartScreen = Container.expand(function () {
var self = Container.call(this);
// Create ocean-themed background container
var bgContainer = new Container();
self.addChild(bgContainer);
// Create gradient background
var bgGraphics = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
bgGraphics.tint = 0x0088dd; // Ocean blue
// Create decorative bubbles
var bubbles = [];
for (var i = 0; i < 30; i++) {
var bubble = self.attachAsset('bubbles', {
anchorX: 0.5,
anchorY: 0.5
});
bubble.tint = 0xffffff;
bubble.alpha = 0.2 + Math.random() * 0.6;
bubble.scale.set(0.2 + Math.random() * 0.8);
bubble.x = Math.random() * 2048;
bubble.y = Math.random() * 2732;
bubble.speed = 0.5 + Math.random() * 2;
bubble.wobbleSpeed = 0.01 + Math.random() * 0.04;
bubble.wobbleOffset = Math.random() * Math.PI * 2;
bubbles.push(bubble);
}
// Create title text with shadow
var titleShadow = new Text2('Shark Adventure', {
size: 120,
fill: 0x000000
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 2048 / 2 + 6;
titleShadow.y = 600 + 6;
self.addChild(titleShadow);
var titleText = new Text2('Shark Adventure', {
size: 120,
fill: 0x00ccff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
self.addChild(titleText);
// Create shark image
var sharkImage = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.5
});
sharkImage.x = 2048 / 2;
sharkImage.y = 1000;
sharkImage.scale.set(2);
// Create animated fish in background
var decorativeFish = [];
var fishTypes = ['smallFish', 'mediumFish', 'largeFish', 'goldenFish'];
for (var i = 0; i < 10; i++) {
var fishType = fishTypes[Math.floor(Math.random() * fishTypes.length)];
var fish = self.attachAsset(fishType, {
anchorX: 0.5,
anchorY: 0.5
});
fish.x = Math.random() * 2048;
fish.y = 300 + Math.random() * 1800;
fish.scale.set(0.6 + Math.random() * 0.8);
fish.speed = 1 + Math.random() * 3;
fish.direction = Math.random() > 0.5 ? 1 : -1;
fish.scale.x *= fish.direction;
fish.alpha = 0.7;
decorativeFish.push(fish);
}
// Create start button with gradient effect
var buttonBg = self.attachAsset('oceanBg', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.width = 500;
buttonBg.height = 150;
buttonBg.tint = 0x0066aa;
buttonBg.x = 2048 / 2;
buttonBg.y = 1600;
var buttonShadow = new Text2('TAP TO PLAY', {
size: 80,
fill: 0x000000
});
buttonShadow.anchor.set(0.5, 0.5);
buttonShadow.x = 2048 / 2 + 4;
buttonShadow.y = 1600 + 4;
self.addChild(buttonShadow);
var buttonText = new Text2('TAP TO PLAY', {
size: 80,
fill: 0xffffff
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 2048 / 2;
buttonText.y = 1600;
self.addChild(buttonText);
// Display record score
var recordText = new Text2('Record: ' + (storage.recordScore || 0), {
size: 60,
fill: 0xffdd00
});
recordText.anchor.set(0.5, 0.5);
recordText.x = 2048 / 2;
recordText.y = 1800;
self.addChild(recordText);
// Add pulse animation to button
function pulseButton() {
tween(buttonBg.scale, {
x: 1.1,
y: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonBg.scale, {
x: 1.0,
y: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: pulseButton
});
}
});
}
pulseButton();
// Add floating animation to shark
function floatShark() {
tween(sharkImage, {
y: sharkImage.y + 50
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sharkImage, {
y: sharkImage.y - 50
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: floatShark
});
}
});
}
floatShark();
// Add title animation
tween(titleText.scale, {
x: 1.1,
y: 1.1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText.scale, {
x: 1.0,
y: 1.0
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
// Handle tap anywhere to start
self.down = function (x, y, obj) {
self.onStartGame && self.onStartGame();
};
self.update = function () {
// Update bubbles
for (var i = 0; i < bubbles.length; i++) {
var bubble = bubbles[i];
bubble.y -= bubble.speed;
bubble.x += Math.sin(LK.ticks * bubble.wobbleSpeed + bubble.wobbleOffset) * 0.5;
// Loop bubbles when they reach the top
if (bubble.y < -50) {
bubble.y = 2732 + 50;
bubble.x = Math.random() * 2048;
}
}
// Update fish swimming
for (var i = 0; i < decorativeFish.length; i++) {
var fish = decorativeFish[i];
fish.x += fish.speed * fish.direction;
// Wrap fish around screen
if (fish.x < -100 && fish.direction < 0) {
fish.x = 2148;
} else if (fish.x > 2148 && fish.direction > 0) {
fish.x = -100;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Black background, ocean handled by OceanBackground class
});
/****
* Game Code
****/
// Background is now handled by the OceanBackground class
// Game variables
var shark;
var fishes = [];
var obstacles = [];
var powerUps = [];
var lastIntersectingFish = {};
var lastIntersectingObstacle = {};
var lastIntersectingPowerUp = {};
var gameActive = false;
var gameStarted = false;
var powerUpActive = false;
var powerUpTimer = 0;
var spawnTimer = 0;
var difficultyTimer = 0;
var difficulty = 1;
var maxFishes = 10;
var dragNode = null;
var oceanBackground;
var startScreen;
var recordScore = storage.recordScore || 0;
// UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
scoreText.x = 120;
scoreText.y = 20;
var recordScoreText = new Text2('Record: ' + recordScore, {
size: 40,
fill: 0xFFDD00
});
recordScoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(recordScoreText);
recordScoreText.x = 120;
recordScoreText.y = 200;
var healthBarBg = LK.getAsset('healthBg', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 100
});
LK.gui.topLeft.addChild(healthBarBg);
var healthBarFill = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 100
});
LK.gui.topLeft.addChild(healthBarFill);
var oxygenBarBg = LK.getAsset('oxygenBg', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 150
});
LK.gui.topLeft.addChild(oxygenBarBg);
var oxygenBarFill = LK.getAsset('oxygen', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 150
});
LK.gui.topLeft.addChild(oxygenBarFill);
// Initialize shark
function initGame() {
if (!gameStarted) {
// Show start screen first
startScreen = new StartScreen();
game.addChild(startScreen);
// Set callback for when start button is pressed
startScreen.onStartGame = function () {
// Remove start screen
startScreen.destroy();
startScreen = null;
// Start the actual game
startGame();
};
gameStarted = true;
} else {
// Direct game start (for game restarts)
startGame();
}
}
// Function to start the actual game
function startGame() {
// Create ocean background
oceanBackground = new OceanBackground();
game.addChild(oceanBackground);
// Create shark
shark = new Shark();
shark.x = 2048 / 2;
shark.y = 2732 / 2;
game.addChild(shark);
// Reset variables
fishes = [];
obstacles = [];
powerUps = [];
lastIntersectingFish = {};
lastIntersectingObstacle = {};
lastIntersectingPowerUp = {};
gameActive = true;
powerUpActive = false;
powerUpTimer = 0;
spawnTimer = 0;
difficultyTimer = 0;
difficulty = 1;
LK.setScore(0);
// Get record score from storage
recordScore = storage.recordScore || 0;
recordScoreText.setText('Record: ' + recordScore);
// Spawn initial fish
for (var i = 0; i < 5; i++) {
spawnFish();
}
}
// Spawn a new fish
function spawnFish() {
var fishType;
var rand = Math.random();
if (rand < 0.05) {
fishType = 'goldenFish';
} else if (rand < 0.2) {
fishType = 'largeFish';
} else if (rand < 0.5) {
fishType = 'mediumFish';
} else {
fishType = 'smallFish';
}
var speed = 1 + Math.random() * 2 * difficulty;
var fish = new Fish(fishType, speed);
// Position fish at random height, but from the side
fish.y = 200 + Math.random() * 2300;
if (Math.random() > 0.5) {
fish.x = -50;
fish.direction = 1;
} else {
fish.x = 2098;
fish.direction = -1;
}
fishes.push(fish);
game.addChild(fish);
}
// Spawn an obstacle
function spawnObstacle() {
var obstacle = new Obstacle(1 + Math.random() * difficulty);
obstacle.x = 100 + Math.random() * 1848;
obstacle.y = -100;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Spawn a power-up
function spawnPowerUp() {
var powerUp = new PowerUp();
powerUp.x = 100 + Math.random() * 1848;
powerUp.y = -100;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Handle shark collision with fish
function handleFishCollision(fish, index) {
// Check if shark can eat this fish
if (shark.size >= fish.danger) {
// Shark eats fish
shark.grow(fish.value * 0.05);
// Reduce width by 10 and height by 5 when eating golden fish
if (fish.type === 'goldenFish') {
var sharkGraphics = shark.getChildAt(0);
sharkGraphics.width -= 10;
sharkGraphics.height -= 5;
}
LK.setScore(shark.score);
scoreText.setText("Score: " + shark.score);
// Check if new record achieved
if (shark.score > recordScore) {
recordScore = shark.score;
storage.recordScore = recordScore;
recordScoreText.setText('Record: ' + recordScore);
// Flash record text to highlight new record
LK.effects.flashObject(recordScoreText, 0xFFFF00, 500);
}
LK.getSound('eat').play();
// Remove fish
fish.destroy();
fishes.splice(index, 1);
} else {
// Fish damages shark
shark.takeDamage(5 * fish.danger);
}
}
// Game events
game.move = function (x, y, obj) {
if (!gameActive || !dragNode) return;
// Move shark to touch position
dragNode.x = x;
dragNode.y = y;
// Update shark direction based on movement
if (dragNode.x > dragNode.lastX) {
dragNode.facing = 1;
} else if (dragNode.x < dragNode.lastX) {
dragNode.facing = -1;
}
};
game.down = function (x, y, obj) {
if (!gameActive) return;
dragNode = shark;
game.move(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update
game.update = function () {
// If start screen is active, update it
if (startScreen) {
startScreen.update();
return;
}
if (!gameActive) return;
// Increase difficulty over time
difficultyTimer++;
if (difficultyTimer >= 600) {
// Every 10 seconds
difficulty += 0.1;
maxFishes = Math.min(20, maxFishes + 1);
difficultyTimer = 0;
}
// Update ocean background
if (oceanBackground) {
oceanBackground.update();
}
// Update shark
shark.update();
// Update UI
healthBarFill.width = shark.health / 100 * 200;
oxygenBarFill.width = shark.oxygen / 100 * 200;
// Check if game over
if (shark.health <= 0) {
gameActive = false;
// Check if we need to update the record
if (shark.score > recordScore) {
recordScore = shark.score;
storage.recordScore = recordScore;
recordScoreText.setText('Record: ' + recordScore);
}
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Spawn new entities
spawnTimer++;
if (spawnTimer >= 60) {
// Every second
if (fishes.length < maxFishes) {
spawnFish();
}
if (Math.random() < 0.2 * difficulty) {
spawnObstacle();
}
if (Math.random() < 0.05) {
spawnPowerUp();
}
spawnTimer = 0;
}
// Handle power-up timer
if (powerUpActive) {
powerUpTimer--;
if (powerUpTimer <= 0) {
powerUpActive = false;
shark.speed = 5;
}
}
// Update fishes and check collisions
for (var i = fishes.length - 1; i >= 0; i--) {
var fish = fishes[i];
fish.update();
var id = "fish" + i;
var isIntersecting = shark.intersects(fish);
// Check collision (transition from not intersecting to intersecting)
if (!lastIntersectingFish[id] && isIntersecting) {
handleFishCollision(fish, i);
continue; // Skip further processing if fish was eaten
}
lastIntersectingFish[id] = isIntersecting;
}
// Update obstacles and check collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.update();
if (obstacle.shouldRemove) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
var id = "obstacle" + i;
var isIntersecting = shark.intersects(obstacle);
// Check collision (transition from not intersecting to intersecting)
if (!lastIntersectingObstacle[id] && isIntersecting) {
if (!powerUpActive || powerUpActive && shark.type !== 'invincibility') {
shark.takeDamage(obstacle.damage);
}
}
lastIntersectingObstacle[id] = isIntersecting;
}
// Update power-ups and check collisions
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.update();
if (powerUp.shouldRemove) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
var id = "powerUp" + i;
var isIntersecting = shark.intersects(powerUp);
// Check collision (transition from not intersecting to intersecting)
if (!lastIntersectingPowerUp[id] && isIntersecting) {
// Apply power-up effect
powerUpActive = true;
powerUpTimer = 300; // 5 seconds
if (powerUp.type === 'speed') {
shark.speed = 10;
}
// Increase health by 15 when collecting any power-up
shark.health = Math.min(100, shark.health + 15);
LK.getSound('powerup').play();
LK.effects.flashObject(shark, 0x00ffff, 500);
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
lastIntersectingPowerUp[id] = isIntersecting;
}
};
// Initialize the game
initGame(); /****
* Plugins
****/
var storage = LK.import("@upit/storage.v1", {
recordScore: 0
});
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Fish = Container.expand(function (type, speed) {
var self = Container.call(this);
self.type = type || 'smallFish';
self.speed = speed || 2;
self.value = 1;
self.lastY = 0;
if (self.type === 'smallFish') {
self.value = 1;
self.danger = 0;
} else if (self.type === 'mediumFish') {
self.value = 2;
self.danger = 0.5;
} else if (self.type === 'largeFish') {
self.value = 4;
self.danger = 1;
} else if (self.type === 'goldenFish') {
self.value = 10;
self.danger = 0;
}
var fishGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = Math.random() > 0.5 ? 1 : -1;
fishGraphics.scale.x = self.direction;
self.update = function () {
self.lastY = self.y;
self.x += self.speed * self.direction;
// Wrap around screen
if (self.x < -100 && self.direction < 0) {
self.x = 2148;
} else if (self.x > 2148 && self.direction > 0) {
self.x = -100;
}
};
return self;
});
var Obstacle = Container.expand(function (speed) {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = speed || 1;
self.damage = 10;
self.lastY = 0;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Remove if off screen
if (self.y > 2832) {
self.shouldRemove = true;
}
};
return self;
});
var OceanBackground = Container.expand(function () {
var self = Container.call(this);
// Main ocean background - blue gradient ocean
var bgGraphics = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
bgGraphics.tint = 0x0066cc; // Deep blue ocean color
// Create gradient effect with multiple layers
var deepLayer = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
deepLayer.tint = 0x003366; // Darker blue for depth
deepLayer.alpha = 0.4;
deepLayer.y = 1500;
var midLayer = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
midLayer.tint = 0x0088dd; // Mid blue
midLayer.alpha = 0.3;
midLayer.y = 800;
var topLayer = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
topLayer.tint = 0x66ccff; // Light blue for surface
topLayer.alpha = 0.2;
topLayer.y = 0;
// Ocean floor with sandy texture
var floorGraphics = self.attachAsset('oceanFloor', {
anchorX: 0,
anchorY: 1
});
floorGraphics.y = 2732;
floorGraphics.tint = 0xd2b48c; // Sandy color
// Water surface with transparency and shimmer
var surfaceGraphics = self.attachAsset('waterSurface', {
anchorX: 0,
anchorY: 0
});
surfaceGraphics.y = 0;
surfaceGraphics.alpha = 0.7;
surfaceGraphics.tint = 0x99ddff; // Light blue surface
// Enhanced light rays for underwater god rays effect
var lights = [];
for (var i = 0; i < 6; i++) {
var light = self.attachAsset('lightRay', {
anchorX: 0.5,
anchorY: 0
});
light.x = 200 + Math.random() * 1600;
light.y = 0;
light.alpha = 0.1 + Math.random() * 0.15;
light.scale.set(0.5 + Math.random() * 0.8);
light.tint = 0xffffcc; // Slight yellow tint for sunlight
lights.push(light);
}
// Bubbles with varied sizes and speeds
var bubbles = [];
for (var i = 0; i < 25; i++) {
spawnBubble();
}
function spawnBubble() {
var bubble = self.attachAsset('bubbles', {
anchorX: 0.5,
anchorY: 0.5
});
bubble.tint = 0xffffff;
bubble.x = Math.random() * 2048;
bubble.y = 500 + Math.random() * 2200;
bubble.alpha = 0.3 + Math.random() * 0.5;
bubble.scale.set(0.2 + Math.random() * 0.5);
bubble.speed = 0.5 + Math.random() * 1.5;
bubble.wobbleSpeed = 0.01 + Math.random() * 0.03;
bubble.wobbleAmount = 0 + Math.random() * 30;
bubble.wobbleOffset = Math.random() * Math.PI * 2;
bubbles.push(bubble);
}
// Create small dust particles for realism
var particles = [];
for (var i = 0; i < 40; i++) {
var particle = self.attachAsset('bubbles', {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = 0xcccccc;
particle.x = Math.random() * 2048;
particle.y = Math.random() * 2732;
particle.alpha = 0.1 + Math.random() * 0.2;
particle.scale.set(0.05 + Math.random() * 0.15);
particle.speed = 0.1 + Math.random() * 0.3;
particle.wobbleSpeed = 0.005 + Math.random() * 0.01;
particle.wobbleOffset = Math.random() * Math.PI * 2;
particles.push(particle);
}
self.update = function () {
// Update bubbles
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
bubble.y -= bubble.speed;
bubble.x += Math.sin(LK.ticks * bubble.wobbleSpeed + bubble.wobbleOffset) * 0.3;
// If bubble reaches surface, respawn it
if (bubble.y < 100) {
bubble.destroy();
bubbles.splice(i, 1);
spawnBubble();
}
}
// Update dust particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
particle.y -= particle.speed;
particle.x += Math.sin(LK.ticks * particle.wobbleSpeed + particle.wobbleOffset) * 0.2;
// Loop particles at the bottom
if (particle.y < 0) {
particle.y = 2732;
particle.x = Math.random() * 2048;
}
}
// Create dynamic water movement
for (var i = 0; i < 4; i++) {
var layer = self.getChildAt(i);
layer.y += Math.sin(LK.ticks * 0.01 + i * 0.5) * 0.2;
}
// Gentle animation for water surface
surfaceGraphics.y = Math.sin(LK.ticks * 0.02) * 5;
surfaceGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.03) * 0.1;
// Animate light rays with movement and intensity changes
for (var i = 0; i < lights.length; i++) {
var light = lights[i];
light.alpha = 0.1 + Math.sin(LK.ticks * 0.01 + i) * 0.1;
light.x += Math.sin(LK.ticks * 0.003 + i * 0.2) * 0.3;
light.width = light.width + Math.sin(LK.ticks * 0.01 + i * 0.5) * 0.4;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.random() > 0.5 ? 'speed' : 'invincibility';
self.speed = 1;
self.lastY = 0;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Simple animation
self.rotation += 0.02;
// Remove if off screen
if (self.y > 2832) {
self.shouldRemove = true;
}
};
return self;
});
// Set ocean blue background
var Shark = Container.expand(function () {
var self = Container.call(this);
var sharkGraphics = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.5
});
self.size = 1;
self.speed = 5;
self.health = 100;
self.oxygen = 100;
self.score = 0;
self.lastX = 0;
self.lastY = 0;
self.facing = 1; // 1 = right, -1 = left
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Reduce oxygen when deep in the ocean (upper part of the screen is surface)
if (self.y > 1000) {
self.oxygen -= 0.2;
if (self.oxygen <= 0) {
self.health -= 0.5;
}
} else {
// Replenish oxygen near the surface
self.oxygen = Math.min(100, self.oxygen + 0.5);
}
// Update scale based on size
self.scale.set(self.size);
// Flip shark graphic based on direction
if (self.facing === 1) {
sharkGraphics.scale.x = Math.abs(sharkGraphics.scale.x);
} else {
sharkGraphics.scale.x = -Math.abs(sharkGraphics.scale.x);
}
};
self.grow = function (amount) {
self.size += amount;
self.score += Math.round(amount * 10);
};
self.takeDamage = function (amount) {
self.health -= amount;
LK.getSound('damage').play();
LK.effects.flashObject(self, 0xff0000, 500);
};
return self;
});
var StartScreen = Container.expand(function () {
var self = Container.call(this);
// Create ocean-themed background container
var bgContainer = new Container();
self.addChild(bgContainer);
// Create gradient background
var bgGraphics = self.attachAsset('oceanBg', {
anchorX: 0,
anchorY: 0
});
bgGraphics.tint = 0x0088dd; // Ocean blue
// Create decorative bubbles
var bubbles = [];
for (var i = 0; i < 30; i++) {
var bubble = self.attachAsset('bubbles', {
anchorX: 0.5,
anchorY: 0.5
});
bubble.tint = 0xffffff;
bubble.alpha = 0.2 + Math.random() * 0.6;
bubble.scale.set(0.2 + Math.random() * 0.8);
bubble.x = Math.random() * 2048;
bubble.y = Math.random() * 2732;
bubble.speed = 0.5 + Math.random() * 2;
bubble.wobbleSpeed = 0.01 + Math.random() * 0.04;
bubble.wobbleOffset = Math.random() * Math.PI * 2;
bubbles.push(bubble);
}
// Create title text with shadow
var titleShadow = new Text2('Shark Adventure', {
size: 120,
fill: 0x000000
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 2048 / 2 + 6;
titleShadow.y = 600 + 6;
self.addChild(titleShadow);
var titleText = new Text2('Shark Adventure', {
size: 120,
fill: 0x00ccff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
self.addChild(titleText);
// Create shark image
var sharkImage = self.attachAsset('shark', {
anchorX: 0.5,
anchorY: 0.5
});
sharkImage.x = 2048 / 2;
sharkImage.y = 1000;
sharkImage.scale.set(2);
// Create animated fish in background
var decorativeFish = [];
var fishTypes = ['smallFish', 'mediumFish', 'largeFish', 'goldenFish'];
for (var i = 0; i < 10; i++) {
var fishType = fishTypes[Math.floor(Math.random() * fishTypes.length)];
var fish = self.attachAsset(fishType, {
anchorX: 0.5,
anchorY: 0.5
});
fish.x = Math.random() * 2048;
fish.y = 300 + Math.random() * 1800;
fish.scale.set(0.6 + Math.random() * 0.8);
fish.speed = 1 + Math.random() * 3;
fish.direction = Math.random() > 0.5 ? 1 : -1;
fish.scale.x *= fish.direction;
fish.alpha = 0.7;
decorativeFish.push(fish);
}
// Create start button with gradient effect
var buttonBg = self.attachAsset('oceanBg', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.width = 500;
buttonBg.height = 150;
buttonBg.tint = 0x0066aa;
buttonBg.x = 2048 / 2;
buttonBg.y = 1600;
var buttonShadow = new Text2('TAP TO PLAY', {
size: 80,
fill: 0x000000
});
buttonShadow.anchor.set(0.5, 0.5);
buttonShadow.x = 2048 / 2 + 4;
buttonShadow.y = 1600 + 4;
self.addChild(buttonShadow);
var buttonText = new Text2('TAP TO PLAY', {
size: 80,
fill: 0xffffff
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 2048 / 2;
buttonText.y = 1600;
self.addChild(buttonText);
// Display record score
var recordText = new Text2('Record: ' + (storage.recordScore || 0), {
size: 60,
fill: 0xffdd00
});
recordText.anchor.set(0.5, 0.5);
recordText.x = 2048 / 2;
recordText.y = 1800;
self.addChild(recordText);
// Add pulse animation to button
function pulseButton() {
tween(buttonBg.scale, {
x: 1.1,
y: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonBg.scale, {
x: 1.0,
y: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: pulseButton
});
}
});
}
pulseButton();
// Add floating animation to shark
function floatShark() {
tween(sharkImage, {
y: sharkImage.y + 50
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sharkImage, {
y: sharkImage.y - 50
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: floatShark
});
}
});
}
floatShark();
// Add title animation
tween(titleText.scale, {
x: 1.1,
y: 1.1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText.scale, {
x: 1.0,
y: 1.0
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
// Handle tap anywhere to start
self.down = function (x, y, obj) {
self.onStartGame && self.onStartGame();
};
self.update = function () {
// Update bubbles
for (var i = 0; i < bubbles.length; i++) {
var bubble = bubbles[i];
bubble.y -= bubble.speed;
bubble.x += Math.sin(LK.ticks * bubble.wobbleSpeed + bubble.wobbleOffset) * 0.5;
// Loop bubbles when they reach the top
if (bubble.y < -50) {
bubble.y = 2732 + 50;
bubble.x = Math.random() * 2048;
}
}
// Update fish swimming
for (var i = 0; i < decorativeFish.length; i++) {
var fish = decorativeFish[i];
fish.x += fish.speed * fish.direction;
// Wrap fish around screen
if (fish.x < -100 && fish.direction < 0) {
fish.x = 2148;
} else if (fish.x > 2148 && fish.direction > 0) {
fish.x = -100;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Black background, ocean handled by OceanBackground class
});
/****
* Game Code
****/
// Background is now handled by the OceanBackground class
// Game variables
var shark;
var fishes = [];
var obstacles = [];
var powerUps = [];
var lastIntersectingFish = {};
var lastIntersectingObstacle = {};
var lastIntersectingPowerUp = {};
var gameActive = false;
var gameStarted = false;
var powerUpActive = false;
var powerUpTimer = 0;
var spawnTimer = 0;
var difficultyTimer = 0;
var difficulty = 1;
var maxFishes = 10;
var dragNode = null;
var oceanBackground;
var startScreen;
var recordScore = storage.recordScore || 0;
// UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
scoreText.x = 120;
scoreText.y = 20;
var recordScoreText = new Text2('Record: ' + recordScore, {
size: 40,
fill: 0xFFDD00
});
recordScoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(recordScoreText);
recordScoreText.x = 120;
recordScoreText.y = 200;
var healthBarBg = LK.getAsset('healthBg', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 100
});
LK.gui.topLeft.addChild(healthBarBg);
var healthBarFill = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 100
});
LK.gui.topLeft.addChild(healthBarFill);
var oxygenBarBg = LK.getAsset('oxygenBg', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 150
});
LK.gui.topLeft.addChild(oxygenBarBg);
var oxygenBarFill = LK.getAsset('oxygen', {
anchorX: 0,
anchorY: 0.5,
x: 120,
y: 150
});
LK.gui.topLeft.addChild(oxygenBarFill);
// Initialize shark
function initGame() {
if (!gameStarted) {
// Show start screen first
startScreen = new StartScreen();
game.addChild(startScreen);
// Set callback for when start button is pressed
startScreen.onStartGame = function () {
// Remove start screen
startScreen.destroy();
startScreen = null;
// Start the actual game
startGame();
};
gameStarted = true;
} else {
// Direct game start (for game restarts)
startGame();
}
}
// Function to start the actual game
function startGame() {
// Create ocean background
oceanBackground = new OceanBackground();
game.addChild(oceanBackground);
// Create shark
shark = new Shark();
shark.x = 2048 / 2;
shark.y = 2732 / 2;
game.addChild(shark);
// Reset variables
fishes = [];
obstacles = [];
powerUps = [];
lastIntersectingFish = {};
lastIntersectingObstacle = {};
lastIntersectingPowerUp = {};
gameActive = true;
powerUpActive = false;
powerUpTimer = 0;
spawnTimer = 0;
difficultyTimer = 0;
difficulty = 1;
LK.setScore(0);
// Get record score from storage
recordScore = storage.recordScore || 0;
recordScoreText.setText('Record: ' + recordScore);
// Spawn initial fish
for (var i = 0; i < 5; i++) {
spawnFish();
}
}
// Spawn a new fish
function spawnFish() {
var fishType;
var rand = Math.random();
if (rand < 0.05) {
fishType = 'goldenFish';
} else if (rand < 0.2) {
fishType = 'largeFish';
} else if (rand < 0.5) {
fishType = 'mediumFish';
} else {
fishType = 'smallFish';
}
var speed = 1 + Math.random() * 2 * difficulty;
var fish = new Fish(fishType, speed);
// Position fish at random height, but from the side
fish.y = 200 + Math.random() * 2300;
if (Math.random() > 0.5) {
fish.x = -50;
fish.direction = 1;
} else {
fish.x = 2098;
fish.direction = -1;
}
fishes.push(fish);
game.addChild(fish);
}
// Spawn an obstacle
function spawnObstacle() {
var obstacle = new Obstacle(1 + Math.random() * difficulty);
obstacle.x = 100 + Math.random() * 1848;
obstacle.y = -100;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Spawn a power-up
function spawnPowerUp() {
var powerUp = new PowerUp();
powerUp.x = 100 + Math.random() * 1848;
powerUp.y = -100;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Handle shark collision with fish
function handleFishCollision(fish, index) {
// Check if shark can eat this fish
if (shark.size >= fish.danger) {
// Shark eats fish
shark.grow(fish.value * 0.05);
// Reduce width by 10 and height by 5 when eating golden fish
if (fish.type === 'goldenFish') {
var sharkGraphics = shark.getChildAt(0);
sharkGraphics.width -= 10;
sharkGraphics.height -= 5;
}
LK.setScore(shark.score);
scoreText.setText("Score: " + shark.score);
// Check if new record achieved
if (shark.score > recordScore) {
recordScore = shark.score;
storage.recordScore = recordScore;
recordScoreText.setText('Record: ' + recordScore);
// Flash record text to highlight new record
LK.effects.flashObject(recordScoreText, 0xFFFF00, 500);
}
LK.getSound('eat').play();
// Remove fish
fish.destroy();
fishes.splice(index, 1);
} else {
// Fish damages shark
shark.takeDamage(5 * fish.danger);
}
}
// Game events
game.move = function (x, y, obj) {
if (!gameActive || !dragNode) return;
// Move shark to touch position
dragNode.x = x;
dragNode.y = y;
// Update shark direction based on movement
if (dragNode.x > dragNode.lastX) {
dragNode.facing = 1;
} else if (dragNode.x < dragNode.lastX) {
dragNode.facing = -1;
}
};
game.down = function (x, y, obj) {
if (!gameActive) return;
dragNode = shark;
game.move(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update
game.update = function () {
// If start screen is active, update it
if (startScreen) {
startScreen.update();
return;
}
if (!gameActive) return;
// Increase difficulty over time
difficultyTimer++;
if (difficultyTimer >= 600) {
// Every 10 seconds
difficulty += 0.1;
maxFishes = Math.min(20, maxFishes + 1);
difficultyTimer = 0;
}
// Update ocean background
if (oceanBackground) {
oceanBackground.update();
}
// Update shark
shark.update();
// Update UI
healthBarFill.width = shark.health / 100 * 200;
oxygenBarFill.width = shark.oxygen / 100 * 200;
// Check if game over
if (shark.health <= 0) {
gameActive = false;
// Check if we need to update the record
if (shark.score > recordScore) {
recordScore = shark.score;
storage.recordScore = recordScore;
recordScoreText.setText('Record: ' + recordScore);
}
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Spawn new entities
spawnTimer++;
if (spawnTimer >= 60) {
// Every second
if (fishes.length < maxFishes) {
spawnFish();
}
if (Math.random() < 0.2 * difficulty) {
spawnObstacle();
}
if (Math.random() < 0.05) {
spawnPowerUp();
}
spawnTimer = 0;
}
// Handle power-up timer
if (powerUpActive) {
powerUpTimer--;
if (powerUpTimer <= 0) {
powerUpActive = false;
shark.speed = 5;
}
}
// Update fishes and check collisions
for (var i = fishes.length - 1; i >= 0; i--) {
var fish = fishes[i];
fish.update();
var id = "fish" + i;
var isIntersecting = shark.intersects(fish);
// Check collision (transition from not intersecting to intersecting)
if (!lastIntersectingFish[id] && isIntersecting) {
handleFishCollision(fish, i);
continue; // Skip further processing if fish was eaten
}
lastIntersectingFish[id] = isIntersecting;
}
// Update obstacles and check collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.update();
if (obstacle.shouldRemove) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
var id = "obstacle" + i;
var isIntersecting = shark.intersects(obstacle);
// Check collision (transition from not intersecting to intersecting)
if (!lastIntersectingObstacle[id] && isIntersecting) {
if (!powerUpActive || powerUpActive && shark.type !== 'invincibility') {
shark.takeDamage(obstacle.damage);
}
}
lastIntersectingObstacle[id] = isIntersecting;
}
// Update power-ups and check collisions
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.update();
if (powerUp.shouldRemove) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
var id = "powerUp" + i;
var isIntersecting = shark.intersects(powerUp);
// Check collision (transition from not intersecting to intersecting)
if (!lastIntersectingPowerUp[id] && isIntersecting) {
// Apply power-up effect
powerUpActive = true;
powerUpTimer = 300; // 5 seconds
if (powerUp.type === 'speed') {
shark.speed = 10;
}
// Increase health by 15 when collecting any power-up
shark.health = Math.min(100, shark.health + 15);
LK.getSound('powerup').play();
LK.effects.flashObject(shark, 0x00ffff, 500);
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
lastIntersectingPowerUp[id] = isIntersecting;
}
};
// Initialize the game
initGame();
realistic pixel shark. In-Game asset. 2d. High contrast. No shadows
realistic pixel gold fish. In-Game asset. 2d. High contrast. No shadows
realistic pixel sea turtle. In-Game asset. 2d. High contrast. No shadows
realistic pixel horizontal jellyfish. In-Game asset. 2d. High contrast. No shadows
Realistic pixel horizontal dolphin. In-Game asset. 2d. High contrast. No shadows
realistic vertical meteor. In-Game asset. 2d. High contrast. No shadows
realistic pixel diver. In-Game asset. 2d. High contrast. No shadows