/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Enemy Cannonball Class var Cannonball = Container.expand(function () { var self = Container.call(this); var ball = self.attachAsset('cannonball', { anchorX: 0.5, anchorY: 0.5 }); self.width = ball.width; self.height = ball.height; self.speed = 10; self.update = function () { self.y += self.speed; }; return self; }); // Enemy Ship Class var EnemyShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('enemyShip', { anchorX: 0.5, anchorY: 0.5 }); self.width = ship.width; self.height = ship.height; self.speed = 2 + Math.random() * 2; // Vary speed self.fireCooldown = 60 + Math.floor(Math.random() * 60); // Ticks until next shot self.update = function () { self.y += self.speed; self.fireCooldown--; }; return self; }); // Explosion effect (visual only) var Explosion = Container.expand(function () { var self = Container.call(this); var exp = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); // Animate: scale up and fade out tween(self, { scaleX: 1.8, scaleY: 1.8, alpha: 0 }, { duration: 350, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); return self; }); // Player Cannonball Class var PlayerCannonball = Container.expand(function () { var self = Container.call(this); var ball = self.attachAsset('playerCannonball', { anchorX: 0.5, anchorY: 0.5 }); self.width = ball.width; self.height = ball.height; self.speed = -16; self.update = function () { self.y += self.speed; }; return self; }); // Player Ship Class var PlayerShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); self.width = ship.width; self.height = ship.height; // For hit flash self.flash = function () { tween(self, { alpha: 0.3 }, { duration: 100, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 200 }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a3a5c // Deep blue sea }); /**** * Game Code ****/ // Explosion: red ellipse, 80x80 // Player cannonball: gold ellipse, 60x60 // Cannonball: black ellipse, 60x60 // Enemy ship: dark gray box, 160x100 // Player ship: brown box, 180x120 // --- Globals --- var playerShip; var enemyShips = []; var cannonballs = []; var playerCannonballs = []; var explosions = []; var dragNode = null; var lastPlayerHit = false; var scoreTxt; var spawnTimer = 0; var enemySpawnInterval = 180; // ticks (increased to reduce enemy appearance) var minEnemySpawnInterval = 80; var difficultyTimer = 0; // --- Setup background color --- game.setBackgroundColor(0x1a3a5c); // --- Add background image (sharp, scaled to fill) --- var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); // Render at native HD resolution for sharp detail bg.scaleX = 1; bg.scaleY = 1; game.addChildAt(bg, 0); // --- Play background music --- LK.playMusic('1battlefieldepic'); // (Background asset removed) // --- Score UI --- scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Player Ship --- playerShip = new PlayerShip(); playerShip.x = 2048 / 2; playerShip.y = 2732 - 220; game.addChild(playerShip); // --- Touch Controls --- function clamp(val, min, max) { if (val < min) return min; if (val > max) return max; return val; } // --- Smooth swipe control variables --- var swipeTargetX = null; var swipeTargetY = null; var swipeActive = false; function handleMove(x, y, obj) { if (dragNode === playerShip) { // Set target position for smooth movement var halfW = playerShip.width / 2; var halfH = playerShip.height / 2; swipeTargetX = clamp(x, halfW, 2048 - halfW); swipeTargetY = clamp(y, 2732 * 0.5, 2732 - halfH - 20); swipeActive = true; } } game.move = handleMove; game.down = function (x, y, obj) { dragNode = playerShip; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; swipeActive = false; }; // --- Game Update Loop --- game.update = function () { // --- Difficulty scaling --- difficultyTimer++; if (difficultyTimer % 600 === 0 && enemySpawnInterval > minEnemySpawnInterval) { enemySpawnInterval -= 10; if (enemySpawnInterval < minEnemySpawnInterval) enemySpawnInterval = minEnemySpawnInterval; } // --- Spawn Enemies --- spawnTimer++; if (spawnTimer >= enemySpawnInterval) { spawnTimer = 0; var enemy = new EnemyShip(); // Random x, avoid edges var ew = enemy.width / 2; enemy.x = ew + Math.random() * (2048 - ew * 2); enemy.y = -enemy.height / 2 - 10; enemyShips.push(enemy); game.addChild(enemy); } // --- Update Enemies --- for (var i = enemyShips.length - 1; i >= 0; i--) { var enemy = enemyShips[i]; enemy.update(); // Fire cannonball if ready and player is alive if (enemy.fireCooldown <= 0 && playerShip && !lastPlayerHit) { var cb = new Cannonball(); cb.x = enemy.x; cb.y = enemy.y + enemy.height / 2 + 10; // Calculate direction vector from enemy to player var dx = playerShip.x - cb.x; var dy = playerShip.y - cb.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) { dx = 0; dy = 1; dist = 1; } cb.vx = dx / dist * cb.speed; cb.vy = dy / dist * cb.speed; // Overwrite update to move in direction (function (cannonball) { cannonball.update = function () { cannonball.x += cannonball.vx; cannonball.y += cannonball.vy; }; })(cb); cannonballs.push(cb); game.addChild(cb); // Play cannon fire sound LK.getSound('cannon_fire').play(); enemy.fireCooldown = 90 + Math.floor(Math.random() * 60); } // Remove if off screen if (enemy.y - enemy.height / 2 > 2732 + 100) { enemy.destroy(); enemyShips.splice(i, 1); } } // --- Update Enemy Cannonballs --- for (var i = cannonballs.length - 1; i >= 0; i--) { var cb = cannonballs[i]; cb.update(); // Collision with player if (playerShip && cb.intersects(playerShip)) { // Hit! if (!lastPlayerHit) { playerShip.flash(); // Add explosion effect at player position (player explosion asset) var exp = new Explosion(); exp.x = playerShip.x; exp.y = playerShip.y; game.addChild(exp); // Play explosion sound LK.getSound('explosion_sfx').play(); LK.effects.flashScreen(0xff0000, 800); lastPlayerHit = true; // Remove player ship from game after explosion LK.setTimeout(function () { if (playerShip) { playerShip.destroy(); playerShip = null; } LK.showGameOver(); }, 600); } } // Remove if off screen if (cb.y - cb.height / 2 > 2732 + 60) { cb.destroy(); cannonballs.splice(i, 1); } } // --- Update Player Cannonballs --- for (var i = playerCannonballs.length - 1; i >= 0; i--) { var pcb = playerCannonballs[i]; pcb.update(); // Remove if off screen if (pcb.y + pcb.height / 2 < -60) { pcb.destroy(); playerCannonballs.splice(i, 1); continue; } // Check collision with enemy ships for (var j = enemyShips.length - 1; j >= 0; j--) { var enemy = enemyShips[j]; if (pcb.intersects(enemy)) { // Explosion effect var exp = new Explosion(); exp.x = enemy.x; exp.y = enemy.y; game.addChild(exp); // Play explosion sound LK.getSound('explosion_sfx').play(); // Remove enemy and cannonball enemy.destroy(); enemyShips.splice(j, 1); pcb.destroy(); playerCannonballs.splice(i, 1); // Score LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); break; } } } // --- Fire player cannonball (auto-fire every 1 second = 60 ticks) --- if (playerShip && !lastPlayerHit && LK.ticks % 60 === 0) { var pcb = new PlayerCannonball(); pcb.x = playerShip.x; pcb.y = playerShip.y - playerShip.height / 2 - 10; playerCannonballs.push(pcb); game.addChild(pcb); // Play cannon fire sound LK.getSound('cannon_fire').play(); } // --- Smooth swipe control update --- if (playerShip && swipeActive && swipeTargetX !== null && swipeTargetY !== null) { // Easing factor (0.18 = fast, 0.08 = slow) var ease = 0.18; var dx = swipeTargetX - playerShip.x; var dy = swipeTargetY - playerShip.y; // Only move if not already very close if (Math.abs(dx) > 1 || Math.abs(dy) > 1) { playerShip.x += dx * ease; playerShip.y += dy * ease; } else { playerShip.x = swipeTargetX; playerShip.y = swipeTargetY; } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Enemy Cannonball Class
var Cannonball = Container.expand(function () {
var self = Container.call(this);
var ball = self.attachAsset('cannonball', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ball.width;
self.height = ball.height;
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy Ship Class
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ship.width;
self.height = ship.height;
self.speed = 2 + Math.random() * 2; // Vary speed
self.fireCooldown = 60 + Math.floor(Math.random() * 60); // Ticks until next shot
self.update = function () {
self.y += self.speed;
self.fireCooldown--;
};
return self;
});
// Explosion effect (visual only)
var Explosion = Container.expand(function () {
var self = Container.call(this);
var exp = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
// Animate: scale up and fade out
tween(self, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
// Player Cannonball Class
var PlayerCannonball = Container.expand(function () {
var self = Container.call(this);
var ball = self.attachAsset('playerCannonball', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ball.width;
self.height = ball.height;
self.speed = -16;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Ship Class
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ship.width;
self.height = ship.height;
// For hit flash
self.flash = function () {
tween(self, {
alpha: 0.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 200
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a3a5c // Deep blue sea
});
/****
* Game Code
****/
// Explosion: red ellipse, 80x80
// Player cannonball: gold ellipse, 60x60
// Cannonball: black ellipse, 60x60
// Enemy ship: dark gray box, 160x100
// Player ship: brown box, 180x120
// --- Globals ---
var playerShip;
var enemyShips = [];
var cannonballs = [];
var playerCannonballs = [];
var explosions = [];
var dragNode = null;
var lastPlayerHit = false;
var scoreTxt;
var spawnTimer = 0;
var enemySpawnInterval = 180; // ticks (increased to reduce enemy appearance)
var minEnemySpawnInterval = 80;
var difficultyTimer = 0;
// --- Setup background color ---
game.setBackgroundColor(0x1a3a5c);
// --- Add background image (sharp, scaled to fill) ---
var bg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Render at native HD resolution for sharp detail
bg.scaleX = 1;
bg.scaleY = 1;
game.addChildAt(bg, 0);
// --- Play background music ---
LK.playMusic('1battlefieldepic');
// (Background asset removed)
// --- Score UI ---
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Player Ship ---
playerShip = new PlayerShip();
playerShip.x = 2048 / 2;
playerShip.y = 2732 - 220;
game.addChild(playerShip);
// --- Touch Controls ---
function clamp(val, min, max) {
if (val < min) return min;
if (val > max) return max;
return val;
}
// --- Smooth swipe control variables ---
var swipeTargetX = null;
var swipeTargetY = null;
var swipeActive = false;
function handleMove(x, y, obj) {
if (dragNode === playerShip) {
// Set target position for smooth movement
var halfW = playerShip.width / 2;
var halfH = playerShip.height / 2;
swipeTargetX = clamp(x, halfW, 2048 - halfW);
swipeTargetY = clamp(y, 2732 * 0.5, 2732 - halfH - 20);
swipeActive = true;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = playerShip;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
swipeActive = false;
};
// --- Game Update Loop ---
game.update = function () {
// --- Difficulty scaling ---
difficultyTimer++;
if (difficultyTimer % 600 === 0 && enemySpawnInterval > minEnemySpawnInterval) {
enemySpawnInterval -= 10;
if (enemySpawnInterval < minEnemySpawnInterval) enemySpawnInterval = minEnemySpawnInterval;
}
// --- Spawn Enemies ---
spawnTimer++;
if (spawnTimer >= enemySpawnInterval) {
spawnTimer = 0;
var enemy = new EnemyShip();
// Random x, avoid edges
var ew = enemy.width / 2;
enemy.x = ew + Math.random() * (2048 - ew * 2);
enemy.y = -enemy.height / 2 - 10;
enemyShips.push(enemy);
game.addChild(enemy);
}
// --- Update Enemies ---
for (var i = enemyShips.length - 1; i >= 0; i--) {
var enemy = enemyShips[i];
enemy.update();
// Fire cannonball if ready and player is alive
if (enemy.fireCooldown <= 0 && playerShip && !lastPlayerHit) {
var cb = new Cannonball();
cb.x = enemy.x;
cb.y = enemy.y + enemy.height / 2 + 10;
// Calculate direction vector from enemy to player
var dx = playerShip.x - cb.x;
var dy = playerShip.y - cb.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) {
dx = 0;
dy = 1;
dist = 1;
}
cb.vx = dx / dist * cb.speed;
cb.vy = dy / dist * cb.speed;
// Overwrite update to move in direction
(function (cannonball) {
cannonball.update = function () {
cannonball.x += cannonball.vx;
cannonball.y += cannonball.vy;
};
})(cb);
cannonballs.push(cb);
game.addChild(cb);
// Play cannon fire sound
LK.getSound('cannon_fire').play();
enemy.fireCooldown = 90 + Math.floor(Math.random() * 60);
}
// Remove if off screen
if (enemy.y - enemy.height / 2 > 2732 + 100) {
enemy.destroy();
enemyShips.splice(i, 1);
}
}
// --- Update Enemy Cannonballs ---
for (var i = cannonballs.length - 1; i >= 0; i--) {
var cb = cannonballs[i];
cb.update();
// Collision with player
if (playerShip && cb.intersects(playerShip)) {
// Hit!
if (!lastPlayerHit) {
playerShip.flash();
// Add explosion effect at player position (player explosion asset)
var exp = new Explosion();
exp.x = playerShip.x;
exp.y = playerShip.y;
game.addChild(exp);
// Play explosion sound
LK.getSound('explosion_sfx').play();
LK.effects.flashScreen(0xff0000, 800);
lastPlayerHit = true;
// Remove player ship from game after explosion
LK.setTimeout(function () {
if (playerShip) {
playerShip.destroy();
playerShip = null;
}
LK.showGameOver();
}, 600);
}
}
// Remove if off screen
if (cb.y - cb.height / 2 > 2732 + 60) {
cb.destroy();
cannonballs.splice(i, 1);
}
}
// --- Update Player Cannonballs ---
for (var i = playerCannonballs.length - 1; i >= 0; i--) {
var pcb = playerCannonballs[i];
pcb.update();
// Remove if off screen
if (pcb.y + pcb.height / 2 < -60) {
pcb.destroy();
playerCannonballs.splice(i, 1);
continue;
}
// Check collision with enemy ships
for (var j = enemyShips.length - 1; j >= 0; j--) {
var enemy = enemyShips[j];
if (pcb.intersects(enemy)) {
// Explosion effect
var exp = new Explosion();
exp.x = enemy.x;
exp.y = enemy.y;
game.addChild(exp);
// Play explosion sound
LK.getSound('explosion_sfx').play();
// Remove enemy and cannonball
enemy.destroy();
enemyShips.splice(j, 1);
pcb.destroy();
playerCannonballs.splice(i, 1);
// Score
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
break;
}
}
}
// --- Fire player cannonball (auto-fire every 1 second = 60 ticks) ---
if (playerShip && !lastPlayerHit && LK.ticks % 60 === 0) {
var pcb = new PlayerCannonball();
pcb.x = playerShip.x;
pcb.y = playerShip.y - playerShip.height / 2 - 10;
playerCannonballs.push(pcb);
game.addChild(pcb);
// Play cannon fire sound
LK.getSound('cannon_fire').play();
}
// --- Smooth swipe control update ---
if (playerShip && swipeActive && swipeTargetX !== null && swipeTargetY !== null) {
// Easing factor (0.18 = fast, 0.08 = slow)
var ease = 0.18;
var dx = swipeTargetX - playerShip.x;
var dy = swipeTargetY - playerShip.y;
// Only move if not already very close
if (Math.abs(dx) > 1 || Math.abs(dy) > 1) {
playerShip.x += dx * ease;
playerShip.y += dy * ease;
} else {
playerShip.x = swipeTargetX;
playerShip.y = swipeTargetY;
}
}
};
blue flyng wyvern dragon back view. In-Game asset. 2d. High contrast. No shadows
winged evil gray skull. In-Game asset. 2d. High contrast. No shadows
oval fire ball. In-Game asset. 2d. High contrast. No shadows
yellow bright fire explosion. In-Game asset. 2d. High contrast. No shadows
blue thunder ball. In-Game asset. 2d. High contrast. No shadows