User prompt
When playing, the song that plays now is "Game music"
User prompt
Now, when realoading, we do the "Reload" sound effect
User prompt
Add a 6 second cooldown after firing 15 arrows
Code edit (1 edits merged)
Please save this source code
User prompt
Archery Bastions
Initial prompt
Archery bastions
/****
* Classes
****/
// Sound when an enemy reaches the bastion
// No plugins needed for this version of the game.
/**
* Represents an Arrow fired by the player.
* @param {number} angle - The angle in radians at which the arrow is fired.
*/
var Arrow = Container.expand(function (angle) {
var self = Container.call(this);
// Create and attach the arrow graphic asset
var graphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.rotation = angle + Math.PI / 2; // Align arrow graphic with direction
self.speed = 30; // Speed of the arrow in pixels per tick
self.vx = Math.sin(angle) * self.speed; // Horizontal velocity component
self.vy = -Math.cos(angle) * self.speed; // Vertical velocity component (negative Y is up)
/**
* Update method called each game tick by the LK engine.
* Moves the arrow based on its velocity.
*/
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self; // Return self for potential inheritance
});
/**
* Represents an Enemy attacker moving towards the bastion.
* @param {number} speed - The vertical speed of the enemy in pixels per tick.
*/
var Enemy = Container.expand(function (speed) {
var self = Container.call(this);
// Create and attach the enemy graphic asset
var graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = speed; // Vertical speed (pixels per tick)
/**
* Update method called each game tick by the LK engine.
* Moves the enemy downwards.
*/
self.update = function () {
self.y += self.speed;
};
return self; // Return self for potential inheritance
});
/****
* Initialize Game
****/
// Create the main game instance with a dark background color.
var game = new LK.Game({
backgroundColor: 0x101030 // Dark blue/purple background
});
/****
* Game Code
****/
// Constants defining game dimensions and key vertical positions.
// Define shapes and sounds needed for the game.
// LK engine will automatically initialize these based on usage.
// Yellow arrow shape
// Red enemy shape
// Grey line representing the bastion defense line
// Sound for firing an arrow
// Sound for an arrow hitting an enemy
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BASTION_Y = GAME_HEIGHT - 250; // Y-coordinate representing the defense line. Enemies crossing this trigger game over.
var FIRING_POS_Y = GAME_HEIGHT - 150; // Y-coordinate from where arrows are fired.
var FIRING_POS_X = GAME_WIDTH / 2; // X-coordinate from where arrows are fired (center).
// Arrays to keep track of active arrows and enemies.
var arrows = [];
var enemies = [];
// Variables for game state and difficulty scaling.
var scoreTxt; // Text2 object for displaying the score.
var dragStartX = null; // Starting X coordinate of a touch/mouse drag.
var dragStartY = null; // Starting Y coordinate of a touch/mouse drag.
var enemySpawnInterval = 120; // Initial ticks between enemy spawns (2 seconds at 60 FPS).
var arrowsFired = 0; // Counter for arrows fired since the last cooldown.
var cooldownTimer = 0; // Timer in ticks for the cooldown period.
var cooldownDuration = 6 * 60; // Cooldown duration in ticks (6 seconds * 60 ticks/sec).
var minEnemySpawnInterval = 30; // Minimum ticks between enemy spawns (0.5 seconds).
var enemySpawnRateDecrease = 0.08; // Amount to decrease spawn interval each time an enemy spawns.
var currentEnemySpeed = 3; // Initial speed of enemies.
var maxEnemySpeed = 12; // Maximum speed enemies can reach.
var enemySpeedIncrease = 0.015; // Amount to increase enemy speed each time an enemy spawns.
// --- Visual Setup ---
// Create a visual line representing the bastion defense zone.
var bastionLine = game.addChild(LK.getAsset('bastionLine', {
anchorX: 0.0,
// Anchor at the left edge.
anchorY: 0.5,
// Anchor vertically centered.
x: 0,
// Position at the left edge of the screen.
y: BASTION_Y // Position at the defined bastion Y-coordinate.
}));
// Create and configure the score display text.
scoreTxt = new Text2('0', {
size: 150,
// Font size.
fill: 0xFFFFFF // White color.
});
scoreTxt.anchor.set(0.5, 0); // Anchor at the horizontal center, top edge.
// Add score text to the GUI layer at the top-center position.
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 30; // Add padding below the top edge. Ensure it's clear of the top-left menu icon area.
// --- Input Event Handlers ---
// Handles touch/mouse press down event on the game area.
game.down = function (x, y, obj) {
// Record the starting position of the drag in game coordinates.
var gamePos = game.toLocal({
x: x,
y: y
});
dragStartX = gamePos.x;
dragStartY = gamePos.y;
// Potential enhancement: Show an aiming indicator originating from FIRING_POS_X, FIRING_POS_Y towards the drag point.
};
// Handles touch/mouse move event while dragging on the game area.
game.move = function (x, y, obj) {
// Only process if a drag is currently active.
if (dragStartX !== null) {
var gamePos = game.toLocal({
x: x,
y: y
});
// Potential enhancement: Update the aiming indicator based on the current drag position (gamePos).
}
};
// Handles touch/mouse release event on the game area.
game.up = function (x, y, obj) {
// Only process if a drag was active.
if (dragStartX !== null && cooldownTimer <= 0) {
// Only allow firing if not on cooldown.
var gamePos = game.toLocal({
x: x,
y: y
});
var dragEndX = gamePos.x;
var dragEndY = gamePos.y;
// Calculate the difference between the firing position and the release point to determine direction.
// A longer drag could potentially mean more power, but we'll keep it simple: direction only.
var dx = dragEndX - FIRING_POS_X;
var dy = dragEndY - FIRING_POS_Y;
// Avoid division by zero or zero vector if start and end points are the same.
if (dx === 0 && dy === 0) {
// Optionally handle this case, e.g., fire straight up or do nothing.
// Let's fire straight up if drag distance is negligible.
dy = -1;
}
// Calculate the angle using atan2. Note the order (dx, dy) and the negation of dy
// because the Y-axis is inverted in screen coordinates (positive Y is down).
var angle = Math.atan2(dx, -dy);
// Create a new arrow instance with the calculated angle.
var newArrow = new Arrow(angle);
newArrow.x = FIRING_POS_X;
newArrow.y = FIRING_POS_Y;
// Initialize last position for state tracking (e.g., off-screen detection)
newArrow.lastY = newArrow.y;
newArrow.lastX = newArrow.x;
// Add the arrow to the game scene and the tracking array.
game.addChild(newArrow);
arrows.push(newArrow);
LK.getSound('shoot').play(); // Play shooting sound.
arrowsFired++; // Increment arrow count.
if (arrowsFired >= 15) {
cooldownTimer = cooldownDuration; // Start cooldown.
arrowsFired = 0; // Reset arrow count.
LK.getSound('Reload').play(); // Play reload sound.
}
// Reset drag state.
dragStartX = null;
dragStartY = null;
// Potential enhancement: Hide the aiming indicator.
}
};
// --- Main Game Update Loop ---
// This function is called automatically by the LK engine on every frame (tick).
game.update = function () {
// Decrease cooldown timer if active.
if (cooldownTimer > 0) {
cooldownTimer--;
}
// 1. Update and check Arrows
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Note: LK engine calls arrow.update() automatically as it's added to the game stage.
// Initialize last position if it hasn't been set yet (first frame).
if (arrow.lastY === undefined) {
arrow.lastY = arrow.y;
}
if (arrow.lastX === undefined) {
arrow.lastX = arrow.x;
}
// Check for collisions between the current arrow and all enemies.
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
// Use the intersects method for collision detection.
if (arrow.intersects(enemy)) {
// Collision detected!
LK.setScore(LK.getScore() + 1); // Increment score.
scoreTxt.setText(LK.getScore()); // Update score display.
LK.getSound('hit').play(); // Play hit sound.
// Destroy the enemy and the arrow involved in the collision.
enemy.destroy();
enemies.splice(j, 1); // Remove enemy from array.
arrow.destroy();
arrows.splice(i, 1); // Remove arrow from array.
hitEnemy = true; // Mark that a hit occurred.
break; // An arrow can only hit one enemy per frame; stop checking this arrow.
}
}
// If the arrow hit an enemy, it was destroyed, so skip to the next arrow.
if (hitEnemy) {
continue;
}
// Check if the arrow has gone off-screen (top, left, or right).
// Use transition detection: check if it was on screen last frame and is off screen now.
var wasOnScreen = arrow.lastY > -arrow.height / 2 && arrow.lastX > -arrow.width / 2 && arrow.lastX < GAME_WIDTH + arrow.width / 2;
var isOffScreen = arrow.y < -arrow.height / 2 ||
// Off top edge
arrow.x < -arrow.width / 2 ||
// Off left edge
arrow.x > GAME_WIDTH + arrow.width / 2; // Off right edge
if (wasOnScreen && isOffScreen) {
// Arrow is off-screen, destroy it and remove from the array.
arrow.destroy();
arrows.splice(i, 1);
} else if (!isOffScreen) {
// Update last known position only if the arrow is still potentially on screen
arrow.lastY = arrow.y;
arrow.lastX = arrow.x;
}
}
// 2. Update and check Enemies
for (var k = enemies.length - 1; k >= 0; k--) {
var enemy = enemies[k];
// Note: LK engine calls enemy.update() automatically.
// Initialize last position if not set.
if (enemy.lastY === undefined) {
enemy.lastY = enemy.y;
}
// Check if the enemy has reached or passed the bastion line.
// Use transition detection: was the enemy's bottom edge above the line last frame,
// and is it on or below the line now?
var enemyBottomY = enemy.y + enemy.height / 2;
var enemyLastBottomY = enemy.lastY + enemy.height / 2;
var wasAboveBastion = enemyLastBottomY < BASTION_Y;
var isAtOrBelowBastion = enemyBottomY >= BASTION_Y;
if (wasAboveBastion && isAtOrBelowBastion) {
// Enemy reached the bastion! Game Over.
LK.getSound('gameOverSfx').play(); // Play game over sound effect.
LK.showGameOver(); // Trigger the engine's game over sequence.
// LK.showGameOver handles game state reset, no need to manually clear arrays here.
return; // Exit the update loop immediately as the game is over.
} else {
// Update last known position if game is not over for this enemy.
enemy.lastY = enemy.y;
}
}
// 3. Spawn new Enemies periodically
// Use LK.ticks and the spawn interval. Ensure interval doesn't go below minimum.
if (LK.ticks % Math.max(minEnemySpawnInterval, Math.floor(enemySpawnInterval)) === 0) {
// Determine the speed for the new enemy, capping at max speed.
var newEnemySpeed = Math.min(maxEnemySpeed, currentEnemySpeed);
var newEnemy = new Enemy(newEnemySpeed);
// Position the new enemy at the top of the screen at a random horizontal position.
// Add padding to avoid spawning exactly at the screen edges.
var spawnPadding = newEnemy.width / 2 + 20; // Add a little extra padding
newEnemy.x = spawnPadding + Math.random() * (GAME_WIDTH - 2 * spawnPadding);
newEnemy.y = -newEnemy.height / 2; // Start just above the top edge.
// Initialize last position for state tracking.
newEnemy.lastY = newEnemy.y;
// Add the new enemy to the game scene and the tracking array.
game.addChild(newEnemy);
enemies.push(newEnemy);
// Increase difficulty for the next spawn: decrease spawn interval and increase speed.
enemySpawnInterval -= enemySpawnRateDecrease;
currentEnemySpeed += enemySpeedIncrease;
}
};
// --- Initial Game Setup ---
// Set the initial score text based on the starting score (which is 0).
scoreTxt.setText(LK.getScore());
;
// Play the background music.
LK.playMusic('Gamemusic'); ===================================================================
--- original.js
+++ change.js
@@ -288,5 +288,8 @@
}
};
// --- Initial Game Setup ---
// Set the initial score text based on the starting score (which is 0).
-scoreTxt.setText(LK.getScore());
\ No newline at end of file
+scoreTxt.setText(LK.getScore());
+;
+// Play the background music.
+LK.playMusic('Gamemusic');
\ No newline at end of file
Arrow. In-Game asset. 2d. High contrast. No shadows. Topdown
Red stickman with a sword. In-Game asset. 2d. High contrast. No shadows. Topdown
Blue stickman with a bow. In-Game asset. 2d. High contrast. No shadows
Red stickman with an iron helmet, iron sword and iron shield. In-Game asset. 2d. High contrast. No shadows. No eyes
Red stickman with a knife and a thief's bandana. In-Game asset. 2d. High contrast. No shadows. No eyes
Purple stickman with a crown. In-Game asset. 2d. High contrast. No shadows
Blue stickman with a sword. In-Game asset. 2d. High contrast. No shadows
Tower. In-Game asset. 2d. High contrast. No shadows
Red stickman with a big wooden shield full of spikes. In-Game asset. 2d. High contrast. No shadows
Green stickman with a blue wizard hat and a staff; no eyes. In-Game asset. 2d. High contrast. No shadows
Red stickman with a golden knight helmet, gold sword and gold shield and gold boots. In-Game asset. 2d. High contrast. No shadows
Cannon. In-Game asset. 2d. High contrast. No shadows
Cannonball. In-Game asset. 2d. High contrast. No shadows
Yellow stickman with an azur wizard hat and staff on a tower. In-Game asset. 2d. High contrast. No shadows
Magic ice ball. In-Game asset. 2d. High contrast. No shadows
Green stickman with a Spartan helmet, Spartan shield and Spartan spear. In-Game asset. 2d. High contrast. No shadows
Green war elephant. In-Game asset. 2d. High contrast. No shadows
Yellow viking stickman holding an axe and is about to throw it. In-Game asset. 2d. High contrast. No shadows
Hatchet. In-Game asset. 2d. High contrast. No shadows
A red stickman with a big golden shield and golden armor. In-Game asset. 2d. High contrast. No shadows
Gray stickman with it's face covered with a black hood equipped with a bow In-Game asset. 2d. High contrast. No shadows, no eyes
Hot air balloon full of red stickmen. In-Game asset. 2d. High contrast. No shadows
Black war elephant with red eyes. In-Game asset. 2d. High contrast. No shadows
Red stickman that is a jester that is on a blue ball and is juggling. In-Game asset. 2d. High contrast. No shadows
Green stickman with a tribal mask and a stick to shoot darts. In-Game asset. 2d. High contrast. No shadows
White female stickman that is an angel with golden armor and a heavenly sword. In-Game asset. 2d. High contrast. No shadows
Wooden dart In-Game asset. 2d. High contrast. No shadows. Topdown
Orb of light. In-Game asset. 2d. High contrast. No shadows
Purple dragon with a red stickman riding it. In-Game asset. 2d. High contrast. No shadows
Add a Roman shield
Bomb. In-Game asset. 2d. High contrast. No shadows
Blue stickman with safety goggles, yellow safety helmet and a bomb. In-Game asset. 2d. High contrast. No shadows
Giant crossbow. In-Game asset. 2d. High contrast. No shadows. Topdown
Green stickman with a British soldier's hat and with a red flag with 2 swords. In-Game asset. 2d. High contrast. No shadows
Baby dragon from clash of clans. In-Game asset. 2d. High contrast. No shadows
Missile launcher BTD6. In-Game asset. 2d. High contrast. No shadows
Red Missile. In-Game asset. 2d. High contrast. No shadows