/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BeatIndicator = Container.expand(function () { var self = Container.call(this); var indicatorGraphics = self.attachAsset('beatIndicator', { anchorX: 0.5, anchorY: 0.5 }); self.maxScale = 1.5; self.minScale = 0.8; self.pulse = function () { indicatorGraphics.scaleX = self.maxScale; indicatorGraphics.scaleY = self.maxScale; tween(indicatorGraphics, { scaleX: self.minScale, scaleY: self.minScale }, { duration: 200, easing: tween.easeOut }); }; return self; }); var Bubble = Container.expand(function () { var self = Container.call(this); var bubbleGraphics = self.attachAsset('bubble', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.floatSpeed = -1; self.update = function () { self.x += self.speed; self.y += self.floatSpeed; bubbleGraphics.alpha = Math.max(0, bubbleGraphics.alpha - 0.005); if (bubbleGraphics.alpha <= 0) { self.destroy(); } }; return self; }); var Fish = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('fish', { anchorX: 0.5, anchorY: 0.5 }); self.velocity = 0; self.gravity = 0.8; self.bounceForce = -15; self.isAlive = true; self.bounce = function () { if (self.isAlive) { self.velocity = self.bounceForce; LK.getSound('bounce').play(); // Add bounce animation tween(fishGraphics, { rotation: -0.3 }, { duration: 150 }); tween(fishGraphics, { rotation: 0 }, { duration: 150, delay: 150 }); } }; self.update = function () { if (self.isAlive) { self.velocity += self.gravity; self.y += self.velocity; // Boundary checking if (self.y < 100) { self.y = 100; self.velocity = 0; } if (self.y > 2632) { self.y = 2632; self.velocity = 0; } // Rotation based on velocity fishGraphics.rotation = Math.min(Math.max(self.velocity * 0.03, -0.5), 0.5); } }; 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 = -8; self.passed = false; self.update = function () { self.x += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x001122 }); /**** * Game Code ****/ // Game variables var fish; var obstacles = []; var bubbles = []; var beatIndicator; var scoreTxt; var multiplierTxt; var gameSpeed = 1; var beatTimer = 0; var beatInterval = 60; // 60 ticks = 1 second at 60fps var lastBeatTime = 0; var scoreMultiplier = 1; var distanceScore = 0; var perfectBeatWindow = 10; // ticks var gameStarted = false; // Initialize UI scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); multiplierTxt = new Text2('x1', { size: 60, fill: 0xFFFF00 }); multiplierTxt.anchor.set(1, 0); LK.gui.topRight.addChild(multiplierTxt); // Initialize fish fish = game.addChild(new Fish()); fish.x = 400; fish.y = 1366; // Initialize beat indicator beatIndicator = game.addChild(new BeatIndicator()); beatIndicator.x = 200; beatIndicator.y = 200; // Start background music LK.playMusic('bgmusic'); // Spawn obstacle function function spawnObstacle() { var obstacle = new Obstacle(); obstacle.x = 2200; // Random height with gaps var gapSize = 400; var gapCenter = 600 + Math.random() * 1500; // Create top obstacle var topObstacle = game.addChild(new Obstacle()); topObstacle.x = 2200; topObstacle.y = gapCenter - gapSize / 2 - 100; obstacles.push(topObstacle); // Create bottom obstacle var bottomObstacle = game.addChild(new Obstacle()); bottomObstacle.x = 2200; bottomObstacle.y = gapCenter + gapSize / 2 + 100; obstacles.push(bottomObstacle); } // Spawn bubble function function spawnBubble() { var bubble = game.addChild(new Bubble()); bubble.x = 2100 + Math.random() * 200; bubble.y = 500 + Math.random() * 1500; bubbles.push(bubble); } // Handle tap input game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; return; } // Check if tap is in sync with beat var timeSinceBeat = Math.abs(beatTimer - lastBeatTime); if (timeSinceBeat <= perfectBeatWindow) { scoreMultiplier = Math.min(scoreMultiplier + 0.5, 5); LK.effects.flashObject(beatIndicator, 0x00ff00, 300); } else { scoreMultiplier = Math.max(scoreMultiplier - 0.2, 1); } fish.bounce(); multiplierTxt.setText('x' + scoreMultiplier.toFixed(1)); }; // Main game loop game.update = function () { if (!gameStarted) return; beatTimer++; // Beat detection and obstacle spawning if (beatTimer % beatInterval === 0) { lastBeatTime = beatTimer; beatIndicator.pulse(); // Spawn obstacles on beat if (Math.random() < 0.7) { spawnObstacle(); } // Increase tempo gradually if (beatInterval > 30) { beatInterval -= 0.1; } } // Spawn bubbles randomly if (Math.random() < 0.03) { spawnBubble(); } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; // Check collision if (fish.intersects(obstacle) && fish.isAlive) { fish.isAlive = false; LK.getSound('hit').play(); LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } // Remove off-screen obstacles and award points if (obstacle.x < -100) { if (!obstacle.passed) { obstacle.passed = true; distanceScore += 10 * scoreMultiplier; LK.setScore(Math.floor(distanceScore)); scoreTxt.setText(LK.getScore()); } obstacle.destroy(); obstacles.splice(i, 1); } } // Update bubbles for (var j = bubbles.length - 1; j >= 0; j--) { var bubble = bubbles[j]; if (bubble.x < -50 || bubble.y < -50) { bubble.destroy(); bubbles.splice(j, 1); } } // Continuous distance scoring if (LK.ticks % 10 === 0) { distanceScore += 1 * scoreMultiplier; LK.setScore(Math.floor(distanceScore)); scoreTxt.setText(LK.getScore()); } // Check if fish goes off screen if (fish.y > 2732 || fish.y < 0) { fish.isAlive = false; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BeatIndicator = Container.expand(function () {
var self = Container.call(this);
var indicatorGraphics = self.attachAsset('beatIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxScale = 1.5;
self.minScale = 0.8;
self.pulse = function () {
indicatorGraphics.scaleX = self.maxScale;
indicatorGraphics.scaleY = self.maxScale;
tween(indicatorGraphics, {
scaleX: self.minScale,
scaleY: self.minScale
}, {
duration: 200,
easing: tween.easeOut
});
};
return self;
});
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -2;
self.floatSpeed = -1;
self.update = function () {
self.x += self.speed;
self.y += self.floatSpeed;
bubbleGraphics.alpha = Math.max(0, bubbleGraphics.alpha - 0.005);
if (bubbleGraphics.alpha <= 0) {
self.destroy();
}
};
return self;
});
var Fish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('fish', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = 0;
self.gravity = 0.8;
self.bounceForce = -15;
self.isAlive = true;
self.bounce = function () {
if (self.isAlive) {
self.velocity = self.bounceForce;
LK.getSound('bounce').play();
// Add bounce animation
tween(fishGraphics, {
rotation: -0.3
}, {
duration: 150
});
tween(fishGraphics, {
rotation: 0
}, {
duration: 150,
delay: 150
});
}
};
self.update = function () {
if (self.isAlive) {
self.velocity += self.gravity;
self.y += self.velocity;
// Boundary checking
if (self.y < 100) {
self.y = 100;
self.velocity = 0;
}
if (self.y > 2632) {
self.y = 2632;
self.velocity = 0;
}
// Rotation based on velocity
fishGraphics.rotation = Math.min(Math.max(self.velocity * 0.03, -0.5), 0.5);
}
};
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 = -8;
self.passed = false;
self.update = function () {
self.x += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Game variables
var fish;
var obstacles = [];
var bubbles = [];
var beatIndicator;
var scoreTxt;
var multiplierTxt;
var gameSpeed = 1;
var beatTimer = 0;
var beatInterval = 60; // 60 ticks = 1 second at 60fps
var lastBeatTime = 0;
var scoreMultiplier = 1;
var distanceScore = 0;
var perfectBeatWindow = 10; // ticks
var gameStarted = false;
// Initialize UI
scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
multiplierTxt = new Text2('x1', {
size: 60,
fill: 0xFFFF00
});
multiplierTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(multiplierTxt);
// Initialize fish
fish = game.addChild(new Fish());
fish.x = 400;
fish.y = 1366;
// Initialize beat indicator
beatIndicator = game.addChild(new BeatIndicator());
beatIndicator.x = 200;
beatIndicator.y = 200;
// Start background music
LK.playMusic('bgmusic');
// Spawn obstacle function
function spawnObstacle() {
var obstacle = new Obstacle();
obstacle.x = 2200;
// Random height with gaps
var gapSize = 400;
var gapCenter = 600 + Math.random() * 1500;
// Create top obstacle
var topObstacle = game.addChild(new Obstacle());
topObstacle.x = 2200;
topObstacle.y = gapCenter - gapSize / 2 - 100;
obstacles.push(topObstacle);
// Create bottom obstacle
var bottomObstacle = game.addChild(new Obstacle());
bottomObstacle.x = 2200;
bottomObstacle.y = gapCenter + gapSize / 2 + 100;
obstacles.push(bottomObstacle);
}
// Spawn bubble function
function spawnBubble() {
var bubble = game.addChild(new Bubble());
bubble.x = 2100 + Math.random() * 200;
bubble.y = 500 + Math.random() * 1500;
bubbles.push(bubble);
}
// Handle tap input
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
return;
}
// Check if tap is in sync with beat
var timeSinceBeat = Math.abs(beatTimer - lastBeatTime);
if (timeSinceBeat <= perfectBeatWindow) {
scoreMultiplier = Math.min(scoreMultiplier + 0.5, 5);
LK.effects.flashObject(beatIndicator, 0x00ff00, 300);
} else {
scoreMultiplier = Math.max(scoreMultiplier - 0.2, 1);
}
fish.bounce();
multiplierTxt.setText('x' + scoreMultiplier.toFixed(1));
};
// Main game loop
game.update = function () {
if (!gameStarted) return;
beatTimer++;
// Beat detection and obstacle spawning
if (beatTimer % beatInterval === 0) {
lastBeatTime = beatTimer;
beatIndicator.pulse();
// Spawn obstacles on beat
if (Math.random() < 0.7) {
spawnObstacle();
}
// Increase tempo gradually
if (beatInterval > 30) {
beatInterval -= 0.1;
}
}
// Spawn bubbles randomly
if (Math.random() < 0.03) {
spawnBubble();
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Check collision
if (fish.intersects(obstacle) && fish.isAlive) {
fish.isAlive = false;
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Remove off-screen obstacles and award points
if (obstacle.x < -100) {
if (!obstacle.passed) {
obstacle.passed = true;
distanceScore += 10 * scoreMultiplier;
LK.setScore(Math.floor(distanceScore));
scoreTxt.setText(LK.getScore());
}
obstacle.destroy();
obstacles.splice(i, 1);
}
}
// Update bubbles
for (var j = bubbles.length - 1; j >= 0; j--) {
var bubble = bubbles[j];
if (bubble.x < -50 || bubble.y < -50) {
bubble.destroy();
bubbles.splice(j, 1);
}
}
// Continuous distance scoring
if (LK.ticks % 10 === 0) {
distanceScore += 1 * scoreMultiplier;
LK.setScore(Math.floor(distanceScore));
scoreTxt.setText(LK.getScore());
}
// Check if fish goes off screen
if (fish.y > 2732 || fish.y < 0) {
fish.isAlive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
};
Shark. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Floppy Fish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Water ripple from above. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Bubble. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows