/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Arrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 1.0 }); self.speed = 18; self.targetX = 0; self.targetY = 0; self.velocityX = 0; self.velocityY = 0; self.setTarget = function (targetX, targetY) { self.targetX = targetX; self.targetY = targetY; var deltaX = targetX - self.x; var deltaY = targetY - self.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); self.velocityX = deltaX / distance * self.speed; self.velocityY = deltaY / distance * self.speed; // Rotate arrow to face direction var angle = Math.atan2(deltaY, deltaX) + Math.PI / 2; arrowGraphics.rotation = angle; }; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.update = function () { self.y += self.speed; }; return self; }); var RandomEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); enemyGraphics.tint = 0xff6666; // Tint red to distinguish from regular enemies self.speed = 4; self.velocityX = (Math.random() - 0.5) * 4; // Random horizontal velocity self.velocityY = Math.random() * 2 + 2; // Downward velocity with some randomness self.changeDirectionTimer = 0; self.update = function () { // Change direction randomly every 60-120 ticks self.changeDirectionTimer++; if (self.changeDirectionTimer >= Math.random() * 60 + 60) { self.velocityX = (Math.random() - 0.5) * 6; self.velocityY = Math.random() * 3 + 2; self.changeDirectionTimer = 0; } // Move based on velocity self.x += self.velocityX; self.y += self.velocityY; // Keep within screen bounds horizontally if (self.x < 80) { self.x = 80; self.velocityX = Math.abs(self.velocityX); } if (self.x > 2048 - 80) { self.x = 2048 - 80; self.velocityX = -Math.abs(self.velocityX); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xC0C0C0 }); /**** * Game Code ****/ var bow = game.addChild(LK.getAsset('bow', { anchorX: 0.5, anchorY: 0.5 })); bow.x = 2048 / 2; bow.y = 2732 - 150; var arrows = []; var enemies = []; var currentRound = 1; var enemiesSpawned = 0; var enemiesRemaining = 0; var gameStarted = false; var spawnTimer = 0; var arrowsRemaining = 0; var maxArrows = 0; // UI Elements var roundText = new Text2('Round: 1', { size: 80, fill: 0xFFFFFF }); roundText.anchor.set(0.5, 0); LK.gui.top.addChild(roundText); roundText.y = 120; var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.topRight.addChild(scoreText); scoreText.x = -300; scoreText.y = 50; var arrowsText = new Text2('Arrows: 0', { size: 60, fill: 0xFFFFFF }); arrowsText.anchor.set(0, 0); LK.gui.topLeft.addChild(arrowsText); arrowsText.x = 120; arrowsText.y = 50; function startNewRound() { enemiesSpawned = 0; enemiesRemaining = currentRound; spawnTimer = 0; maxArrows = currentRound + 5; arrowsRemaining = maxArrows; roundText.setText('Round: ' + currentRound); arrowsText.setText('Arrows: ' + arrowsRemaining); gameStarted = true; } function spawnEnemy() { if (enemiesSpawned < currentRound) { var enemy; // Every 4th round, spawn a RandomEnemy if (currentRound % 4 === 0) { enemy = new RandomEnemy(); } else { enemy = new Enemy(); } // Spawn enemies from random positions across the screen enemy.x = Math.random() * (2048 - 200) + 100; // Random X between 100 and 1948 enemy.y = -100; // Increase speed by 10% each round (base speed 4) enemy.speed = 4 * Math.pow(1.10, currentRound - 1); enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } } function checkRoundComplete() { if (enemiesRemaining <= 0 && enemies.length === 0) { currentRound++; scoreText.setText('Score: ' + LK.getScore()); // Brief pause before next round LK.setTimeout(function () { startNewRound(); }, 1500); } } game.down = function (x, y, obj) { if (!gameStarted || arrowsRemaining <= 0) { return; } var arrow = new Arrow(); arrow.x = bow.x; arrow.y = bow.y - 40; arrow.setTarget(x, y); arrows.push(arrow); game.addChild(arrow); arrowsRemaining--; arrowsText.setText('Arrows: ' + arrowsRemaining); LK.getSound('shoot').play(); }; game.update = function () { if (!gameStarted) { startNewRound(); return; } // Spawn enemies with timing spawnTimer++; if (spawnTimer >= 30 && enemiesSpawned < currentRound) { // Spawn every 0.5 seconds spawnEnemy(); spawnTimer = 0; } // Update and check arrows for (var i = arrows.length - 1; i >= 0; i--) { var arrow = arrows[i]; // Remove arrows that go off screen if (arrow.y < -100 || arrow.x < -100 || arrow.x > 2148) { arrow.destroy(); arrows.splice(i, 1); continue; } // Check arrow-enemy collisions for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (arrow.intersects(enemy)) { // Hit enemy LK.getSound('hit').play(); LK.setScore(LK.getScore() + 10); scoreText.setText('Score: ' + LK.getScore()); // Remove arrow and enemy arrow.destroy(); arrows.splice(i, 1); enemy.destroy(); enemies.splice(j, 1); enemiesRemaining--; break; } } } // Update and check enemies for (var k = enemies.length - 1; k >= 0; k--) { var enemy = enemies[k]; // Check if enemy reached bottom if (enemy.y > 2732 - 100) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Check if player ran out of arrows with enemies still alive if (arrowsRemaining <= 0 && arrows.length === 0 && enemies.length > 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } // Check if round is complete checkRoundComplete(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Arrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 18;
self.targetX = 0;
self.targetY = 0;
self.velocityX = 0;
self.velocityY = 0;
self.setTarget = function (targetX, targetY) {
self.targetX = targetX;
self.targetY = targetY;
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
self.velocityX = deltaX / distance * self.speed;
self.velocityY = deltaY / distance * self.speed;
// Rotate arrow to face direction
var angle = Math.atan2(deltaY, deltaX) + Math.PI / 2;
arrowGraphics.rotation = angle;
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.update = function () {
self.y += self.speed;
};
return self;
});
var RandomEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
enemyGraphics.tint = 0xff6666; // Tint red to distinguish from regular enemies
self.speed = 4;
self.velocityX = (Math.random() - 0.5) * 4; // Random horizontal velocity
self.velocityY = Math.random() * 2 + 2; // Downward velocity with some randomness
self.changeDirectionTimer = 0;
self.update = function () {
// Change direction randomly every 60-120 ticks
self.changeDirectionTimer++;
if (self.changeDirectionTimer >= Math.random() * 60 + 60) {
self.velocityX = (Math.random() - 0.5) * 6;
self.velocityY = Math.random() * 3 + 2;
self.changeDirectionTimer = 0;
}
// Move based on velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Keep within screen bounds horizontally
if (self.x < 80) {
self.x = 80;
self.velocityX = Math.abs(self.velocityX);
}
if (self.x > 2048 - 80) {
self.x = 2048 - 80;
self.velocityX = -Math.abs(self.velocityX);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xC0C0C0
});
/****
* Game Code
****/
var bow = game.addChild(LK.getAsset('bow', {
anchorX: 0.5,
anchorY: 0.5
}));
bow.x = 2048 / 2;
bow.y = 2732 - 150;
var arrows = [];
var enemies = [];
var currentRound = 1;
var enemiesSpawned = 0;
var enemiesRemaining = 0;
var gameStarted = false;
var spawnTimer = 0;
var arrowsRemaining = 0;
var maxArrows = 0;
// UI Elements
var roundText = new Text2('Round: 1', {
size: 80,
fill: 0xFFFFFF
});
roundText.anchor.set(0.5, 0);
LK.gui.top.addChild(roundText);
roundText.y = 120;
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreText);
scoreText.x = -300;
scoreText.y = 50;
var arrowsText = new Text2('Arrows: 0', {
size: 60,
fill: 0xFFFFFF
});
arrowsText.anchor.set(0, 0);
LK.gui.topLeft.addChild(arrowsText);
arrowsText.x = 120;
arrowsText.y = 50;
function startNewRound() {
enemiesSpawned = 0;
enemiesRemaining = currentRound;
spawnTimer = 0;
maxArrows = currentRound + 5;
arrowsRemaining = maxArrows;
roundText.setText('Round: ' + currentRound);
arrowsText.setText('Arrows: ' + arrowsRemaining);
gameStarted = true;
}
function spawnEnemy() {
if (enemiesSpawned < currentRound) {
var enemy;
// Every 4th round, spawn a RandomEnemy
if (currentRound % 4 === 0) {
enemy = new RandomEnemy();
} else {
enemy = new Enemy();
}
// Spawn enemies from random positions across the screen
enemy.x = Math.random() * (2048 - 200) + 100; // Random X between 100 and 1948
enemy.y = -100;
// Increase speed by 10% each round (base speed 4)
enemy.speed = 4 * Math.pow(1.10, currentRound - 1);
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
}
function checkRoundComplete() {
if (enemiesRemaining <= 0 && enemies.length === 0) {
currentRound++;
scoreText.setText('Score: ' + LK.getScore());
// Brief pause before next round
LK.setTimeout(function () {
startNewRound();
}, 1500);
}
}
game.down = function (x, y, obj) {
if (!gameStarted || arrowsRemaining <= 0) {
return;
}
var arrow = new Arrow();
arrow.x = bow.x;
arrow.y = bow.y - 40;
arrow.setTarget(x, y);
arrows.push(arrow);
game.addChild(arrow);
arrowsRemaining--;
arrowsText.setText('Arrows: ' + arrowsRemaining);
LK.getSound('shoot').play();
};
game.update = function () {
if (!gameStarted) {
startNewRound();
return;
}
// Spawn enemies with timing
spawnTimer++;
if (spawnTimer >= 30 && enemiesSpawned < currentRound) {
// Spawn every 0.5 seconds
spawnEnemy();
spawnTimer = 0;
}
// Update and check arrows
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Remove arrows that go off screen
if (arrow.y < -100 || arrow.x < -100 || arrow.x > 2148) {
arrow.destroy();
arrows.splice(i, 1);
continue;
}
// Check arrow-enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (arrow.intersects(enemy)) {
// Hit enemy
LK.getSound('hit').play();
LK.setScore(LK.getScore() + 10);
scoreText.setText('Score: ' + LK.getScore());
// Remove arrow and enemy
arrow.destroy();
arrows.splice(i, 1);
enemy.destroy();
enemies.splice(j, 1);
enemiesRemaining--;
break;
}
}
}
// Update and check enemies
for (var k = enemies.length - 1; k >= 0; k--) {
var enemy = enemies[k];
// Check if enemy reached bottom
if (enemy.y > 2732 - 100) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Check if player ran out of arrows with enemies still alive
if (arrowsRemaining <= 0 && arrows.length === 0 && enemies.length > 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Check if round is complete
checkRoundComplete();
};