/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Crosshair class var Crosshair = Container.expand(function () { var self = Container.call(this); var cross = self.attachAsset('crosshair', { anchorX: 0.5, anchorY: 0.5 }); cross.alpha = 0.5; // Muzzle flash var muzzle = self.attachAsset('muzzle', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); muzzle.visible = false; // Show muzzle flash self.flash = function () { muzzle.visible = true; muzzle.alpha = 1; tween(muzzle, { alpha: 0 }, { duration: 120, easing: tween.linear, onFinish: function onFinish() { muzzle.visible = false; } }); }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var enemySprite = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Speed and direction self.speed = 6; self.dx = 0; self.dy = 0; self.radius = enemySprite.width * 0.5; // For hit detection self.isAlive = true; // For wave/difficulty self.wave = 1; // Set movement vector towards center self.setTarget = function (tx, ty) { var dx = tx - self.x; var dy = ty - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) { self.dx = 0; self.dy = self.speed; } else { self.dx = dx / dist * self.speed; self.dy = dy / dist * self.speed; } }; // Called every tick self.update = function () { if (!self.isAlive) return; self.x += self.dx; self.y += self.dy; }; // Flash when hit self.flash = function () { tween(self, { alpha: 0.2 }, { duration: 60, easing: tween.linear, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 120, easing: tween.linear }); } }); }; // Destroy enemy self.kill = function () { self.isAlive = false; self.visible = false; self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c1f }); /**** * Game Code ****/ // Background music // Miss sound // Enemy destroyed sound // Shot sound // Muzzle flash: Ellipse, orange // Crosshair: Box, yellow // Enemy: Ellipse, red // Game area var GAME_W = 2048; var GAME_H = 2732; // Center point var CENTER_X = GAME_W / 2; var CENTER_Y = GAME_H / 2; // Main character (village) at center var village = LK.getAsset('character', { anchorX: 0.5, anchorY: 0.5, x: CENTER_X, y: CENTER_Y }); game.addChild(village); // Score display var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Wave display var waveTxt = new Text2('1. Dalga', { size: 70, fill: 0xFFE066 }); waveTxt.anchor.set(0.5, 0); LK.gui.top.addChild(waveTxt); waveTxt.y = 120; // Crosshair var crosshair = new Crosshair(); game.addChild(crosshair); crosshair.x = CENTER_X; crosshair.y = CENTER_Y; // Enemy array var enemies = []; // For drag/aim var isAiming = false; // Game state var wave = 1; var enemiesPerWave = 5; var enemiesSpawned = 0; var enemiesKilled = 0; var waveInProgress = false; var spawnTimer = null; var nextWaveTimeout = null; var gameOver = false; // Difficulty scaling function getEnemySpeed(wave) { // Early waves are slow, then speed up more after wave 5 if (wave <= 3) { return 5 + (wave - 1) * 0.8; } else if (wave <= 7) { return 7 + (wave - 4) * 1.5; } else { return 13 + (wave - 8) * 2.2; } } function getEnemiesPerWave(wave) { // Early waves: fewer enemies, then increase more rapidly if (wave <= 2) { return 4 + (wave - 1) * 1; // 4, 5 } else if (wave <= 5) { return 6 + (wave - 3) * 2; // 6, 8, 10 } else if (wave <= 8) { return 12 + (wave - 6) * 3; // 12, 15, 18 } else { return 22 + (wave - 9) * 4; // 22, 26, 30, ... } } // Spawn enemy at random edge, moving toward center function spawnEnemy() { var edge = Math.floor(Math.random() * 4); // 0:top, 1:right, 2:bottom, 3:left var ex, ey; var margin = 120; if (edge === 0) { // top ex = margin + Math.random() * (GAME_W - 2 * margin); ey = -100; } else if (edge === 1) { // right ex = GAME_W + 100; ey = margin + Math.random() * (GAME_H - 2 * margin); } else if (edge === 2) { // bottom ex = margin + Math.random() * (GAME_W - 2 * margin); ey = GAME_H + 100; } else { // left ex = -100; ey = margin + Math.random() * (GAME_H - 2 * margin); } var enemy = new Enemy(); enemy.x = ex; enemy.y = ey; enemy.speed = getEnemySpeed(wave); enemy.wave = wave; enemy.setTarget(village.x, village.y); enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } // Start a wave function startWave() { waveInProgress = true; enemiesPerWave = getEnemiesPerWave(wave); enemiesSpawned = 0; enemiesKilled = 0; waveTxt.setText(wave + ". Dalga"); // Calculate spawn interval: slow at first, then faster var spawnInterval; if (wave <= 3) { spawnInterval = 700 - (wave - 1) * 100; } else if (wave <= 7) { spawnInterval = 400 - (wave - 4) * 40; } else { spawnInterval = 240 - (wave - 8) * 20; } spawnInterval = Math.max(100, spawnInterval); spawnTimer = LK.setInterval(function () { if (enemiesSpawned < enemiesPerWave) { spawnEnemy(); } if (enemiesSpawned >= enemiesPerWave) { LK.clearInterval(spawnTimer); } }, spawnInterval); } // End wave, start next after delay function endWave() { waveInProgress = false; nextWaveTimeout = LK.setTimeout(function () { wave++; startWave(); }, 1200); } // Reset game state function resetGame() { for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].kill(); enemies.splice(i, 1); } wave = 1; LK.setScore(0); scoreTxt.setText('0'); waveTxt.setText('1. Dalga'); gameOver = false; if (spawnTimer) LK.clearInterval(spawnTimer); if (nextWaveTimeout) LK.clearTimeout(nextWaveTimeout); startWave(); } // Check if enemy reached center (game over) function checkEnemyReachedCenter(enemy) { // Use intersects to check if enemy reached the village if (enemy.intersects(village)) { return true; } return false; } // Check if point (x, y) hits enemy (circle hitbox) function isHit(enemy, x, y) { var dx = enemy.x - x; var dy = enemy.y - y; var r = enemy.radius * 0.95; return dx * dx + dy * dy <= r * r; } // Handle shooting function shootAt(x, y) { if (gameOver) return; crosshair.flash(); LK.getSound('shot').play(); // Find closest enemy under crosshair var hitEnemy = null; var minDist = 99999; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (!enemy.isAlive) continue; if (isHit(enemy, x, y)) { var dx = enemy.x - x; var dy = enemy.y - y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; hitEnemy = enemy; } } } if (hitEnemy) { hitEnemy.flash(); hitEnemy.kill(); LK.getSound('enemyDown').play(); LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); enemiesKilled++; // Remove from array for (var j = 0; j < enemies.length; j++) { if (enemies[j] === hitEnemy) { enemies.splice(j, 1); break; } } // If all enemies killed, end wave if (enemiesKilled >= enemiesPerWave && enemiesSpawned >= enemiesPerWave) { endWave(); } } else { LK.getSound('miss').play(); } } // Move crosshair with drag/tap function handleMove(x, y, obj) { if (gameOver) return; // Clamp inside game area var nx = Math.max(60, Math.min(GAME_W - 60, x)); var ny = Math.max(60, Math.min(GAME_H - 60, y)); crosshair.x = nx; crosshair.y = ny; } game.move = handleMove; // Touch down: aim and shoot game.down = function (x, y, obj) { if (gameOver) return; isAiming = true; handleMove(x, y, obj); shootAt(crosshair.x, crosshair.y); }; game.up = function (x, y, obj) { isAiming = false; }; // Main update loop game.update = function () { if (gameOver) return; // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); if (!enemy.isAlive) continue; // Check if reached center if (checkEnemyReachedCenter(enemy)) { // Game over gameOver = true; LK.effects.flashScreen(0xff0000, 900); LK.showGameOver(); return; } } }; // Start music LK.playMusic('bgmusic', { fade: { start: 0, end: 1, duration: 800 } }); // Start game resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Crosshair class
var Crosshair = Container.expand(function () {
var self = Container.call(this);
var cross = self.attachAsset('crosshair', {
anchorX: 0.5,
anchorY: 0.5
});
cross.alpha = 0.5;
// Muzzle flash
var muzzle = self.attachAsset('muzzle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
muzzle.visible = false;
// Show muzzle flash
self.flash = function () {
muzzle.visible = true;
muzzle.alpha = 1;
tween(muzzle, {
alpha: 0
}, {
duration: 120,
easing: tween.linear,
onFinish: function onFinish() {
muzzle.visible = false;
}
});
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Speed and direction
self.speed = 6;
self.dx = 0;
self.dy = 0;
self.radius = enemySprite.width * 0.5;
// For hit detection
self.isAlive = true;
// For wave/difficulty
self.wave = 1;
// Set movement vector towards center
self.setTarget = function (tx, ty) {
var dx = tx - self.x;
var dy = ty - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) {
self.dx = 0;
self.dy = self.speed;
} else {
self.dx = dx / dist * self.speed;
self.dy = dy / dist * self.speed;
}
};
// Called every tick
self.update = function () {
if (!self.isAlive) return;
self.x += self.dx;
self.y += self.dy;
};
// Flash when hit
self.flash = function () {
tween(self, {
alpha: 0.2
}, {
duration: 60,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 120,
easing: tween.linear
});
}
});
};
// Destroy enemy
self.kill = function () {
self.isAlive = false;
self.visible = false;
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c1f
});
/****
* Game Code
****/
// Background music
// Miss sound
// Enemy destroyed sound
// Shot sound
// Muzzle flash: Ellipse, orange
// Crosshair: Box, yellow
// Enemy: Ellipse, red
// Game area
var GAME_W = 2048;
var GAME_H = 2732;
// Center point
var CENTER_X = GAME_W / 2;
var CENTER_Y = GAME_H / 2;
// Main character (village) at center
var village = LK.getAsset('character', {
anchorX: 0.5,
anchorY: 0.5,
x: CENTER_X,
y: CENTER_Y
});
game.addChild(village);
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Wave display
var waveTxt = new Text2('1. Dalga', {
size: 70,
fill: 0xFFE066
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
waveTxt.y = 120;
// Crosshair
var crosshair = new Crosshair();
game.addChild(crosshair);
crosshair.x = CENTER_X;
crosshair.y = CENTER_Y;
// Enemy array
var enemies = [];
// For drag/aim
var isAiming = false;
// Game state
var wave = 1;
var enemiesPerWave = 5;
var enemiesSpawned = 0;
var enemiesKilled = 0;
var waveInProgress = false;
var spawnTimer = null;
var nextWaveTimeout = null;
var gameOver = false;
// Difficulty scaling
function getEnemySpeed(wave) {
// Early waves are slow, then speed up more after wave 5
if (wave <= 3) {
return 5 + (wave - 1) * 0.8;
} else if (wave <= 7) {
return 7 + (wave - 4) * 1.5;
} else {
return 13 + (wave - 8) * 2.2;
}
}
function getEnemiesPerWave(wave) {
// Early waves: fewer enemies, then increase more rapidly
if (wave <= 2) {
return 4 + (wave - 1) * 1; // 4, 5
} else if (wave <= 5) {
return 6 + (wave - 3) * 2; // 6, 8, 10
} else if (wave <= 8) {
return 12 + (wave - 6) * 3; // 12, 15, 18
} else {
return 22 + (wave - 9) * 4; // 22, 26, 30, ...
}
}
// Spawn enemy at random edge, moving toward center
function spawnEnemy() {
var edge = Math.floor(Math.random() * 4); // 0:top, 1:right, 2:bottom, 3:left
var ex, ey;
var margin = 120;
if (edge === 0) {
// top
ex = margin + Math.random() * (GAME_W - 2 * margin);
ey = -100;
} else if (edge === 1) {
// right
ex = GAME_W + 100;
ey = margin + Math.random() * (GAME_H - 2 * margin);
} else if (edge === 2) {
// bottom
ex = margin + Math.random() * (GAME_W - 2 * margin);
ey = GAME_H + 100;
} else {
// left
ex = -100;
ey = margin + Math.random() * (GAME_H - 2 * margin);
}
var enemy = new Enemy();
enemy.x = ex;
enemy.y = ey;
enemy.speed = getEnemySpeed(wave);
enemy.wave = wave;
enemy.setTarget(village.x, village.y);
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
// Start a wave
function startWave() {
waveInProgress = true;
enemiesPerWave = getEnemiesPerWave(wave);
enemiesSpawned = 0;
enemiesKilled = 0;
waveTxt.setText(wave + ". Dalga");
// Calculate spawn interval: slow at first, then faster
var spawnInterval;
if (wave <= 3) {
spawnInterval = 700 - (wave - 1) * 100;
} else if (wave <= 7) {
spawnInterval = 400 - (wave - 4) * 40;
} else {
spawnInterval = 240 - (wave - 8) * 20;
}
spawnInterval = Math.max(100, spawnInterval);
spawnTimer = LK.setInterval(function () {
if (enemiesSpawned < enemiesPerWave) {
spawnEnemy();
}
if (enemiesSpawned >= enemiesPerWave) {
LK.clearInterval(spawnTimer);
}
}, spawnInterval);
}
// End wave, start next after delay
function endWave() {
waveInProgress = false;
nextWaveTimeout = LK.setTimeout(function () {
wave++;
startWave();
}, 1200);
}
// Reset game state
function resetGame() {
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].kill();
enemies.splice(i, 1);
}
wave = 1;
LK.setScore(0);
scoreTxt.setText('0');
waveTxt.setText('1. Dalga');
gameOver = false;
if (spawnTimer) LK.clearInterval(spawnTimer);
if (nextWaveTimeout) LK.clearTimeout(nextWaveTimeout);
startWave();
}
// Check if enemy reached center (game over)
function checkEnemyReachedCenter(enemy) {
// Use intersects to check if enemy reached the village
if (enemy.intersects(village)) {
return true;
}
return false;
}
// Check if point (x, y) hits enemy (circle hitbox)
function isHit(enemy, x, y) {
var dx = enemy.x - x;
var dy = enemy.y - y;
var r = enemy.radius * 0.95;
return dx * dx + dy * dy <= r * r;
}
// Handle shooting
function shootAt(x, y) {
if (gameOver) return;
crosshair.flash();
LK.getSound('shot').play();
// Find closest enemy under crosshair
var hitEnemy = null;
var minDist = 99999;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy.isAlive) continue;
if (isHit(enemy, x, y)) {
var dx = enemy.x - x;
var dy = enemy.y - y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
hitEnemy = enemy;
}
}
}
if (hitEnemy) {
hitEnemy.flash();
hitEnemy.kill();
LK.getSound('enemyDown').play();
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
enemiesKilled++;
// Remove from array
for (var j = 0; j < enemies.length; j++) {
if (enemies[j] === hitEnemy) {
enemies.splice(j, 1);
break;
}
}
// If all enemies killed, end wave
if (enemiesKilled >= enemiesPerWave && enemiesSpawned >= enemiesPerWave) {
endWave();
}
} else {
LK.getSound('miss').play();
}
}
// Move crosshair with drag/tap
function handleMove(x, y, obj) {
if (gameOver) return;
// Clamp inside game area
var nx = Math.max(60, Math.min(GAME_W - 60, x));
var ny = Math.max(60, Math.min(GAME_H - 60, y));
crosshair.x = nx;
crosshair.y = ny;
}
game.move = handleMove;
// Touch down: aim and shoot
game.down = function (x, y, obj) {
if (gameOver) return;
isAiming = true;
handleMove(x, y, obj);
shootAt(crosshair.x, crosshair.y);
};
game.up = function (x, y, obj) {
isAiming = false;
};
// Main update loop
game.update = function () {
if (gameOver) return;
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
if (!enemy.isAlive) continue;
// Check if reached center
if (checkEnemyReachedCenter(enemy)) {
// Game over
gameOver = true;
LK.effects.flashScreen(0xff0000, 900);
LK.showGameOver();
return;
}
}
};
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 800
}
});
// Start game
resetGame();