/****
* 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();
};