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