/****
* 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