Code edit (20 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'length')' in or related to this line: 'self.graphic = self.attachAsset(null, {}); // Start with no asset, will be set by init' Line Number: 472
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'length')' in or related to this line: 'self.graphic = self.attachAsset(null, {}); // Start with no asset' Line Number: 119
User prompt
Please fix the bug: 'Uncaught TypeError: LK.Rectangle is not a constructor' in or related to this line: 'var background = new LK.Rectangle({' Line Number: 559
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'barkButton.style.fill = 0xffcc00; // Restore color' Line Number: 748
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'height')' in or related to this line: 'var SCREEN_HEIGHT = LK.screen.height; // Get screen height /**** NEW ****/' Line Number: 435
User prompt
Please fix the bug: 'LK.getScreenSize is not a function' in or related to this line: 'var screenSize = LK.getScreenSize();' Line Number: 434
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'height')' in or related to this line: 'var SCREEN_HEIGHT = LK.canvas.height; // Get screen height /**** NEW ****/' Line Number: 434
Code edit (1 edits merged)
Please save this source code
User prompt
DOGE vs. Bureaucracy
Initial prompt
Create the foundational code for a 2D top-down Hero Defense game called "DOGE vs. Bureaucracy" using the LK Game Engine. The game features the Doge meme character defending a goal zone from waves of bureaucracy-themed enemies, assisted by office-supply-themed towers placed by the player. **I. Core Game Setup:** 1. Initialize the main game object using `LK.Game`. 2. Create necessary containers: `gameContainer` for gameplay elements (hero, enemies, towers, projectiles), and `uiContainer` for UI elements (text, buttons). Ensure `uiContainer` renders on top. 3. Define a variable `playerCurrency` initialized to a starting value (e.g., 100). 4. Define a `goalZone` object (can be a simple Container with position and size) with a `health` property (e.g., 100). **II. Hero Object (DOGE):** 1. Create a `Hero` class using `Container.expand`. 2. **Assets:** Use a placeholder asset `doge_sprite` (define via `LK.init.image`) for the visual representation. Include basic states like 'idle', 'walk', 'attack'. 3. **Stats:** Add properties for `health` (e.g., 50), `speed` (e.g., 3), and `attackRange` (e.g., 50), `attackDamage` (e.g., 5), `attackCooldown` (e.g., 0.5 seconds). Add a `currentAttackCooldown` timer. 4. **Movement:** * Implement click-to-move. Use `self.down` on the `gameContainer` (or a background layer) to get target coordinates. * In the `Hero.update` method, move the Hero towards the `targetX`, `targetY` at its `speed`. Stop when close to the target. Basic direction vector calculation is sufficient for now (no complex pathfinding needed initially). * Update the visual state to 'walk' when moving, 'idle' when stopped. 5. **Auto-Attack ("Much Bark"):** * In `Hero.update`, decrement `currentAttackCooldown`. * If `currentAttackCooldown <= 0`: * Find the nearest `Enemy` object within `attackRange`. * If an enemy is found: * Apply `attackDamage` to the enemy's health. * Reset `currentAttackCooldown` to `attackCooldown`. * Briefly set the visual state to 'attack'. * (Optional: Create a short-lived visual effect or placeholder `bark_projectile` object). **III. Enemy Object (Paperwork Swarm - Basic):** 1. Create an `Enemy` base class using `Container.expand`. Add basic properties like `health`, `speed`. 2. Create a `PaperworkEnemy` class inheriting from `Enemy` using `Container.expand`. 3. **Assets:** Use a placeholder asset `paper_sprite` (`LK.init.image`). 4. **Stats:** Set low `health` (e.g., 10) and moderate `speed` (e.g., 1.5). Add a property `currencyValue` (e.g., 5). 5. **Movement:** * Define a simple, predefined path using an array of coordinates `pathPoints`. * In `PaperworkEnemy.update`, move the enemy along the `pathPoints` towards the next point in the array at its `speed`. * If the enemy reaches the `goalZone`'s coordinates: decrease `goalZone.health` (e.g., by 10) and destroy the enemy object. 6. **Defeat:** When `health <= 0`, award `currencyValue` to `playerCurrency` and destroy the enemy object. **IV. Tower Object (Stapler Turret - Basic):** 1. Create a `Tower` base class using `Container.expand`. Add properties `cost`, `attackRange`, `attackDamage`, `attackCooldown`. 2. Create a `StaplerTower` class inheriting from `Tower` using `Container.expand`. 3. **Assets:** Use a placeholder asset `stapler_sprite` (`LK.init.image`). 4. **Stats:** Set `cost` (e.g., 50), `attackRange` (e.g., 100), `attackDamage` (e.g., 8), `attackCooldown` (e.g., 1 second). Add `currentAttackCooldown` timer. 5. **Placement:** * Create placeholder `BuildSpot` objects (simple Containers) at predefined locations. * When a `BuildSpot` is clicked (`self.down`): * If `playerCurrency >= StaplerTower.cost`: * Subtract the cost from `playerCurrency`. * Create a new `StaplerTower` instance at the `BuildSpot`'s position. * Make the `BuildSpot` inactive/occupied. 6. **Auto-Attack:** * In `StaplerTower.update`, decrement `currentAttackCooldown`. * If `currentAttackCooldown <= 0`: * Find the nearest `Enemy` within `attackRange`. * If an enemy is found: * Apply `attackDamage` to the enemy's health. * Reset `currentAttackCooldown` to `attackCooldown`. * (Optional: Create placeholder `staple_projectile` object traveling towards the enemy). **V. Basic Game Loop (`game.update`):** 1. Update the Hero instance. 2. Iterate through and update all active Enemy instances. Check for defeat conditions. 3. Iterate through and update all active Tower instances. 4. Implement basic enemy spawning: Use `LK.setInterval` or a timer within `game.update` to spawn a new `PaperworkEnemy` at a starting point every few seconds (e.g., 3 seconds). Add a counter to limit the total number of enemies spawned per wave (e.g., 10 enemies). 5. Check for lose condition: If `goalZone.health <= 0`, stop the game loop or display a "Game Over" message. 6. (Optional: Add win condition check - e.g., after X enemies spawned and defeated). **VI. Basic UI:** 1. Use `Text2` objects within the `uiContainer`. 2. Create text elements to display: * `playerCurrency`. * `goalZone.health`. 3. Update these text elements regularly (e.g., within `game.update` or only when values change). **Instructions for Ava:** * Use placeholder assets (like `doge_sprite`, `paper_sprite`, `stapler_sprite`) defined using `LK.init.image` with basic dimensions. I will replace these with actual art later. * Use simple geometric shapes (`LK.init.shape`) for projectiles or build spots if needed initially. * Focus on setting up the object structures (`Container.expand`), core properties, and the basic `update` logic for movement, attacking, spawning, and health/currency management. * Implement the click handling (`self.down`) for hero movement and tower placement. * Ensure basic collision detection logic (enemy reaching goal zone) and targeting logic (finding nearest enemy) is functional. * Keep the initial implementation simple; advanced features like multiple enemy/tower types, complex pathfinding, hero abilities, upgrades, detailed animations, sound effects, and sophisticated wave logic will be added later.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var BarkWave = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('barkWave', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.damage = 1; self.duration = 30; // frames self.radius = 100; self.maxRadius = 300; self.update = function () { self.radius += 10; graphic.scaleX = self.radius / 100; graphic.scaleY = self.radius / 100; graphic.alpha -= 0.015; // Check for enemies in range for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.radius) { enemy.takeDamage(self.damage); } } self.duration--; if (self.duration <= 0 || self.radius >= self.maxRadius) { self.destroy(); } }; return self; }); var BuildSpot = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('buildSpot', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.hasTower = false; self.tower = null; self.down = function (x, y, obj) { if (!self.hasTower && currency >= TOWER_COST) { self.buildTower(); } }; self.buildTower = function () { var tower = new StaplerTower(); tower.x = 0; tower.y = 0; self.addChild(tower); self.tower = tower; self.hasTower = true; currency -= TOWER_COST; currencyText.setText("$: " + currency); LK.getSound('buildTower').play(); }; return self; }); var DogeHero = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('dogeHero', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.targetX = self.x; self.targetY = self.y; self.barkCooldown = 0; self.barkRate = 120; // frames between barks self.update = function () { // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { dx = dx / distance * self.speed; dy = dy / distance * self.speed; self.x += dx; self.y += dy; } if (self.barkCooldown > 0) { self.barkCooldown--; } }; self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; }; self.bark = function () { if (self.barkCooldown <= 0) { var wave = new BarkWave(); wave.x = self.x; wave.y = self.y; game.addChild(wave); LK.getSound('dogeBark').play(); self.barkCooldown = self.barkRate; } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('enemyPaper', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.speed = 2; self.value = 10; // Currency earned when killed self.currentPathIndex = 0; self.update = function () { if (self.currentPathIndex < pathPoints.length) { var target = pathPoints[self.currentPathIndex]; var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 20) { self.currentPathIndex++; // Check if enemy reached the goal if (self.currentPathIndex >= pathPoints.length) { playerLives--; livesText.setText("Lives: " + playerLives); LK.getSound('enemyReachGoal').play(); if (playerLives <= 0) { // Game over if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } LK.showGameOver(); } self.destroy(); return; } } else { // Move towards the target point dx = dx / distance * self.speed; dy = dy / distance * self.speed; self.x += dx; self.y += dy; } } }; self.takeDamage = function (amount) { self.health -= amount; // Flash red when taking damage LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { currency += self.value; currencyText.setText("$: " + currency); LK.setScore(LK.getScore() + self.value); scoreText.setText("Score: " + LK.getScore()); LK.getSound('enemyDeath').play(); self.destroy(); } }; return self; }); var GameLevel = Container.expand(function () { var self = Container.call(this); self.createPath = function (pathPoints) { self.pathTiles = []; for (var i = 0; i < pathPoints.length - 1; i++) { var start = pathPoints[i]; var end = pathPoints[i + 1]; // Calculate direction and distance var dx = end.x - start.x; var dy = end.y - start.y; var distance = Math.sqrt(dx * dx + dy * dy); var steps = Math.ceil(distance / 100); for (var j = 0; j < steps; j++) { var ratio = j / steps; var x = start.x + dx * ratio; var y = start.y + dy * ratio; var tile = LK.getAsset('pathTile', { x: x, y: y, alpha: 0.5, anchorX: 0.5, anchorY: 0.5 }); self.addChild(tile); self.pathTiles.push(tile); } } }; self.createBuildSpots = function (spots) { self.buildSpots = []; for (var i = 0; i < spots.length; i++) { var spot = new BuildSpot(); spot.x = spots[i].x; spot.y = spots[i].y; self.addChild(spot); self.buildSpots.push(spot); } }; return self; }); var Goal = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('goal', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 }); return self; }); var StaplerTower = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('stapler', { anchorX: 0.5, anchorY: 0.5 }); self.fireRate = 60; // frames between shots self.range = 300; self.damage = 1; self.lastFired = 0; self.update = function () { self.lastFired++; if (self.lastFired >= self.fireRate) { // Find closest enemy var closestEnemy = null; var closestDistance = self.range; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - (self.parent.x + self.x); var dy = enemy.y - (self.parent.y + self.y); var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } if (closestEnemy) { self.shoot(closestEnemy); self.lastFired = 0; } } }; self.shoot = function (target) { var bullet = new TowerBullet(); var globalPos = self.parent.toGlobal(self.position); bullet.x = globalPos.x; bullet.y = globalPos.y; bullet.target = target; bullet.damage = self.damage; game.addChild(bullet); bullets.push(bullet); LK.getSound('shoot').play(); }; return self; }); var TowerBullet = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.damage = 1; self.target = null; self.update = function () { if (!self.target || self.target.health <= 0) { self.destroy(); return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 20) { self.target.takeDamage(self.damage); self.destroy(); return; } // Normalize and multiply by speed dx = dx / distance * self.speed; dy = dy / distance * self.speed; self.x += dx; self.y += dy; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xF0F0F0 }); /**** * Game Code ****/ // Game constants var TOWER_COST = 50; var WAVE_DELAY = 300; // frames between waves var MAX_WAVES = 10; // Game variables var currency = 100; var playerLives = 5; var currentWave = 0; var waveTimer = 0; var isWaveActive = false; var enemies = []; var bullets = []; var pathPoints = []; var level; var doge; var goal; // UI elements var scoreText = new Text2("Score: 0", { size: 50, fill: 0x000000 }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var waveText = new Text2("Wave: 0/" + MAX_WAVES, { size: 50, fill: 0x000000 }); waveText.anchor.set(0, 0); waveText.x = 100; LK.gui.topRight.addChild(waveText); var currencyText = new Text2("$: " + currency, { size: 50, fill: 0x000000 }); currencyText.anchor.set(0.5, 0); currencyText.y = 60; LK.gui.top.addChild(currencyText); var livesText = new Text2("Lives: " + playerLives, { size: 50, fill: 0x000000 }); livesText.anchor.set(0, 0); livesText.x = 100; livesText.y = 60; LK.gui.topRight.addChild(livesText); var infoText = new Text2("Tap to place towers ($" + TOWER_COST + ")\nDrag Doge & tap again to bark", { size: 40, fill: 0x000000 }); infoText.anchor.set(0.5, 1); LK.gui.bottom.addChild(infoText); // Initialize game level and path function initializeGame() { level = new GameLevel(); game.addChild(level); // Create path points pathPoints = [{ x: 0, y: 700 }, { x: 400, y: 700 }, { x: 400, y: 1200 }, { x: 1000, y: 1200 }, { x: 1000, y: 700 }, { x: 1600, y: 700 }, { x: 1600, y: 1800 }, { x: 1000, y: 1800 }, { x: 1000, y: 2300 }, { x: 1600, y: 2300 }]; level.createPath(pathPoints); // Create build spots var buildSpots = [{ x: 200, y: 500 }, { x: 600, y: 700 }, { x: 600, y: 1000 }, { x: 800, y: 1400 }, { x: 1200, y: 700 }, { x: 1200, y: 1000 }, { x: 1400, y: 1400 }, { x: 1800, y: 900 }, { x: 1800, y: 1600 }, { x: 800, y: 2100 }, { x: 1200, y: 2100 }, { x: 1800, y: 2300 }]; level.createBuildSpots(buildSpots); // Create goal goal = new Goal(); goal.x = pathPoints[pathPoints.length - 1].x; goal.y = pathPoints[pathPoints.length - 1].y; game.addChild(goal); // Create Doge hero doge = new DogeHero(); doge.x = 1024; doge.y = 1366; game.addChild(doge); // Reset game variables currency = 100; playerLives = 5; currentWave = 0; waveTimer = 0; isWaveActive = false; enemies = []; bullets = []; // Update UI currencyText.setText("$: " + currency); livesText.setText("Lives: " + playerLives); waveText.setText("Wave: " + currentWave + "/" + MAX_WAVES); // Start background music LK.playMusic('bgmusic'); } function spawnWave() { currentWave++; waveText.setText("Wave: " + currentWave + "/" + MAX_WAVES); var enemyCount = 5 + currentWave * 2; var spawnInterval = 60; // frames between enemy spawns function spawnEnemy(count) { if (count <= 0) { return; } var enemy = new Enemy(); enemy.x = pathPoints[0].x; enemy.y = pathPoints[0].y; // Increase difficulty with each wave enemy.health = 2 + Math.floor(currentWave / 2); if (currentWave > 5) { enemy.speed = 2.5; } if (currentWave > 8) { enemy.speed = 3; } game.addChild(enemy); enemies.push(enemy); LK.setTimeout(function () { spawnEnemy(count - 1); }, spawnInterval * 16); // Convert frames to ms (approx 60fps) } spawnEnemy(enemyCount); isWaveActive = true; } function checkWaveComplete() { if (isWaveActive && enemies.length === 0) { isWaveActive = false; waveTimer = 0; if (currentWave >= MAX_WAVES) { // Player wins if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } LK.showYouWin(); } } } // Event Handlers var dragDoge = false; game.down = function (x, y, obj) { // If clicking on doge, start dragging var dx = x - doge.x; var dy = y - doge.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 75) { dragDoge = true; } else { // If not dragging doge and doge is close enough, perform bark var dogeDistance = Math.sqrt(dx * dx + dy * dy); if (dogeDistance < 300) { doge.bark(); } else { // Otherwise, move doge to the tap position doge.setTarget(x, y); } } }; game.move = function (x, y, obj) { if (dragDoge) { doge.x = x; doge.y = y; } }; game.up = function (x, y, obj) { dragDoge = false; }; // Main game loop game.update = function () { // Spawn waves with delay if (!isWaveActive) { waveTimer++; if (waveTimer >= WAVE_DELAY && currentWave < MAX_WAVES) { spawnWave(); } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { if (!bullets[i].parent) { bullets.splice(i, 1); } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { if (!enemies[i].parent) { enemies.splice(i, 1); } } // Check if wave is complete checkWaveComplete(); }; // Initialize the game initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,554 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0
+});
+
+/****
+* Classes
+****/
+var BarkWave = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('barkWave', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ });
+ self.damage = 1;
+ self.duration = 30; // frames
+ self.radius = 100;
+ self.maxRadius = 300;
+ self.update = function () {
+ self.radius += 10;
+ graphic.scaleX = self.radius / 100;
+ graphic.scaleY = self.radius / 100;
+ graphic.alpha -= 0.015;
+ // Check for enemies in range
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ var dx = enemy.x - self.x;
+ var dy = enemy.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < self.radius) {
+ enemy.takeDamage(self.damage);
+ }
+ }
+ self.duration--;
+ if (self.duration <= 0 || self.radius >= self.maxRadius) {
+ self.destroy();
+ }
+ };
+ return self;
+});
+var BuildSpot = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('buildSpot', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ });
+ self.hasTower = false;
+ self.tower = null;
+ self.down = function (x, y, obj) {
+ if (!self.hasTower && currency >= TOWER_COST) {
+ self.buildTower();
+ }
+ };
+ self.buildTower = function () {
+ var tower = new StaplerTower();
+ tower.x = 0;
+ tower.y = 0;
+ self.addChild(tower);
+ self.tower = tower;
+ self.hasTower = true;
+ currency -= TOWER_COST;
+ currencyText.setText("$: " + currency);
+ LK.getSound('buildTower').play();
+ };
+ return self;
+});
+var DogeHero = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('dogeHero', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 5;
+ self.targetX = self.x;
+ self.targetY = self.y;
+ self.barkCooldown = 0;
+ self.barkRate = 120; // frames between barks
+ self.update = function () {
+ // Move towards target
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 5) {
+ dx = dx / distance * self.speed;
+ dy = dy / distance * self.speed;
+ self.x += dx;
+ self.y += dy;
+ }
+ if (self.barkCooldown > 0) {
+ self.barkCooldown--;
+ }
+ };
+ self.setTarget = function (x, y) {
+ self.targetX = x;
+ self.targetY = y;
+ };
+ self.bark = function () {
+ if (self.barkCooldown <= 0) {
+ var wave = new BarkWave();
+ wave.x = self.x;
+ wave.y = self.y;
+ game.addChild(wave);
+ LK.getSound('dogeBark').play();
+ self.barkCooldown = self.barkRate;
+ }
+ };
+ return self;
+});
+var Enemy = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('enemyPaper', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 3;
+ self.speed = 2;
+ self.value = 10; // Currency earned when killed
+ self.currentPathIndex = 0;
+ self.update = function () {
+ if (self.currentPathIndex < pathPoints.length) {
+ var target = pathPoints[self.currentPathIndex];
+ var dx = target.x - self.x;
+ var dy = target.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 20) {
+ self.currentPathIndex++;
+ // Check if enemy reached the goal
+ if (self.currentPathIndex >= pathPoints.length) {
+ playerLives--;
+ livesText.setText("Lives: " + playerLives);
+ LK.getSound('enemyReachGoal').play();
+ if (playerLives <= 0) {
+ // Game over
+ if (LK.getScore() > storage.highScore) {
+ storage.highScore = LK.getScore();
+ }
+ LK.showGameOver();
+ }
+ self.destroy();
+ return;
+ }
+ } else {
+ // Move towards the target point
+ dx = dx / distance * self.speed;
+ dy = dy / distance * self.speed;
+ self.x += dx;
+ self.y += dy;
+ }
+ }
+ };
+ self.takeDamage = function (amount) {
+ self.health -= amount;
+ // Flash red when taking damage
+ LK.effects.flashObject(self, 0xff0000, 200);
+ if (self.health <= 0) {
+ currency += self.value;
+ currencyText.setText("$: " + currency);
+ LK.setScore(LK.getScore() + self.value);
+ scoreText.setText("Score: " + LK.getScore());
+ LK.getSound('enemyDeath').play();
+ self.destroy();
+ }
+ };
+ return self;
+});
+var GameLevel = Container.expand(function () {
+ var self = Container.call(this);
+ self.createPath = function (pathPoints) {
+ self.pathTiles = [];
+ for (var i = 0; i < pathPoints.length - 1; i++) {
+ var start = pathPoints[i];
+ var end = pathPoints[i + 1];
+ // Calculate direction and distance
+ var dx = end.x - start.x;
+ var dy = end.y - start.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ var steps = Math.ceil(distance / 100);
+ for (var j = 0; j < steps; j++) {
+ var ratio = j / steps;
+ var x = start.x + dx * ratio;
+ var y = start.y + dy * ratio;
+ var tile = LK.getAsset('pathTile', {
+ x: x,
+ y: y,
+ alpha: 0.5,
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.addChild(tile);
+ self.pathTiles.push(tile);
+ }
+ }
+ };
+ self.createBuildSpots = function (spots) {
+ self.buildSpots = [];
+ for (var i = 0; i < spots.length; i++) {
+ var spot = new BuildSpot();
+ spot.x = spots[i].x;
+ spot.y = spots[i].y;
+ self.addChild(spot);
+ self.buildSpots.push(spot);
+ }
+ };
+ return self;
+});
+var Goal = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('goal', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ });
+ return self;
+});
+var StaplerTower = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('stapler', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.fireRate = 60; // frames between shots
+ self.range = 300;
+ self.damage = 1;
+ self.lastFired = 0;
+ self.update = function () {
+ self.lastFired++;
+ if (self.lastFired >= self.fireRate) {
+ // Find closest enemy
+ var closestEnemy = null;
+ var closestDistance = self.range;
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ var dx = enemy.x - (self.parent.x + self.x);
+ var dy = enemy.y - (self.parent.y + self.y);
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestEnemy = enemy;
+ }
+ }
+ if (closestEnemy) {
+ self.shoot(closestEnemy);
+ self.lastFired = 0;
+ }
+ }
+ };
+ self.shoot = function (target) {
+ var bullet = new TowerBullet();
+ var globalPos = self.parent.toGlobal(self.position);
+ bullet.x = globalPos.x;
+ bullet.y = globalPos.y;
+ bullet.target = target;
+ bullet.damage = self.damage;
+ game.addChild(bullet);
+ bullets.push(bullet);
+ LK.getSound('shoot').play();
+ };
+ return self;
+});
+var TowerBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('bullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 10;
+ self.damage = 1;
+ self.target = null;
+ self.update = function () {
+ if (!self.target || self.target.health <= 0) {
+ self.destroy();
+ return;
+ }
+ var dx = self.target.x - self.x;
+ var dy = self.target.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 20) {
+ self.target.takeDamage(self.damage);
+ self.destroy();
+ return;
+ }
+ // Normalize and multiply by speed
+ dx = dx / distance * self.speed;
+ dy = dy / distance * self.speed;
+ self.x += dx;
+ self.y += dy;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0xF0F0F0
+});
+
+/****
+* Game Code
+****/
+// Game constants
+var TOWER_COST = 50;
+var WAVE_DELAY = 300; // frames between waves
+var MAX_WAVES = 10;
+// Game variables
+var currency = 100;
+var playerLives = 5;
+var currentWave = 0;
+var waveTimer = 0;
+var isWaveActive = false;
+var enemies = [];
+var bullets = [];
+var pathPoints = [];
+var level;
+var doge;
+var goal;
+// UI elements
+var scoreText = new Text2("Score: 0", {
+ size: 50,
+ fill: 0x000000
+});
+scoreText.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreText);
+var waveText = new Text2("Wave: 0/" + MAX_WAVES, {
+ size: 50,
+ fill: 0x000000
+});
+waveText.anchor.set(0, 0);
+waveText.x = 100;
+LK.gui.topRight.addChild(waveText);
+var currencyText = new Text2("$: " + currency, {
+ size: 50,
+ fill: 0x000000
+});
+currencyText.anchor.set(0.5, 0);
+currencyText.y = 60;
+LK.gui.top.addChild(currencyText);
+var livesText = new Text2("Lives: " + playerLives, {
+ size: 50,
+ fill: 0x000000
+});
+livesText.anchor.set(0, 0);
+livesText.x = 100;
+livesText.y = 60;
+LK.gui.topRight.addChild(livesText);
+var infoText = new Text2("Tap to place towers ($" + TOWER_COST + ")\nDrag Doge & tap again to bark", {
+ size: 40,
+ fill: 0x000000
+});
+infoText.anchor.set(0.5, 1);
+LK.gui.bottom.addChild(infoText);
+// Initialize game level and path
+function initializeGame() {
+ level = new GameLevel();
+ game.addChild(level);
+ // Create path points
+ pathPoints = [{
+ x: 0,
+ y: 700
+ }, {
+ x: 400,
+ y: 700
+ }, {
+ x: 400,
+ y: 1200
+ }, {
+ x: 1000,
+ y: 1200
+ }, {
+ x: 1000,
+ y: 700
+ }, {
+ x: 1600,
+ y: 700
+ }, {
+ x: 1600,
+ y: 1800
+ }, {
+ x: 1000,
+ y: 1800
+ }, {
+ x: 1000,
+ y: 2300
+ }, {
+ x: 1600,
+ y: 2300
+ }];
+ level.createPath(pathPoints);
+ // Create build spots
+ var buildSpots = [{
+ x: 200,
+ y: 500
+ }, {
+ x: 600,
+ y: 700
+ }, {
+ x: 600,
+ y: 1000
+ }, {
+ x: 800,
+ y: 1400
+ }, {
+ x: 1200,
+ y: 700
+ }, {
+ x: 1200,
+ y: 1000
+ }, {
+ x: 1400,
+ y: 1400
+ }, {
+ x: 1800,
+ y: 900
+ }, {
+ x: 1800,
+ y: 1600
+ }, {
+ x: 800,
+ y: 2100
+ }, {
+ x: 1200,
+ y: 2100
+ }, {
+ x: 1800,
+ y: 2300
+ }];
+ level.createBuildSpots(buildSpots);
+ // Create goal
+ goal = new Goal();
+ goal.x = pathPoints[pathPoints.length - 1].x;
+ goal.y = pathPoints[pathPoints.length - 1].y;
+ game.addChild(goal);
+ // Create Doge hero
+ doge = new DogeHero();
+ doge.x = 1024;
+ doge.y = 1366;
+ game.addChild(doge);
+ // Reset game variables
+ currency = 100;
+ playerLives = 5;
+ currentWave = 0;
+ waveTimer = 0;
+ isWaveActive = false;
+ enemies = [];
+ bullets = [];
+ // Update UI
+ currencyText.setText("$: " + currency);
+ livesText.setText("Lives: " + playerLives);
+ waveText.setText("Wave: " + currentWave + "/" + MAX_WAVES);
+ // Start background music
+ LK.playMusic('bgmusic');
+}
+function spawnWave() {
+ currentWave++;
+ waveText.setText("Wave: " + currentWave + "/" + MAX_WAVES);
+ var enemyCount = 5 + currentWave * 2;
+ var spawnInterval = 60; // frames between enemy spawns
+ function spawnEnemy(count) {
+ if (count <= 0) {
+ return;
+ }
+ var enemy = new Enemy();
+ enemy.x = pathPoints[0].x;
+ enemy.y = pathPoints[0].y;
+ // Increase difficulty with each wave
+ enemy.health = 2 + Math.floor(currentWave / 2);
+ if (currentWave > 5) {
+ enemy.speed = 2.5;
+ }
+ if (currentWave > 8) {
+ enemy.speed = 3;
+ }
+ game.addChild(enemy);
+ enemies.push(enemy);
+ LK.setTimeout(function () {
+ spawnEnemy(count - 1);
+ }, spawnInterval * 16); // Convert frames to ms (approx 60fps)
+ }
+ spawnEnemy(enemyCount);
+ isWaveActive = true;
+}
+function checkWaveComplete() {
+ if (isWaveActive && enemies.length === 0) {
+ isWaveActive = false;
+ waveTimer = 0;
+ if (currentWave >= MAX_WAVES) {
+ // Player wins
+ if (LK.getScore() > storage.highScore) {
+ storage.highScore = LK.getScore();
+ }
+ LK.showYouWin();
+ }
+ }
+}
+// Event Handlers
+var dragDoge = false;
+game.down = function (x, y, obj) {
+ // If clicking on doge, start dragging
+ var dx = x - doge.x;
+ var dy = y - doge.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 75) {
+ dragDoge = true;
+ } else {
+ // If not dragging doge and doge is close enough, perform bark
+ var dogeDistance = Math.sqrt(dx * dx + dy * dy);
+ if (dogeDistance < 300) {
+ doge.bark();
+ } else {
+ // Otherwise, move doge to the tap position
+ doge.setTarget(x, y);
+ }
+ }
+};
+game.move = function (x, y, obj) {
+ if (dragDoge) {
+ doge.x = x;
+ doge.y = y;
+ }
+};
+game.up = function (x, y, obj) {
+ dragDoge = false;
+};
+// Main game loop
+game.update = function () {
+ // Spawn waves with delay
+ if (!isWaveActive) {
+ waveTimer++;
+ if (waveTimer >= WAVE_DELAY && currentWave < MAX_WAVES) {
+ spawnWave();
+ }
+ }
+ // Update bullets
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ if (!bullets[i].parent) {
+ bullets.splice(i, 1);
+ }
+ }
+ // Update enemies
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ if (!enemies[i].parent) {
+ enemies.splice(i, 1);
+ }
+ }
+ // Check if wave is complete
+ checkWaveComplete();
+};
+// Initialize the game
+initializeGame();
\ No newline at end of file
Stapler Turret Sprite Sheet: An office stapler mounted on a simple rotating base images show it opening and closing.. In-Game asset. 2d. High contrast. No shadows
Stapler bullet. In-Game asset. 2d. High contrast. No shadows
Remove the background
A stylized golden fire hydrant labeled "Free Speech" OR a glowing server rack labeled "Meme Archive".. In-Game asset. 2d. High contrast. No shadows
Paperclip. In-Game asset. 2d. High contrast. No shadows
A simple, slightly glowing circular outline indicating where towers can be placed.. In-Game asset. 2d. High contrast. No shadows
More cabinet, More Files
black circle. In-Game asset. 2d. High contrast. No shadows
DOGE Enemy Auditor. In-Game asset. 2d. High contrast. No shadows
grow the image and have papers fall from the folders
Squish the image like the cabinet is squeezing in on itself
Red Tape enemy extends as if bouncing while moving
Envelope flying through the air with wings. In-Game asset. 2d. High contrast. No shadows
"Laser Cat Perch": A cat with laser eyes that "targets" and zaps high-priority enemies with precision. (Internet loves cats).. In-Game asset. 2d. High contrast. No shadows
"Rickroller": A RickAstley tower holding a mic. In-Game asset. 2d. High contrast. No shadows
"'This Is Fine' Fire Pit": A tower resembling the "This is Fine" dog meme.. In-Game asset. 2d. High contrast. No shadows
Sell icon with a money symbol. In-Game asset. 2d. High contrast. No shadows
DOGE Coin. In-Game asset. 2d. High contrast. No shadows
Realistic MEME of Rick Astley dancing with mic. In-Game asset. 2d. High contrast. No shadows
Range Circle. In-Game asset. 2d. High contrast. No shadows
Shape: A tall, sleek, perhaps slightly intimidating rectangular or obelisk-like structure. Think modern skyscraper aesthetics scaled down. Material/Color: Polished chrome, brushed aluminum, dark grey, or a very clean white. Minimalist. Details: Maybe a single, subtly glowing slit or a small, focused lens near the top where the "restructuring energy" will eventually be directed from (though the actual effect happens on the target). Very clean lines, sharp edges. A small, almost unnoticeable corporate logo (maybe a stylized "R" or an abstract "efficiency" symbol). No visible moving parts when idle. It's about quiet, decisive power. Meme Angle: Evokes the feeling of an unapproachable, all-powerful corporate entity or a consultant's "black box" solution.. In-Game asset. 2d. High contrast. No shadows
Beam of disintegration. In-Game asset. 2d. High contrast. No shadows
Intern holding a coffee cup running 3 frames. In-Game asset. 2d. High contrast. No shadows