/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Fish = Container.expand(function () { var self = Container.call(this); // Attach fish asset var fishGraphics = self.attachAsset('fish', { anchorX: 0.5, anchorY: 0.5 }); // Set fish properties self.speed = 5; self.collected = false; // Add some animation self.bobAmount = 20; self.bobSpeed = 0.05; self.startY = 0; self.bobPhase = Math.random() * Math.PI * 2; // Random starting phase self.update = function () { // Move fish to the left self.x -= self.speed; // Bob up and down if (self.startY) { self.bobPhase += self.bobSpeed; self.y = self.startY + Math.sin(self.bobPhase) * self.bobAmount; } else { self.startY = self.y; } }; return self; }); var Ground = Container.expand(function () { var self = Container.call(this); // Attach ground asset var groundGraphics = self.attachAsset('ground', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Game state variables var Penguin = Container.expand(function () { var self = Container.call(this); // Attach penguin asset var penguinGraphics = self.attachAsset('penguin', { anchorX: 0.5, anchorY: 0.5 }); // Physics properties self.velocity = 0; self.gravity = 0.5; self.flapStrength = -10; self.rotation = 0; self.isShielded = false; self.shieldTimer = 0; // Initialize last positions for collision detection self.lastY = 0; self.lastWasColliding = false; // Create shield visual (initially hidden) var shield = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); shield.scale.set(2); self.flap = function () { self.velocity = self.flapStrength; LK.getSound('flap').play(); }; self.activateShield = function (duration) { self.isShielded = true; self.shieldTimer = duration; shield.alpha = 0.7; LK.getSound('powerup').play(); }; self.update = function () { // Store last position self.lastY = self.y; // Apply gravity and update position self.velocity += self.gravity; self.y += self.velocity; // Update rotation based on velocity var targetRotation = Math.min(Math.max(self.velocity * 0.04, -0.5), 0.5); self.rotation += (targetRotation - self.rotation) * 0.1; penguinGraphics.rotation = self.rotation; // Update shield timer if (self.isShielded) { self.shieldTimer--; if (self.shieldTimer <= 0) { self.isShielded = false; shield.alpha = 0; } } }; // Collision check method self.checkCollision = function (object) { return self.intersects(object); }; return self; }); var Pillar = Container.expand(function () { var self = Container.call(this); // Create top and bottom pillars var topPillar = self.attachAsset('pillarTop', { anchorX: 0.5, anchorY: 1.0 }); var bottomPillar = self.attachAsset('pillarBottom', { anchorX: 0.5, anchorY: 0.0 }); // Set pillar properties self.speed = 5; self.passed = false; self.gap = 550; // Gap between pillars // Position the pillars self.setGapPosition = function (yPosition) { topPillar.y = yPosition - self.gap / 2; bottomPillar.y = yPosition + self.gap / 2; }; self.update = function () { // Move pillar to the left self.x -= self.speed; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); // Initialize with default type self.type = "shield"; self.speed = 5; self.collected = false; // Method to set the power-up type self.setType = function (type) { self.type = type; // Remove existing graphic if any while (self.children.length > 0) { self.removeChild(self.children[0]); } // Add new graphic based on type var assetId; if (type === "shield") { assetId = 'shield'; } else if (type === "slowMotion") { assetId = 'slowMotion'; } else if (type === "magnet") { assetId = 'magnet'; } self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Add pulsing animation tween(self.scale, { x: 1.2, y: 1.2 }, { duration: 500, repeat: -1, yoyo: true }); }; self.update = function () { // Move power-up to the left self.x -= self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game state variables var gameStarted = false; var gameOver = false; var score = 0; var highScore = storage.highScore || 0; // Game speed (for slow motion power-up) var gameSpeed = 1; var normalSpeed = 1; var slowMotionSpeed = 0.6; var slowMotionTimer = 0; // Game object arrays var pillars = []; var fishes = []; var powerUps = []; // Magnet power-up variables var magnetActive = false; var magnetTimer = 0; var magnetRange = 300; // Set up the game background game.setBackgroundColor(0x87CEEB); // Sky blue background // Create the penguin var penguin = new Penguin(); penguin.x = 400; penguin.y = 1366; game.addChild(penguin); // Create the ground var ground = new Ground(); ground.x = 1024; ground.y = 2650; game.addChild(ground); // Spawn timers var pillarSpawnTimer = 0; var pillarSpawnInterval = 120; // 2 seconds at 60 FPS var fishSpawnTimer = 0; var powerUpSpawnTimer = 0; // Create score text var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create tap to start text var startTxt = new Text2('TAP TO FLAP', { size: 80, fill: 0xFFFFFF }); startTxt.anchor.set(0.5, 0.5); startTxt.y = 200; LK.gui.center.addChild(startTxt); // Start the background music LK.playMusic('bgMusic', { fade: { start: 0, end: 0.5, duration: 1000 } }); // Handle game input events game.down = function (x, y, obj) { if (!gameOver) { if (!gameStarted) { gameStarted = true; startTxt.visible = false; } penguin.flap(); } }; // Spawn a new pillar function spawnPillar() { var pillar = new Pillar(); pillar.x = 2300; // Just off-screen to the right // Random y position for the gap var minY = 900; var maxY = 2000; var gapY = minY + Math.random() * (maxY - minY); pillar.setGapPosition(gapY); pillars.push(pillar); game.addChild(pillar); } // Spawn a fish function spawnFish() { var fish = new Fish(); fish.x = 2300; // Just off-screen to the right fish.y = 900 + Math.random() * 1000; // Random height fishes.push(fish); game.addChild(fish); } // Spawn a power-up function spawnPowerUp() { var powerUp = new PowerUp(); powerUp.x = 2300; // Just off-screen to the right powerUp.y = 900 + Math.random() * 1000; // Random height // Random power-up type var types = ["shield", "slowMotion", "magnet"]; var type = types[Math.floor(Math.random() * types.length)]; powerUp.setType(type); powerUps.push(powerUp); game.addChild(powerUp); } // Apply power-up effect function applyPowerUp(type) { if (type === "shield") { penguin.activateShield(300); // 5 seconds at 60 FPS } else if (type === "slowMotion") { gameSpeed = slowMotionSpeed; slowMotionTimer = 300; // 5 seconds at 60 FPS LK.getSound('powerup').play(); } else if (type === "magnet") { magnetActive = true; magnetTimer = 300; // 5 seconds at 60 FPS LK.getSound('powerup').play(); } } // Main game update loop game.update = function () { if (!gameStarted) return; // Update game speed (slow motion power-up) if (slowMotionTimer > 0) { slowMotionTimer--; if (slowMotionTimer <= 0) { gameSpeed = normalSpeed; } } // Update magnet power-up if (magnetActive) { magnetTimer--; if (magnetTimer <= 0) { magnetActive = false; } } // Update penguin penguin.update(); // Check if penguin hits the ground if (!gameOver && penguin.y > 2600) { endGame(); } // Check if penguin hits the ceiling if (!gameOver && penguin.y < 100) { penguin.y = 100; penguin.velocity = 0; } // Spawn pillars pillarSpawnTimer++; if (pillarSpawnTimer >= pillarSpawnInterval * gameSpeed) { spawnPillar(); pillarSpawnTimer = 0; } // Spawn fishes fishSpawnTimer++; if (fishSpawnTimer >= 240 * gameSpeed) { // 4 seconds spawnFish(); fishSpawnTimer = 0; } // Spawn power-ups (less frequently) powerUpSpawnTimer++; if (powerUpSpawnTimer >= 600 * gameSpeed) { // 10 seconds spawnPowerUp(); powerUpSpawnTimer = 0; } // Update pillars for (var i = pillars.length - 1; i >= 0; i--) { var pillar = pillars[i]; pillar.speed = 5 * gameSpeed; pillar.update(); // Check for collisions if not game over and not shielded if (!gameOver && !penguin.isShielded) { // Check collision with top pillar if (penguin.checkCollision(pillar.children[0])) { endGame(); break; } // Check collision with bottom pillar if (penguin.checkCollision(pillar.children[1])) { endGame(); break; } } // Check if penguin passed the pillar if (!pillar.passed && pillar.x < penguin.x) { score++; scoreTxt.setText(score.toString()); pillar.passed = true; } // Remove pillars that are off-screen if (pillar.x < -200) { pillar.destroy(); pillars.splice(i, 1); } } // Update fishes for (var j = fishes.length - 1; j >= 0; j--) { var fish = fishes[j]; fish.speed = 5 * gameSpeed; fish.update(); // Apply magnet effect if active if (magnetActive) { var dx = penguin.x - fish.x; var dy = penguin.y - fish.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < magnetRange) { // Move fish toward penguin fish.x += dx * 0.1; fish.y += dy * 0.1; } } // Check if penguin collected the fish if (!fish.collected && penguin.checkCollision(fish)) { fish.collected = true; fish.alpha = 0; // Award points score += 3; scoreTxt.setText(score.toString()); // Play collect sound LK.getSound('collect').play(); // Show a +3 text effect var plusText = new Text2('+3', { size: 60, fill: 0xFFFF00 }); plusText.x = fish.x; plusText.y = fish.y; plusText.anchor.set(0.5, 0.5); game.addChild(plusText); // Animate and remove the text tween(plusText, { y: plusText.y - 100, alpha: 0 }, { duration: 1000, onComplete: function onComplete() { plusText.destroy(); } }); } // Remove fishes that are off-screen if (fish.x < -100) { fish.destroy(); fishes.splice(j, 1); } } // Update power-ups for (var k = powerUps.length - 1; k >= 0; k--) { var powerUp = powerUps[k]; powerUp.speed = 5 * gameSpeed; powerUp.update(); // Check if penguin collected the power-up if (!powerUp.collected && penguin.checkCollision(powerUp)) { powerUp.collected = true; powerUp.alpha = 0; // Apply the power-up effect applyPowerUp(powerUp.type); } // Remove power-ups that are off-screen if (powerUp.x < -100) { powerUp.destroy(); powerUps.splice(k, 1); } } }; // End the game function endGame() { if (gameOver) return; gameOver = true; LK.getSound('crash').play(); // Flash the screen LK.effects.flashScreen(0xFF0000, 500); // Update high score if (score > highScore) { highScore = score; storage.highScore = highScore; } // Show game over screen LK.setTimeout(function () { LK.showGameOver(); }, 1000); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Fish = Container.expand(function () {
var self = Container.call(this);
// Attach fish asset
var fishGraphics = self.attachAsset('fish', {
anchorX: 0.5,
anchorY: 0.5
});
// Set fish properties
self.speed = 5;
self.collected = false;
// Add some animation
self.bobAmount = 20;
self.bobSpeed = 0.05;
self.startY = 0;
self.bobPhase = Math.random() * Math.PI * 2; // Random starting phase
self.update = function () {
// Move fish to the left
self.x -= self.speed;
// Bob up and down
if (self.startY) {
self.bobPhase += self.bobSpeed;
self.y = self.startY + Math.sin(self.bobPhase) * self.bobAmount;
} else {
self.startY = self.y;
}
};
return self;
});
var Ground = Container.expand(function () {
var self = Container.call(this);
// Attach ground asset
var groundGraphics = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Game state variables
var Penguin = Container.expand(function () {
var self = Container.call(this);
// Attach penguin asset
var penguinGraphics = self.attachAsset('penguin', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.velocity = 0;
self.gravity = 0.5;
self.flapStrength = -10;
self.rotation = 0;
self.isShielded = false;
self.shieldTimer = 0;
// Initialize last positions for collision detection
self.lastY = 0;
self.lastWasColliding = false;
// Create shield visual (initially hidden)
var shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
shield.scale.set(2);
self.flap = function () {
self.velocity = self.flapStrength;
LK.getSound('flap').play();
};
self.activateShield = function (duration) {
self.isShielded = true;
self.shieldTimer = duration;
shield.alpha = 0.7;
LK.getSound('powerup').play();
};
self.update = function () {
// Store last position
self.lastY = self.y;
// Apply gravity and update position
self.velocity += self.gravity;
self.y += self.velocity;
// Update rotation based on velocity
var targetRotation = Math.min(Math.max(self.velocity * 0.04, -0.5), 0.5);
self.rotation += (targetRotation - self.rotation) * 0.1;
penguinGraphics.rotation = self.rotation;
// Update shield timer
if (self.isShielded) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.isShielded = false;
shield.alpha = 0;
}
}
};
// Collision check method
self.checkCollision = function (object) {
return self.intersects(object);
};
return self;
});
var Pillar = Container.expand(function () {
var self = Container.call(this);
// Create top and bottom pillars
var topPillar = self.attachAsset('pillarTop', {
anchorX: 0.5,
anchorY: 1.0
});
var bottomPillar = self.attachAsset('pillarBottom', {
anchorX: 0.5,
anchorY: 0.0
});
// Set pillar properties
self.speed = 5;
self.passed = false;
self.gap = 550; // Gap between pillars
// Position the pillars
self.setGapPosition = function (yPosition) {
topPillar.y = yPosition - self.gap / 2;
bottomPillar.y = yPosition + self.gap / 2;
};
self.update = function () {
// Move pillar to the left
self.x -= self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Initialize with default type
self.type = "shield";
self.speed = 5;
self.collected = false;
// Method to set the power-up type
self.setType = function (type) {
self.type = type;
// Remove existing graphic if any
while (self.children.length > 0) {
self.removeChild(self.children[0]);
}
// Add new graphic based on type
var assetId;
if (type === "shield") {
assetId = 'shield';
} else if (type === "slowMotion") {
assetId = 'slowMotion';
} else if (type === "magnet") {
assetId = 'magnet';
}
self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add pulsing animation
tween(self.scale, {
x: 1.2,
y: 1.2
}, {
duration: 500,
repeat: -1,
yoyo: true
});
};
self.update = function () {
// Move power-up to the left
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var gameStarted = false;
var gameOver = false;
var score = 0;
var highScore = storage.highScore || 0;
// Game speed (for slow motion power-up)
var gameSpeed = 1;
var normalSpeed = 1;
var slowMotionSpeed = 0.6;
var slowMotionTimer = 0;
// Game object arrays
var pillars = [];
var fishes = [];
var powerUps = [];
// Magnet power-up variables
var magnetActive = false;
var magnetTimer = 0;
var magnetRange = 300;
// Set up the game background
game.setBackgroundColor(0x87CEEB); // Sky blue background
// Create the penguin
var penguin = new Penguin();
penguin.x = 400;
penguin.y = 1366;
game.addChild(penguin);
// Create the ground
var ground = new Ground();
ground.x = 1024;
ground.y = 2650;
game.addChild(ground);
// Spawn timers
var pillarSpawnTimer = 0;
var pillarSpawnInterval = 120; // 2 seconds at 60 FPS
var fishSpawnTimer = 0;
var powerUpSpawnTimer = 0;
// Create score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create tap to start text
var startTxt = new Text2('TAP TO FLAP', {
size: 80,
fill: 0xFFFFFF
});
startTxt.anchor.set(0.5, 0.5);
startTxt.y = 200;
LK.gui.center.addChild(startTxt);
// Start the background music
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 0.5,
duration: 1000
}
});
// Handle game input events
game.down = function (x, y, obj) {
if (!gameOver) {
if (!gameStarted) {
gameStarted = true;
startTxt.visible = false;
}
penguin.flap();
}
};
// Spawn a new pillar
function spawnPillar() {
var pillar = new Pillar();
pillar.x = 2300; // Just off-screen to the right
// Random y position for the gap
var minY = 900;
var maxY = 2000;
var gapY = minY + Math.random() * (maxY - minY);
pillar.setGapPosition(gapY);
pillars.push(pillar);
game.addChild(pillar);
}
// Spawn a fish
function spawnFish() {
var fish = new Fish();
fish.x = 2300; // Just off-screen to the right
fish.y = 900 + Math.random() * 1000; // Random height
fishes.push(fish);
game.addChild(fish);
}
// Spawn a power-up
function spawnPowerUp() {
var powerUp = new PowerUp();
powerUp.x = 2300; // Just off-screen to the right
powerUp.y = 900 + Math.random() * 1000; // Random height
// Random power-up type
var types = ["shield", "slowMotion", "magnet"];
var type = types[Math.floor(Math.random() * types.length)];
powerUp.setType(type);
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Apply power-up effect
function applyPowerUp(type) {
if (type === "shield") {
penguin.activateShield(300); // 5 seconds at 60 FPS
} else if (type === "slowMotion") {
gameSpeed = slowMotionSpeed;
slowMotionTimer = 300; // 5 seconds at 60 FPS
LK.getSound('powerup').play();
} else if (type === "magnet") {
magnetActive = true;
magnetTimer = 300; // 5 seconds at 60 FPS
LK.getSound('powerup').play();
}
}
// Main game update loop
game.update = function () {
if (!gameStarted) return;
// Update game speed (slow motion power-up)
if (slowMotionTimer > 0) {
slowMotionTimer--;
if (slowMotionTimer <= 0) {
gameSpeed = normalSpeed;
}
}
// Update magnet power-up
if (magnetActive) {
magnetTimer--;
if (magnetTimer <= 0) {
magnetActive = false;
}
}
// Update penguin
penguin.update();
// Check if penguin hits the ground
if (!gameOver && penguin.y > 2600) {
endGame();
}
// Check if penguin hits the ceiling
if (!gameOver && penguin.y < 100) {
penguin.y = 100;
penguin.velocity = 0;
}
// Spawn pillars
pillarSpawnTimer++;
if (pillarSpawnTimer >= pillarSpawnInterval * gameSpeed) {
spawnPillar();
pillarSpawnTimer = 0;
}
// Spawn fishes
fishSpawnTimer++;
if (fishSpawnTimer >= 240 * gameSpeed) {
// 4 seconds
spawnFish();
fishSpawnTimer = 0;
}
// Spawn power-ups (less frequently)
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= 600 * gameSpeed) {
// 10 seconds
spawnPowerUp();
powerUpSpawnTimer = 0;
}
// Update pillars
for (var i = pillars.length - 1; i >= 0; i--) {
var pillar = pillars[i];
pillar.speed = 5 * gameSpeed;
pillar.update();
// Check for collisions if not game over and not shielded
if (!gameOver && !penguin.isShielded) {
// Check collision with top pillar
if (penguin.checkCollision(pillar.children[0])) {
endGame();
break;
}
// Check collision with bottom pillar
if (penguin.checkCollision(pillar.children[1])) {
endGame();
break;
}
}
// Check if penguin passed the pillar
if (!pillar.passed && pillar.x < penguin.x) {
score++;
scoreTxt.setText(score.toString());
pillar.passed = true;
}
// Remove pillars that are off-screen
if (pillar.x < -200) {
pillar.destroy();
pillars.splice(i, 1);
}
}
// Update fishes
for (var j = fishes.length - 1; j >= 0; j--) {
var fish = fishes[j];
fish.speed = 5 * gameSpeed;
fish.update();
// Apply magnet effect if active
if (magnetActive) {
var dx = penguin.x - fish.x;
var dy = penguin.y - fish.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < magnetRange) {
// Move fish toward penguin
fish.x += dx * 0.1;
fish.y += dy * 0.1;
}
}
// Check if penguin collected the fish
if (!fish.collected && penguin.checkCollision(fish)) {
fish.collected = true;
fish.alpha = 0;
// Award points
score += 3;
scoreTxt.setText(score.toString());
// Play collect sound
LK.getSound('collect').play();
// Show a +3 text effect
var plusText = new Text2('+3', {
size: 60,
fill: 0xFFFF00
});
plusText.x = fish.x;
plusText.y = fish.y;
plusText.anchor.set(0.5, 0.5);
game.addChild(plusText);
// Animate and remove the text
tween(plusText, {
y: plusText.y - 100,
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
plusText.destroy();
}
});
}
// Remove fishes that are off-screen
if (fish.x < -100) {
fish.destroy();
fishes.splice(j, 1);
}
}
// Update power-ups
for (var k = powerUps.length - 1; k >= 0; k--) {
var powerUp = powerUps[k];
powerUp.speed = 5 * gameSpeed;
powerUp.update();
// Check if penguin collected the power-up
if (!powerUp.collected && penguin.checkCollision(powerUp)) {
powerUp.collected = true;
powerUp.alpha = 0;
// Apply the power-up effect
applyPowerUp(powerUp.type);
}
// Remove power-ups that are off-screen
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(k, 1);
}
}
};
// End the game
function endGame() {
if (gameOver) return;
gameOver = true;
LK.getSound('crash').play();
// Flash the screen
LK.effects.flashScreen(0xFF0000, 500);
// Update high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
}
// Show game over screen
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}