/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var EnemySubmarine = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemySubmarine', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.points = 10; self.shootTimer = 0; self.shootInterval = 300; // Shoot every 5 seconds self.update = function () { self.y += self.speed; self.shootTimer++; }; return self; }); var EnemyTorpedo = Container.expand(function () { var self = Container.call(this); var torpedoGraphics = self.attachAsset('enemyTorpedo', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.update = function () { self.x += self.speedX; self.y += self.speedY; }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); var explosionGraphics = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5 }); self.lifetime = 0; self.maxLifetime = 30; // 30 frames = 0.5 seconds self.update = function () { self.lifetime++; // Scale up and fade out over time var progress = self.lifetime / self.maxLifetime; explosionGraphics.scaleX = 1 + progress * 2; explosionGraphics.scaleY = 1 + progress * 2; explosionGraphics.alpha = 1 - progress; // Change color from orange to red to dark red if (progress < 0.3) { explosionGraphics.tint = 0xFF4500; // Orange } else if (progress < 0.7) { explosionGraphics.tint = 0xFF0000; // Red } else { explosionGraphics.tint = 0x8B0000; // Dark red } }; return self; }); var SeaCreature = Container.expand(function () { var self = Container.call(this); var creatureGraphics = self.attachAsset('seaCreature', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.points = 20; self.update = function () { self.y += self.speed; // Add slight horizontal movement for more dynamic behavior self.x += Math.sin(LK.ticks * 0.05) * 0.5; }; return self; }); var Submarine = Container.expand(function () { var self = Container.call(this); var submarineGraphics = self.attachAsset('submarine', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Torpedo = Container.expand(function () { var self = Container.call(this); var torpedoGraphics = self.attachAsset('torpedo', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -8; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000080 }); /**** * Game Code ****/ // Add underwater background var background = game.addChild(LK.getAsset('underwaterBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Game variables var submarine; var torpedoes = []; var enemyTorpedoes = []; var enemies = []; var dragNode = null; var spawnTimer = 0; var difficultyLevel = 1; var enemySpawnRate = 120; // Initial spawn rate (ticks between spawns) // Create submarine submarine = game.addChild(new Submarine()); submarine.x = 2048 / 2; submarine.y = 2732 - 200; // Create score display var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.setText(LK.getScore()); // Create high score display var highScore = storage.highScore || 0; var highScoreTxt = new Text2('Best: ' + highScore, { size: 60, fill: 0xFFFF00 }); highScoreTxt.anchor.set(1, 0); highScoreTxt.y = 120; LK.gui.topRight.addChild(highScoreTxt); // Handle submarine movement with soft swipe control var targetX = submarine.x; var targetY = submarine.y; var swipeStartX = 0; var swipeStartY = 0; var isSwipping = false; function handleMove(x, y, obj) { if (dragNode && isSwipping) { // Calculate swipe delta var deltaX = x - swipeStartX; var deltaY = y - swipeStartY; // Update target position based on swipe delta targetX = Math.max(60, Math.min(2048 - 60, targetX + deltaX * 0.5)); targetY = Math.max(100, Math.min(2732 - 100, targetY + deltaY * 0.5)); // Update swipe start position for continuous movement swipeStartX = x; swipeStartY = y; } } game.move = handleMove; game.down = function (x, y, obj) { dragNode = submarine; swipeStartX = x; swipeStartY = y; isSwipping = true; }; game.up = function (x, y, obj) { dragNode = null; isSwipping = false; }; // Spawn enemy function function spawnEnemy() { var enemyType = Math.random(); var enemy; if (enemyType < 0.6) { enemy = new EnemySubmarine(); } else { enemy = new SeaCreature(); } enemy.x = Math.random() * (2048 - 100) + 50; enemy.y = -50; enemy.lastY = enemy.y; enemy.lastIntersecting = false; enemy.hitCount = 0; // Track hits taken, enemy dies after 2 hits enemies.push(enemy); game.addChild(enemy); } // Main game update loop game.update = function () { // Smooth submarine movement toward target position var lerpSpeed = 0.15; submarine.x += (targetX - submarine.x) * lerpSpeed; submarine.y += (targetY - submarine.y) * lerpSpeed; spawnTimer++; // Spawn enemies based on difficulty if (spawnTimer >= enemySpawnRate) { spawnEnemy(); spawnTimer = 0; // Increase difficulty over time if (LK.ticks % 1800 == 0) { // Every 30 seconds difficultyLevel++; enemySpawnRate = Math.max(30, enemySpawnRate - 10); } } // Fire torpedoes automatically if (LK.ticks % 60 == 0) { var torpedo = new Torpedo(); torpedo.x = submarine.x; torpedo.y = submarine.y - 40; torpedo.lastY = torpedo.y; torpedo.lastIntersecting = false; torpedoes.push(torpedo); game.addChild(torpedo); LK.getSound('torpedo_fire').play(); } // Update and check torpedoes for (var t = torpedoes.length - 1; t >= 0; t--) { var torpedo = torpedoes[t]; // Remove torpedoes that go off-screen if (torpedo.lastY >= -50 && torpedo.y < -50) { torpedo.destroy(); torpedoes.splice(t, 1); continue; } // Check torpedo-enemy collisions var torpedoHit = false; for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; var currentIntersecting = torpedo.intersects(enemy); if (!torpedo.lastIntersecting && currentIntersecting) { // Torpedo hit enemy enemy.hitCount++; // Create explosion effect var explosion = new Explosion(); explosion.x = enemy.x; explosion.y = enemy.y; explosion.lastLifetime = 0; game.addChild(explosion); LK.getSound('explosion').play(); // Remove torpedo immediately torpedo.destroy(); torpedoes.splice(t, 1); // Check if enemy should die (after 2 hits) if (enemy.hitCount >= 2) { LK.setScore(LK.getScore() + enemy.points); scoreTxt.setText(LK.getScore()); enemy.destroy(); enemies.splice(e, 1); } torpedoHit = true; break; } } if (!torpedoHit) { torpedo.lastY = torpedo.y; torpedo.lastIntersecting = false; } } // Update and check enemies for (var e = enemies.length - 1; e >= 0; e--) { var enemy = enemies[e]; // Remove enemies that go off-screen if (enemy.lastY <= 2732 + 50 && enemy.y > 2732 + 50) { enemy.destroy(); enemies.splice(e, 1); continue; } // Enemy shooting logic (only for EnemySubmarine) - limit to max 8 enemy torpedoes if (enemy.shootTimer && enemy.shootTimer >= enemy.shootInterval && enemyTorpedoes.length < 8) { var enemyTorpedo = new EnemyTorpedo(); enemyTorpedo.x = enemy.x; enemyTorpedo.y = enemy.y + 40; // Calculate direction toward submarine var deltaX = submarine.x - enemyTorpedo.x; var deltaY = submarine.y - enemyTorpedo.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); var speed = 15; enemyTorpedo.speedX = deltaX / distance * speed; enemyTorpedo.speedY = deltaY / distance * speed; enemyTorpedo.lastY = enemyTorpedo.y; enemyTorpedo.lastIntersecting = false; enemyTorpedoes.push(enemyTorpedo); game.addChild(enemyTorpedo); enemy.shootTimer = 0; } // Check submarine-enemy collision var currentIntersecting = submarine.intersects(enemy); if (!enemy.lastIntersecting && currentIntersecting) { // Game Over LK.effects.flashScreen(0xFF0000, 1000); // Update high score if (LK.getScore() > highScore) { storage.highScore = LK.getScore(); } LK.showGameOver(); return; } enemy.lastY = enemy.y; enemy.lastIntersecting = currentIntersecting; } // Update and check enemy torpedoes for (var et = enemyTorpedoes.length - 1; et >= 0; et--) { var enemyTorpedo = enemyTorpedoes[et]; // Remove enemy torpedoes that go off-screen if (enemyTorpedo.x < -50 || enemyTorpedo.x > 2098 || enemyTorpedo.y < -50 || enemyTorpedo.y > 2782) { enemyTorpedo.destroy(); enemyTorpedoes.splice(et, 1); continue; } // Check enemy torpedo-submarine collision var currentIntersecting = submarine.intersects(enemyTorpedo); if (!enemyTorpedo.lastIntersecting && currentIntersecting) { // Game Over LK.effects.flashScreen(0xFF0000, 1000); // Update high score if (LK.getScore() > highScore) { storage.highScore = LK.getScore(); } LK.showGameOver(); return; } enemyTorpedo.lastY = enemyTorpedo.y; enemyTorpedo.lastIntersecting = currentIntersecting; } // Update and cleanup explosions for (var ex = game.children.length - 1; ex >= 0; ex--) { var child = game.children[ex]; if (child instanceof Explosion) { if (child.lifetime >= child.maxLifetime) { child.destroy(); } } } }; // Start background music LK.playMusic('underwater_ambient');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var EnemySubmarine = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemySubmarine', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.points = 10;
self.shootTimer = 0;
self.shootInterval = 300; // Shoot every 5 seconds
self.update = function () {
self.y += self.speed;
self.shootTimer++;
};
return self;
});
var EnemyTorpedo = Container.expand(function () {
var self = Container.call(this);
var torpedoGraphics = self.attachAsset('enemyTorpedo', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 0;
self.maxLifetime = 30; // 30 frames = 0.5 seconds
self.update = function () {
self.lifetime++;
// Scale up and fade out over time
var progress = self.lifetime / self.maxLifetime;
explosionGraphics.scaleX = 1 + progress * 2;
explosionGraphics.scaleY = 1 + progress * 2;
explosionGraphics.alpha = 1 - progress;
// Change color from orange to red to dark red
if (progress < 0.3) {
explosionGraphics.tint = 0xFF4500; // Orange
} else if (progress < 0.7) {
explosionGraphics.tint = 0xFF0000; // Red
} else {
explosionGraphics.tint = 0x8B0000; // Dark red
}
};
return self;
});
var SeaCreature = Container.expand(function () {
var self = Container.call(this);
var creatureGraphics = self.attachAsset('seaCreature', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.points = 20;
self.update = function () {
self.y += self.speed;
// Add slight horizontal movement for more dynamic behavior
self.x += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var Submarine = Container.expand(function () {
var self = Container.call(this);
var submarineGraphics = self.attachAsset('submarine', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Torpedo = Container.expand(function () {
var self = Container.call(this);
var torpedoGraphics = self.attachAsset('torpedo', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -8;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000080
});
/****
* Game Code
****/
// Add underwater background
var background = game.addChild(LK.getAsset('underwaterBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Game variables
var submarine;
var torpedoes = [];
var enemyTorpedoes = [];
var enemies = [];
var dragNode = null;
var spawnTimer = 0;
var difficultyLevel = 1;
var enemySpawnRate = 120; // Initial spawn rate (ticks between spawns)
// Create submarine
submarine = game.addChild(new Submarine());
submarine.x = 2048 / 2;
submarine.y = 2732 - 200;
// Create score display
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.setText(LK.getScore());
// Create high score display
var highScore = storage.highScore || 0;
var highScoreTxt = new Text2('Best: ' + highScore, {
size: 60,
fill: 0xFFFF00
});
highScoreTxt.anchor.set(1, 0);
highScoreTxt.y = 120;
LK.gui.topRight.addChild(highScoreTxt);
// Handle submarine movement with soft swipe control
var targetX = submarine.x;
var targetY = submarine.y;
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipping = false;
function handleMove(x, y, obj) {
if (dragNode && isSwipping) {
// Calculate swipe delta
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
// Update target position based on swipe delta
targetX = Math.max(60, Math.min(2048 - 60, targetX + deltaX * 0.5));
targetY = Math.max(100, Math.min(2732 - 100, targetY + deltaY * 0.5));
// Update swipe start position for continuous movement
swipeStartX = x;
swipeStartY = y;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = submarine;
swipeStartX = x;
swipeStartY = y;
isSwipping = true;
};
game.up = function (x, y, obj) {
dragNode = null;
isSwipping = false;
};
// Spawn enemy function
function spawnEnemy() {
var enemyType = Math.random();
var enemy;
if (enemyType < 0.6) {
enemy = new EnemySubmarine();
} else {
enemy = new SeaCreature();
}
enemy.x = Math.random() * (2048 - 100) + 50;
enemy.y = -50;
enemy.lastY = enemy.y;
enemy.lastIntersecting = false;
enemy.hitCount = 0; // Track hits taken, enemy dies after 2 hits
enemies.push(enemy);
game.addChild(enemy);
}
// Main game update loop
game.update = function () {
// Smooth submarine movement toward target position
var lerpSpeed = 0.15;
submarine.x += (targetX - submarine.x) * lerpSpeed;
submarine.y += (targetY - submarine.y) * lerpSpeed;
spawnTimer++;
// Spawn enemies based on difficulty
if (spawnTimer >= enemySpawnRate) {
spawnEnemy();
spawnTimer = 0;
// Increase difficulty over time
if (LK.ticks % 1800 == 0) {
// Every 30 seconds
difficultyLevel++;
enemySpawnRate = Math.max(30, enemySpawnRate - 10);
}
}
// Fire torpedoes automatically
if (LK.ticks % 60 == 0) {
var torpedo = new Torpedo();
torpedo.x = submarine.x;
torpedo.y = submarine.y - 40;
torpedo.lastY = torpedo.y;
torpedo.lastIntersecting = false;
torpedoes.push(torpedo);
game.addChild(torpedo);
LK.getSound('torpedo_fire').play();
}
// Update and check torpedoes
for (var t = torpedoes.length - 1; t >= 0; t--) {
var torpedo = torpedoes[t];
// Remove torpedoes that go off-screen
if (torpedo.lastY >= -50 && torpedo.y < -50) {
torpedo.destroy();
torpedoes.splice(t, 1);
continue;
}
// Check torpedo-enemy collisions
var torpedoHit = false;
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
var currentIntersecting = torpedo.intersects(enemy);
if (!torpedo.lastIntersecting && currentIntersecting) {
// Torpedo hit enemy
enemy.hitCount++;
// Create explosion effect
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
explosion.lastLifetime = 0;
game.addChild(explosion);
LK.getSound('explosion').play();
// Remove torpedo immediately
torpedo.destroy();
torpedoes.splice(t, 1);
// Check if enemy should die (after 2 hits)
if (enemy.hitCount >= 2) {
LK.setScore(LK.getScore() + enemy.points);
scoreTxt.setText(LK.getScore());
enemy.destroy();
enemies.splice(e, 1);
}
torpedoHit = true;
break;
}
}
if (!torpedoHit) {
torpedo.lastY = torpedo.y;
torpedo.lastIntersecting = false;
}
}
// Update and check enemies
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
// Remove enemies that go off-screen
if (enemy.lastY <= 2732 + 50 && enemy.y > 2732 + 50) {
enemy.destroy();
enemies.splice(e, 1);
continue;
}
// Enemy shooting logic (only for EnemySubmarine) - limit to max 8 enemy torpedoes
if (enemy.shootTimer && enemy.shootTimer >= enemy.shootInterval && enemyTorpedoes.length < 8) {
var enemyTorpedo = new EnemyTorpedo();
enemyTorpedo.x = enemy.x;
enemyTorpedo.y = enemy.y + 40;
// Calculate direction toward submarine
var deltaX = submarine.x - enemyTorpedo.x;
var deltaY = submarine.y - enemyTorpedo.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var speed = 15;
enemyTorpedo.speedX = deltaX / distance * speed;
enemyTorpedo.speedY = deltaY / distance * speed;
enemyTorpedo.lastY = enemyTorpedo.y;
enemyTorpedo.lastIntersecting = false;
enemyTorpedoes.push(enemyTorpedo);
game.addChild(enemyTorpedo);
enemy.shootTimer = 0;
}
// Check submarine-enemy collision
var currentIntersecting = submarine.intersects(enemy);
if (!enemy.lastIntersecting && currentIntersecting) {
// Game Over
LK.effects.flashScreen(0xFF0000, 1000);
// Update high score
if (LK.getScore() > highScore) {
storage.highScore = LK.getScore();
}
LK.showGameOver();
return;
}
enemy.lastY = enemy.y;
enemy.lastIntersecting = currentIntersecting;
}
// Update and check enemy torpedoes
for (var et = enemyTorpedoes.length - 1; et >= 0; et--) {
var enemyTorpedo = enemyTorpedoes[et];
// Remove enemy torpedoes that go off-screen
if (enemyTorpedo.x < -50 || enemyTorpedo.x > 2098 || enemyTorpedo.y < -50 || enemyTorpedo.y > 2782) {
enemyTorpedo.destroy();
enemyTorpedoes.splice(et, 1);
continue;
}
// Check enemy torpedo-submarine collision
var currentIntersecting = submarine.intersects(enemyTorpedo);
if (!enemyTorpedo.lastIntersecting && currentIntersecting) {
// Game Over
LK.effects.flashScreen(0xFF0000, 1000);
// Update high score
if (LK.getScore() > highScore) {
storage.highScore = LK.getScore();
}
LK.showGameOver();
return;
}
enemyTorpedo.lastY = enemyTorpedo.y;
enemyTorpedo.lastIntersecting = currentIntersecting;
}
// Update and cleanup explosions
for (var ex = game.children.length - 1; ex >= 0; ex--) {
var child = game.children[ex];
if (child instanceof Explosion) {
if (child.lifetime >= child.maxLifetime) {
child.destroy();
}
}
}
};
// Start background music
LK.playMusic('underwater_ambient');
vertical top down blue king crab scifi submarine. In-Game asset. 2d. High contrast. No shadows
vertical top down red burn robotic octopus scifi war submarine. In-Game asset. 2d. High contrast. No shadows
vertical top down gray burn robotic turtle scifi war submarine. In-Game asset. 2d. High contrast. No shadows
top down image of gray sandy seabed. In-Game asset. 2d. High contrast. No shadows
blue electricity. In-Game asset. 2d. High contrast. No shadows
red electricity. In-Game asset. 2d. High contrast. No shadows