User prompt
buat satu musuh yang bisa menembak
User prompt
buat efek meledak pada musuh ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
kurangi jumlah jumlah musuh yang muncul secara drastis
User prompt
menara bisa menembak kesegala arah
Code edit (1 edits merged)
Please save this source code
User prompt
Dragon Guardian: Tower Defense
Initial prompt
buat permainan side scroller shooter penunggang naga terbang penjaga menara perak tinggi dalam hutan. menghancurkan kekuatan jahat yang ingin masuki menara
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Dragon = Container.expand(function () { var self = Container.call(this); var dragonGraphics = self.attachAsset('dragon', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.fireRate = 10; self.fireTimer = 0; self.speed = 8; self.update = function () { if (self.fireTimer > 0) { self.fireTimer--; } }; self.canShoot = function () { return self.fireTimer <= 0; }; self.shoot = function () { if (self.canShoot()) { var fireball = new Fireball(); fireball.x = self.x + 60; fireball.y = self.y; fireballs.push(fireball); game.addChild(fireball); self.fireTimer = self.fireRate; LK.getSound('shoot').play(); } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy1', { anchorX: 0.5, anchorY: 0.5 }); self.health = 10; self.speed = 3; self.damage = 10; self.hitCount = 0; self.maxHits = 5; self.dodgeCount = 0; self.maxDodges = 3; self.dodgeTimer = 0; self.isDodging = false; self.originalY = 0; self.fireRate = 90; self.fireTimer = 0; self.update = function () { self.x -= self.speed; if (self.fireTimer > 0) { self.fireTimer--; } if (self.dodgeTimer > 0) { self.dodgeTimer--; } // Trigger dodge randomly when enemy enters screen and hasn't used all dodges if (self.x < 1900 && self.x > 1800 && !self.isDodging && self.dodgeCount < self.maxDodges && self.dodgeTimer <= 0 && Math.random() < 0.4) { self.performDodge(); } // Shoot at dragon when in range if (self.x < 1600 && self.canShoot()) { self.shootAt(dragon.x, dragon.y); } }; self.canShoot = function () { return self.fireTimer <= 0; }; self.shootAt = function (targetX, targetY) { if (self.canShoot()) { var projectile = new EnemyProjectile(); projectile.x = self.x - 30; projectile.y = self.y; // Calculate direction towards dragon var deltaX = targetX - self.x; var deltaY = targetY - self.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance > 0) { projectile.directionX = deltaX / distance; projectile.directionY = deltaY / distance; } else { projectile.directionX = -1; projectile.directionY = 0; } enemyProjectiles.push(projectile); game.addChild(projectile); self.fireTimer = self.fireRate; LK.getSound('shoot').play(); } }; self.performDodge = function () { if (self.dodgeCount >= self.maxDodges || self.isDodging) return; self.isDodging = true; self.dodgeCount++; self.dodgeTimer = 120; // 2 second cooldown self.originalY = self.y; // Dodge up or down randomly var dodgeDirection = Math.random() < 0.5 ? -1 : 1; var dodgeDistance = 150; tween(self, { y: self.originalY + dodgeDistance * dodgeDirection }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Return to original position tween(self, { y: self.originalY }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { self.isDodging = false; } }); } }); }; self.takeDamage = function (damage) { self.hitCount++; LK.effects.flashObject(self, 0xff0000, 200); if (self.hitCount >= self.maxHits) { self.destroy(); return true; } return false; }; return self; }); var EnemyProjectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('enemyProjectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.damage = 10; self.directionX = -1; self.directionY = 0; self.update = function () { self.x += self.speed * self.directionX; self.y += self.speed * self.directionY; }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); var explosionGraphics = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5 }); self.lifespan = 30; self.maxLifespan = 30; self.update = function () { self.lifespan--; var progress = 1 - self.lifespan / self.maxLifespan; // Scale up then down if (progress < 0.3) { explosionGraphics.scaleX = explosionGraphics.scaleY = progress * 6; } else { explosionGraphics.scaleX = explosionGraphics.scaleY = (1 - progress) * 2; } // Fade out explosionGraphics.alpha = 1 - progress; // Remove when done if (self.lifespan <= 0) { self.destroy(); for (var i = explosions.length - 1; i >= 0; i--) { if (explosions[i] === self) { explosions.splice(i, 1); break; } } } }; return self; }); var FastEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy2', { anchorX: 0.5, anchorY: 0.5 }); self.health = 15; self.speed = 5; self.damage = 15; self.hitCount = 0; self.maxHits = 5; self.dodgeCount = 0; self.maxDodges = 3; self.dodgeTimer = 0; self.isDodging = false; self.originalY = 0; self.fireRate = 75; self.fireTimer = 0; self.update = function () { self.x -= self.speed; if (!self.isDodging) { self.y += Math.sin(self.x * 0.02) * 2; } if (self.fireTimer > 0) { self.fireTimer--; } if (self.dodgeTimer > 0) { self.dodgeTimer--; } // Trigger dodge randomly when enemy enters screen and hasn't used all dodges if (self.x < 1900 && self.x > 1800 && !self.isDodging && self.dodgeCount < self.maxDodges && self.dodgeTimer <= 0 && Math.random() < 0.5) { self.performDodge(); } // Shoot at dragon when in range if (self.x < 1700 && self.canShoot()) { self.shootAt(dragon.x, dragon.y); } }; self.canShoot = function () { return self.fireTimer <= 0; }; self.shootAt = function (targetX, targetY) { if (self.canShoot()) { var projectile = new EnemyProjectile(); projectile.x = self.x - 30; projectile.y = self.y; // Calculate direction towards dragon var deltaX = targetX - self.x; var deltaY = targetY - self.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance > 0) { projectile.directionX = deltaX / distance; projectile.directionY = deltaY / distance; } else { projectile.directionX = -1; projectile.directionY = 0; } enemyProjectiles.push(projectile); game.addChild(projectile); self.fireTimer = self.fireRate; LK.getSound('shoot').play(); } }; self.performDodge = function () { if (self.dodgeCount >= self.maxDodges || self.isDodging) return; self.isDodging = true; self.dodgeCount++; self.dodgeTimer = 100; // Shorter cooldown for fast enemy self.originalY = self.y; // Fast enemy does quicker, more agile dodges var dodgeDirection = Math.random() < 0.5 ? -1 : 1; var dodgeDistance = 180; tween(self, { y: self.originalY + dodgeDistance * dodgeDirection }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Return to original position tween(self, { y: self.originalY }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { self.isDodging = false; } }); } }); }; self.takeDamage = function (damage) { self.hitCount++; LK.effects.flashObject(self, 0xff0000, 200); if (self.hitCount >= self.maxHits) { self.destroy(); return true; } return false; }; return self; }); var Fireball = Container.expand(function () { var self = Container.call(this); var fireballGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.damage = 10; self.update = function () { self.x += self.speed; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.type = 'damage'; // damage, firerate, speed self.update = function () { self.x -= self.speed; self.rotation += 0.1; }; return self; }); var ShootingEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy2', { anchorX: 0.5, anchorY: 0.5 }); self.health = 20; self.speed = 2; self.damage = 20; self.fireRate = 60; self.fireTimer = 0; self.hitCount = 0; self.maxHits = 5; self.dodgeCount = 0; self.maxDodges = 3; self.dodgeTimer = 0; self.isDodging = false; self.originalY = 0; self.update = function () { self.x -= self.speed; if (self.fireTimer > 0) { self.fireTimer--; } if (self.dodgeTimer > 0) { self.dodgeTimer--; } // Trigger dodge randomly when enemy enters screen and hasn't used all dodges if (self.x < 1900 && self.x > 1800 && !self.isDodging && self.dodgeCount < self.maxDodges && self.dodgeTimer <= 0 && Math.random() < 0.35) { self.performDodge(); } // Shoot at dragon every second (60 ticks) when in range if (self.x < 1800 && self.canShoot()) { self.shootAt(dragon.x, dragon.y); } }; self.canShoot = function () { return self.fireTimer <= 0; }; self.shootAt = function (targetX, targetY) { if (self.canShoot()) { // Define 4 cardinal directions: North, East, South, West var directions = [{ x: 0, y: -1 }, // North { x: 1, y: 0 }, // East { x: 0, y: 1 }, // South { x: -1, y: 0 } // West ]; // Fire projectiles in all 4 directions for (var i = 0; i < directions.length; i++) { var projectile = new EnemyProjectile(); projectile.x = self.x - 30; projectile.y = self.y; projectile.directionX = directions[i].x; projectile.directionY = directions[i].y; enemyProjectiles.push(projectile); game.addChild(projectile); } self.fireTimer = self.fireRate; LK.getSound('shoot').play(); } }; self.performDodge = function () { if (self.dodgeCount >= self.maxDodges || self.isDodging) return; self.isDodging = true; self.dodgeCount++; self.dodgeTimer = 150; // Longer cooldown for shooting enemy self.originalY = self.y; // Shooting enemy does defensive dodges var dodgeDirection = Math.random() < 0.5 ? -1 : 1; var dodgeDistance = 120; tween(self, { y: self.originalY + dodgeDistance * dodgeDirection }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Return to original position tween(self, { y: self.originalY }, { duration: 700, easing: tween.easeInOut, onFinish: function onFinish() { self.isDodging = false; } }); } }); }; self.takeDamage = function (damage) { self.hitCount++; LK.effects.flashObject(self, 0xff0000, 200); if (self.hitCount >= self.maxHits) { self.destroy(); return true; } return false; }; return self; }); var Tower = Container.expand(function () { var self = Container.call(this); var towerGraphics = self.attachAsset('tower', { anchorX: 0.5, anchorY: 1.0 }); self.health = 200; self.fireRate = 60; self.fireTimer = 0; self.range = 400; self.update = function () { if (self.fireTimer > 0) { self.fireTimer--; } // Only shoot when there are enemies present if (self.canShoot() && enemies.length > 0) { self.shootAt(0, 0); // Launch homing projectile } }; self.canShoot = function () { return self.fireTimer <= 0; }; self.shootAt = function (targetX, targetY) { if (self.canShoot()) { var projectile = new TowerProjectile(); projectile.x = self.x; projectile.y = self.y - 100; // Start with slight upward direction, homing will take over projectile.directionX = 0.1; projectile.directionY = -0.3; towerProjectiles.push(projectile); game.addChild(projectile); self.fireTimer = self.fireRate; LK.getSound('towerShoot').play(); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.destroy(); return true; } return false; }; return self; }); var TowerFragment = Container.expand(function () { var self = Container.call(this); var fragmentGraphics = self.attachAsset('towerFragment', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 8; self.directionX = 1; self.directionY = 0; self.lifespan = 60; // 1 second at 60fps self.update = function () { self.x += self.speed * self.directionX; self.y += self.speed * self.directionY; self.lifespan--; if (self.lifespan <= 0) { self.destroy(); } }; return self; }); var TowerProjectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('towerProjectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.damage = 15; self.directionX = 0; self.directionY = 0; self.target = null; self.homingStrength = 0.08; // How aggressively it homes in self.maxLifespan = 300; // Maximum time before auto-explode (5 seconds) self.lifespan = 300; self.hasExploded = false; self.update = function () { if (!self.hasExploded) { self.lifespan--; // Find nearest enemy to target var nearestEnemy = null; var nearestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var deltaX = enemy.x - self.x; var deltaY = enemy.y - self.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = enemy; } } // Update target and direction if (nearestEnemy) { self.target = nearestEnemy; var deltaX = self.target.x - self.x; var deltaY = self.target.y - self.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance > 0) { // Gradually adjust direction towards target var targetDirX = deltaX / distance; var targetDirY = deltaY / distance; self.directionX += (targetDirX - self.directionX) * self.homingStrength; self.directionY += (targetDirY - self.directionY) * self.homingStrength; // Normalize direction var dirLength = Math.sqrt(self.directionX * self.directionX + self.directionY * self.directionY); if (dirLength > 0) { self.directionX /= dirLength; self.directionY /= dirLength; } } } self.x += self.speed * self.directionX; self.y += self.speed * self.directionY; // Auto-explode after max lifespan or if very close to target if (self.lifespan <= 0 || self.target && nearestDistance < 30) { self.explode(); } } }; self.explode = function () { if (self.hasExploded) return; self.hasExploded = true; // Create explosion effect createExplosion(self.x, self.y); // Create fragments in all directions var fragmentCount = 8; for (var i = 0; i < fragmentCount; i++) { var angle = i / fragmentCount * Math.PI * 2; var fragment = new TowerFragment(); fragment.x = self.x; fragment.y = self.y; fragment.directionX = Math.cos(angle); fragment.directionY = Math.sin(angle); towerFragments.push(fragment); game.addChild(fragment); } // Remove this projectile self.destroy(); for (var j = towerProjectiles.length - 1; j >= 0; j--) { if (towerProjectiles[j] === self) { towerProjectiles.splice(j, 1); break; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb }); /**** * Game Code ****/ // Background var forestBg = game.addChild(LK.getAsset('forestBg', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.7 })); // Make background image sharp and detailed by disabling texture smoothing if (forestBg.texture && forestBg.texture.baseTexture) { forestBg.texture.baseTexture.scaleMode = 0; // SCALE_MODES.NEAREST for sharp pixels forestBg.texture.baseTexture.mipmap = false; // Disable mipmapping for sharper details } // Game variables var dragon = game.addChild(new Dragon()); var fireballs = []; var enemies = []; var powerups = []; var explosions = []; var enemyProjectiles = []; var towerProjectiles = []; var towerFragments = []; var enemySpawnTimer = 0; var powerUpSpawnTimer = 0; var waveLevel = 1; var gameSpeed = 1; var survivalTime = 0; var enemiesKilled = 0; // Add tower var tower = game.addChild(new Tower()); tower.x = 200; tower.y = 2500; // Add floating animation to tower function startTowerFloating() { // Float up tween(tower, { y: tower.y - 30 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Float down tween(tower, { y: tower.y + 30 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Restart the floating cycle startTowerFloating(); } }); } }); } // Start the floating animation startTowerFloating(); // Position initial elements dragon.x = 1024; dragon.y = 1366; // UI Elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 150; scoreTxt.y = 50; LK.gui.topLeft.addChild(scoreTxt); var timeTxt = new Text2('Time: 0s', { size: 60, fill: 0xFFFFFF }); timeTxt.anchor.set(0.5, 0); LK.gui.top.addChild(timeTxt); var waveTxt = new Text2('Wave: 1', { size: 50, fill: 0xFFFFFF }); waveTxt.anchor.set(1, 0); LK.gui.topRight.addChild(waveTxt); function updateTime() { timeTxt.setText('Time: ' + Math.floor(survivalTime / 60) + 's'); } function updateScore() { scoreTxt.setText('Score: ' + LK.getScore()); } function updateWave() { waveTxt.setText('Wave: ' + waveLevel); } // Touch controls var isDragging = false; game.down = function (x, y, obj) { isDragging = true; dragon.shoot(); // Immediate visual feedback for better control feel LK.effects.flashObject(dragon, 0x00ff00, 200); // Smooth tween animation to touch position var targetX = Math.max(100, Math.min(1900, x)); var targetY = Math.max(100, Math.min(2600, y)); // Stop any existing movement tween tween.stop(dragon, { x: true, y: true }); // Animate smoothly to target position tween(dragon, { x: targetX, y: targetY }, { duration: 200, easing: tween.easeOut }); }; game.move = function (x, y, obj) { if (isDragging) { var targetX = Math.max(100, Math.min(1900, x)); var targetY = Math.max(100, Math.min(2600, y)); // Stop any existing movement tween for immediate responsiveness tween.stop(dragon, { x: true, y: true }); // Smooth tween animation to new position during drag tween(dragon, { x: targetX, y: targetY }, { duration: 150, easing: tween.easeOut }); } }; game.up = function (x, y, obj) { isDragging = false; }; // Spawn functions function spawnEnemy() { var enemy; var rand = Math.random(); if (rand < 0.2 + waveLevel * 0.05) { enemy = new ShootingEnemy(); } else if (rand < 0.4 + waveLevel * 0.1) { enemy = new FastEnemy(); } else { enemy = new Enemy(); } enemy.x = 2100; enemy.y = Math.random() * 2200 + 300; enemy.originalY = enemy.y; // Initialize original Y position for dodging enemies.push(enemy); game.addChild(enemy); } function spawnPowerUp() { var powerup = new PowerUp(); powerup.x = 2100; powerup.y = Math.random() * 2200 + 300; var rand = Math.random(); if (rand < 0.4) { powerup.type = 'damage'; } else if (rand < 0.7) { powerup.type = 'firerate'; } else { powerup.type = 'speed'; } powerups.push(powerup); game.addChild(powerup); } function createExplosion(x, y) { var explosion = new Explosion(); explosion.x = x; explosion.y = y; explosions.push(explosion); game.addChild(explosion); LK.getSound('explosion').play(); // Create additional tween effects for more dramatic explosion var particles = []; for (var i = 0; i < 5; i++) { var particle = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); particle.x = x; particle.y = y; game.addChild(particle); particles.push(particle); var randomX = x + (Math.random() - 0.5) * 200; var randomY = y + (Math.random() - 0.5) * 200; tween(particle, { x: randomX, y: randomY, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } } // Main game loop game.update = function () { // Update survival time survivalTime++; if (LK.ticks % 60 == 0) { updateTime(); } // Increase difficulty over time if (LK.ticks % 1800 == 0) { // Every 30 seconds waveLevel++; updateWave(); gameSpeed += 0.1; } // Spawn enemies enemySpawnTimer--; if (enemySpawnTimer <= 0) { spawnEnemy(); enemySpawnTimer = Math.max(300 - waveLevel * 8, 120); // Increased from 180 to 300, min from 60 to 120 } // Spawn power-ups occasionally powerUpSpawnTimer--; if (powerUpSpawnTimer <= 0) { if (Math.random() < 0.3) { spawnPowerUp(); } powerUpSpawnTimer = Math.random() * 600 + 300; // 5-15 seconds } // Update fireballs for (var i = fireballs.length - 1; i >= 0; i--) { var fireball = fireballs[i]; // Remove if off screen if (fireball.x > 2200) { fireball.destroy(); fireballs.splice(i, 1); continue; } // Check collision with enemy projectiles for (var k = enemyProjectiles.length - 1; k >= 0; k--) { var enemyProjectile = enemyProjectiles[k]; if (fireball.intersects(enemyProjectile)) { // Destroy both projectiles fireball.destroy(); fireballs.splice(i, 1); enemyProjectile.destroy(); enemyProjectiles.splice(k, 1); // Add small score bonus for defensive play LK.setScore(LK.getScore() + 5); updateScore(); LK.getSound('enemyHit').play(); // Create small explosion effect createExplosion(fireball.x, fireball.y); break; } } // Skip enemy collision check if fireball was already destroyed if (i >= fireballs.length) continue; // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (fireball.intersects(enemy)) { if (enemy.takeDamage(fireball.damage)) { createExplosion(enemy.x, enemy.y); enemies.splice(j, 1); enemiesKilled++; LK.setScore(LK.getScore() + 10); updateScore(); LK.getSound('enemyHit').play(); } fireball.destroy(); fireballs.splice(i, 1); break; } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Remove enemies that go off screen (left side) if (enemy.x < -100) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check collision with dragon - game over if hit if (enemy.intersects(dragon)) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } // Update power-ups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; // Remove if off screen if (powerup.x < -100) { powerup.destroy(); powerups.splice(i, 1); continue; } // Check collision with dragon if (powerup.intersects(dragon)) { if (powerup.type === 'damage') { dragon.damage = Math.min(dragon.damage + 5, 50); } else if (powerup.type === 'firerate') { dragon.fireRate = Math.max(dragon.fireRate - 2, 3); } else if (powerup.type === 'speed') { dragon.speed = Math.min(dragon.speed + 1, 15); } LK.getSound('powerUpCollect').play(); LK.effects.flashObject(dragon, 0xffd700, 500); powerup.destroy(); powerups.splice(i, 1); } } // Update enemy projectiles for (var i = enemyProjectiles.length - 1; i >= 0; i--) { var projectile = enemyProjectiles[i]; // Remove if off screen if (projectile.x < -100 || projectile.x > 2200 || projectile.y < -100 || projectile.y > 2800) { projectile.destroy(); enemyProjectiles.splice(i, 1); continue; } // Check collision with dragon - game over if hit if (projectile.intersects(dragon)) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } // Update tower projectiles for (var i = towerProjectiles.length - 1; i >= 0; i--) { var projectile = towerProjectiles[i]; // Remove if off screen (they should explode before this) if (projectile.x > 2200 || projectile.x < -100 || projectile.y > 2800 || projectile.y < -100) { projectile.destroy(); towerProjectiles.splice(i, 1); continue; } } // Update tower fragments for (var i = towerFragments.length - 1; i >= 0; i--) { var fragment = towerFragments[i]; // Remove if off screen or lifespan expired if (fragment.x > 2200 || fragment.x < -100 || fragment.y > 2800 || fragment.y < -100 || fragment.lifespan <= 0) { fragment.destroy(); towerFragments.splice(i, 1); continue; } // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (fragment.intersects(enemy)) { if (enemy.takeDamage(fragment.damage)) { createExplosion(enemy.x, enemy.y); enemies.splice(j, 1); enemiesKilled++; LK.setScore(LK.getScore() + 10); updateScore(); LK.getSound('enemyHit').play(); } fragment.destroy(); towerFragments.splice(i, 1); break; } } } // Check if enemies hit the tower for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.intersects(tower)) { if (tower.takeDamage(enemy.damage)) { // Tower destroyed - game over LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } enemy.destroy(); enemies.splice(i, 1); } } // Auto-shoot for dragon if (LK.ticks % 20 == 0) { dragon.shoot(); } // Smooth movement dampening when not actively dragging if (!isDragging) { // Apply slight dampening to make movement feel more natural dragon.x += (dragon.x - dragon.x) * 0.1; dragon.y += (dragon.y - dragon.y) * 0.1; } }; // Start background music LK.playMusic('bgmusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Dragon = Container.expand(function () {
var self = Container.call(this);
var dragonGraphics = self.attachAsset('dragon', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.fireRate = 10;
self.fireTimer = 0;
self.speed = 8;
self.update = function () {
if (self.fireTimer > 0) {
self.fireTimer--;
}
};
self.canShoot = function () {
return self.fireTimer <= 0;
};
self.shoot = function () {
if (self.canShoot()) {
var fireball = new Fireball();
fireball.x = self.x + 60;
fireball.y = self.y;
fireballs.push(fireball);
game.addChild(fireball);
self.fireTimer = self.fireRate;
LK.getSound('shoot').play();
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy1', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 10;
self.speed = 3;
self.damage = 10;
self.hitCount = 0;
self.maxHits = 5;
self.dodgeCount = 0;
self.maxDodges = 3;
self.dodgeTimer = 0;
self.isDodging = false;
self.originalY = 0;
self.fireRate = 90;
self.fireTimer = 0;
self.update = function () {
self.x -= self.speed;
if (self.fireTimer > 0) {
self.fireTimer--;
}
if (self.dodgeTimer > 0) {
self.dodgeTimer--;
}
// Trigger dodge randomly when enemy enters screen and hasn't used all dodges
if (self.x < 1900 && self.x > 1800 && !self.isDodging && self.dodgeCount < self.maxDodges && self.dodgeTimer <= 0 && Math.random() < 0.4) {
self.performDodge();
}
// Shoot at dragon when in range
if (self.x < 1600 && self.canShoot()) {
self.shootAt(dragon.x, dragon.y);
}
};
self.canShoot = function () {
return self.fireTimer <= 0;
};
self.shootAt = function (targetX, targetY) {
if (self.canShoot()) {
var projectile = new EnemyProjectile();
projectile.x = self.x - 30;
projectile.y = self.y;
// Calculate direction towards dragon
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
projectile.directionX = deltaX / distance;
projectile.directionY = deltaY / distance;
} else {
projectile.directionX = -1;
projectile.directionY = 0;
}
enemyProjectiles.push(projectile);
game.addChild(projectile);
self.fireTimer = self.fireRate;
LK.getSound('shoot').play();
}
};
self.performDodge = function () {
if (self.dodgeCount >= self.maxDodges || self.isDodging) return;
self.isDodging = true;
self.dodgeCount++;
self.dodgeTimer = 120; // 2 second cooldown
self.originalY = self.y;
// Dodge up or down randomly
var dodgeDirection = Math.random() < 0.5 ? -1 : 1;
var dodgeDistance = 150;
tween(self, {
y: self.originalY + dodgeDistance * dodgeDirection
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to original position
tween(self, {
y: self.originalY
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isDodging = false;
}
});
}
});
};
self.takeDamage = function (damage) {
self.hitCount++;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hitCount >= self.maxHits) {
self.destroy();
return true;
}
return false;
};
return self;
});
var EnemyProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('enemyProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 10;
self.directionX = -1;
self.directionY = 0;
self.update = function () {
self.x += self.speed * self.directionX;
self.y += self.speed * self.directionY;
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifespan = 30;
self.maxLifespan = 30;
self.update = function () {
self.lifespan--;
var progress = 1 - self.lifespan / self.maxLifespan;
// Scale up then down
if (progress < 0.3) {
explosionGraphics.scaleX = explosionGraphics.scaleY = progress * 6;
} else {
explosionGraphics.scaleX = explosionGraphics.scaleY = (1 - progress) * 2;
}
// Fade out
explosionGraphics.alpha = 1 - progress;
// Remove when done
if (self.lifespan <= 0) {
self.destroy();
for (var i = explosions.length - 1; i >= 0; i--) {
if (explosions[i] === self) {
explosions.splice(i, 1);
break;
}
}
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 15;
self.speed = 5;
self.damage = 15;
self.hitCount = 0;
self.maxHits = 5;
self.dodgeCount = 0;
self.maxDodges = 3;
self.dodgeTimer = 0;
self.isDodging = false;
self.originalY = 0;
self.fireRate = 75;
self.fireTimer = 0;
self.update = function () {
self.x -= self.speed;
if (!self.isDodging) {
self.y += Math.sin(self.x * 0.02) * 2;
}
if (self.fireTimer > 0) {
self.fireTimer--;
}
if (self.dodgeTimer > 0) {
self.dodgeTimer--;
}
// Trigger dodge randomly when enemy enters screen and hasn't used all dodges
if (self.x < 1900 && self.x > 1800 && !self.isDodging && self.dodgeCount < self.maxDodges && self.dodgeTimer <= 0 && Math.random() < 0.5) {
self.performDodge();
}
// Shoot at dragon when in range
if (self.x < 1700 && self.canShoot()) {
self.shootAt(dragon.x, dragon.y);
}
};
self.canShoot = function () {
return self.fireTimer <= 0;
};
self.shootAt = function (targetX, targetY) {
if (self.canShoot()) {
var projectile = new EnemyProjectile();
projectile.x = self.x - 30;
projectile.y = self.y;
// Calculate direction towards dragon
var deltaX = targetX - self.x;
var deltaY = targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
projectile.directionX = deltaX / distance;
projectile.directionY = deltaY / distance;
} else {
projectile.directionX = -1;
projectile.directionY = 0;
}
enemyProjectiles.push(projectile);
game.addChild(projectile);
self.fireTimer = self.fireRate;
LK.getSound('shoot').play();
}
};
self.performDodge = function () {
if (self.dodgeCount >= self.maxDodges || self.isDodging) return;
self.isDodging = true;
self.dodgeCount++;
self.dodgeTimer = 100; // Shorter cooldown for fast enemy
self.originalY = self.y;
// Fast enemy does quicker, more agile dodges
var dodgeDirection = Math.random() < 0.5 ? -1 : 1;
var dodgeDistance = 180;
tween(self, {
y: self.originalY + dodgeDistance * dodgeDirection
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to original position
tween(self, {
y: self.originalY
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isDodging = false;
}
});
}
});
};
self.takeDamage = function (damage) {
self.hitCount++;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hitCount >= self.maxHits) {
self.destroy();
return true;
}
return false;
};
return self;
});
var Fireball = Container.expand(function () {
var self = Container.call(this);
var fireballGraphics = self.attachAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 10;
self.update = function () {
self.x += self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.type = 'damage'; // damage, firerate, speed
self.update = function () {
self.x -= self.speed;
self.rotation += 0.1;
};
return self;
});
var ShootingEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 20;
self.speed = 2;
self.damage = 20;
self.fireRate = 60;
self.fireTimer = 0;
self.hitCount = 0;
self.maxHits = 5;
self.dodgeCount = 0;
self.maxDodges = 3;
self.dodgeTimer = 0;
self.isDodging = false;
self.originalY = 0;
self.update = function () {
self.x -= self.speed;
if (self.fireTimer > 0) {
self.fireTimer--;
}
if (self.dodgeTimer > 0) {
self.dodgeTimer--;
}
// Trigger dodge randomly when enemy enters screen and hasn't used all dodges
if (self.x < 1900 && self.x > 1800 && !self.isDodging && self.dodgeCount < self.maxDodges && self.dodgeTimer <= 0 && Math.random() < 0.35) {
self.performDodge();
}
// Shoot at dragon every second (60 ticks) when in range
if (self.x < 1800 && self.canShoot()) {
self.shootAt(dragon.x, dragon.y);
}
};
self.canShoot = function () {
return self.fireTimer <= 0;
};
self.shootAt = function (targetX, targetY) {
if (self.canShoot()) {
// Define 4 cardinal directions: North, East, South, West
var directions = [{
x: 0,
y: -1
},
// North
{
x: 1,
y: 0
},
// East
{
x: 0,
y: 1
},
// South
{
x: -1,
y: 0
} // West
];
// Fire projectiles in all 4 directions
for (var i = 0; i < directions.length; i++) {
var projectile = new EnemyProjectile();
projectile.x = self.x - 30;
projectile.y = self.y;
projectile.directionX = directions[i].x;
projectile.directionY = directions[i].y;
enemyProjectiles.push(projectile);
game.addChild(projectile);
}
self.fireTimer = self.fireRate;
LK.getSound('shoot').play();
}
};
self.performDodge = function () {
if (self.dodgeCount >= self.maxDodges || self.isDodging) return;
self.isDodging = true;
self.dodgeCount++;
self.dodgeTimer = 150; // Longer cooldown for shooting enemy
self.originalY = self.y;
// Shooting enemy does defensive dodges
var dodgeDirection = Math.random() < 0.5 ? -1 : 1;
var dodgeDistance = 120;
tween(self, {
y: self.originalY + dodgeDistance * dodgeDirection
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to original position
tween(self, {
y: self.originalY
}, {
duration: 700,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isDodging = false;
}
});
}
});
};
self.takeDamage = function (damage) {
self.hitCount++;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hitCount >= self.maxHits) {
self.destroy();
return true;
}
return false;
};
return self;
});
var Tower = Container.expand(function () {
var self = Container.call(this);
var towerGraphics = self.attachAsset('tower', {
anchorX: 0.5,
anchorY: 1.0
});
self.health = 200;
self.fireRate = 60;
self.fireTimer = 0;
self.range = 400;
self.update = function () {
if (self.fireTimer > 0) {
self.fireTimer--;
}
// Only shoot when there are enemies present
if (self.canShoot() && enemies.length > 0) {
self.shootAt(0, 0); // Launch homing projectile
}
};
self.canShoot = function () {
return self.fireTimer <= 0;
};
self.shootAt = function (targetX, targetY) {
if (self.canShoot()) {
var projectile = new TowerProjectile();
projectile.x = self.x;
projectile.y = self.y - 100;
// Start with slight upward direction, homing will take over
projectile.directionX = 0.1;
projectile.directionY = -0.3;
towerProjectiles.push(projectile);
game.addChild(projectile);
self.fireTimer = self.fireRate;
LK.getSound('towerShoot').play();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
var TowerFragment = Container.expand(function () {
var self = Container.call(this);
var fragmentGraphics = self.attachAsset('towerFragment', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 8;
self.directionX = 1;
self.directionY = 0;
self.lifespan = 60; // 1 second at 60fps
self.update = function () {
self.x += self.speed * self.directionX;
self.y += self.speed * self.directionY;
self.lifespan--;
if (self.lifespan <= 0) {
self.destroy();
}
};
return self;
});
var TowerProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('towerProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 15;
self.directionX = 0;
self.directionY = 0;
self.target = null;
self.homingStrength = 0.08; // How aggressively it homes in
self.maxLifespan = 300; // Maximum time before auto-explode (5 seconds)
self.lifespan = 300;
self.hasExploded = false;
self.update = function () {
if (!self.hasExploded) {
self.lifespan--;
// Find nearest enemy to target
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var deltaX = enemy.x - self.x;
var deltaY = enemy.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
// Update target and direction
if (nearestEnemy) {
self.target = nearestEnemy;
var deltaX = self.target.x - self.x;
var deltaY = self.target.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
// Gradually adjust direction towards target
var targetDirX = deltaX / distance;
var targetDirY = deltaY / distance;
self.directionX += (targetDirX - self.directionX) * self.homingStrength;
self.directionY += (targetDirY - self.directionY) * self.homingStrength;
// Normalize direction
var dirLength = Math.sqrt(self.directionX * self.directionX + self.directionY * self.directionY);
if (dirLength > 0) {
self.directionX /= dirLength;
self.directionY /= dirLength;
}
}
}
self.x += self.speed * self.directionX;
self.y += self.speed * self.directionY;
// Auto-explode after max lifespan or if very close to target
if (self.lifespan <= 0 || self.target && nearestDistance < 30) {
self.explode();
}
}
};
self.explode = function () {
if (self.hasExploded) return;
self.hasExploded = true;
// Create explosion effect
createExplosion(self.x, self.y);
// Create fragments in all directions
var fragmentCount = 8;
for (var i = 0; i < fragmentCount; i++) {
var angle = i / fragmentCount * Math.PI * 2;
var fragment = new TowerFragment();
fragment.x = self.x;
fragment.y = self.y;
fragment.directionX = Math.cos(angle);
fragment.directionY = Math.sin(angle);
towerFragments.push(fragment);
game.addChild(fragment);
}
// Remove this projectile
self.destroy();
for (var j = towerProjectiles.length - 1; j >= 0; j--) {
if (towerProjectiles[j] === self) {
towerProjectiles.splice(j, 1);
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Background
var forestBg = game.addChild(LK.getAsset('forestBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.7
}));
// Make background image sharp and detailed by disabling texture smoothing
if (forestBg.texture && forestBg.texture.baseTexture) {
forestBg.texture.baseTexture.scaleMode = 0; // SCALE_MODES.NEAREST for sharp pixels
forestBg.texture.baseTexture.mipmap = false; // Disable mipmapping for sharper details
}
// Game variables
var dragon = game.addChild(new Dragon());
var fireballs = [];
var enemies = [];
var powerups = [];
var explosions = [];
var enemyProjectiles = [];
var towerProjectiles = [];
var towerFragments = [];
var enemySpawnTimer = 0;
var powerUpSpawnTimer = 0;
var waveLevel = 1;
var gameSpeed = 1;
var survivalTime = 0;
var enemiesKilled = 0;
// Add tower
var tower = game.addChild(new Tower());
tower.x = 200;
tower.y = 2500;
// Add floating animation to tower
function startTowerFloating() {
// Float up
tween(tower, {
y: tower.y - 30
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Float down
tween(tower, {
y: tower.y + 30
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the floating cycle
startTowerFloating();
}
});
}
});
}
// Start the floating animation
startTowerFloating();
// Position initial elements
dragon.x = 1024;
dragon.y = 1366;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 150;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var timeTxt = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFFFF
});
waveTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(waveTxt);
function updateTime() {
timeTxt.setText('Time: ' + Math.floor(survivalTime / 60) + 's');
}
function updateScore() {
scoreTxt.setText('Score: ' + LK.getScore());
}
function updateWave() {
waveTxt.setText('Wave: ' + waveLevel);
}
// Touch controls
var isDragging = false;
game.down = function (x, y, obj) {
isDragging = true;
dragon.shoot();
// Immediate visual feedback for better control feel
LK.effects.flashObject(dragon, 0x00ff00, 200);
// Smooth tween animation to touch position
var targetX = Math.max(100, Math.min(1900, x));
var targetY = Math.max(100, Math.min(2600, y));
// Stop any existing movement tween
tween.stop(dragon, {
x: true,
y: true
});
// Animate smoothly to target position
tween(dragon, {
x: targetX,
y: targetY
}, {
duration: 200,
easing: tween.easeOut
});
};
game.move = function (x, y, obj) {
if (isDragging) {
var targetX = Math.max(100, Math.min(1900, x));
var targetY = Math.max(100, Math.min(2600, y));
// Stop any existing movement tween for immediate responsiveness
tween.stop(dragon, {
x: true,
y: true
});
// Smooth tween animation to new position during drag
tween(dragon, {
x: targetX,
y: targetY
}, {
duration: 150,
easing: tween.easeOut
});
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Spawn functions
function spawnEnemy() {
var enemy;
var rand = Math.random();
if (rand < 0.2 + waveLevel * 0.05) {
enemy = new ShootingEnemy();
} else if (rand < 0.4 + waveLevel * 0.1) {
enemy = new FastEnemy();
} else {
enemy = new Enemy();
}
enemy.x = 2100;
enemy.y = Math.random() * 2200 + 300;
enemy.originalY = enemy.y; // Initialize original Y position for dodging
enemies.push(enemy);
game.addChild(enemy);
}
function spawnPowerUp() {
var powerup = new PowerUp();
powerup.x = 2100;
powerup.y = Math.random() * 2200 + 300;
var rand = Math.random();
if (rand < 0.4) {
powerup.type = 'damage';
} else if (rand < 0.7) {
powerup.type = 'firerate';
} else {
powerup.type = 'speed';
}
powerups.push(powerup);
game.addChild(powerup);
}
function createExplosion(x, y) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
explosions.push(explosion);
game.addChild(explosion);
LK.getSound('explosion').play();
// Create additional tween effects for more dramatic explosion
var particles = [];
for (var i = 0; i < 5; i++) {
var particle = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
particle.x = x;
particle.y = y;
game.addChild(particle);
particles.push(particle);
var randomX = x + (Math.random() - 0.5) * 200;
var randomY = y + (Math.random() - 0.5) * 200;
tween(particle, {
x: randomX,
y: randomY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
// Main game loop
game.update = function () {
// Update survival time
survivalTime++;
if (LK.ticks % 60 == 0) {
updateTime();
}
// Increase difficulty over time
if (LK.ticks % 1800 == 0) {
// Every 30 seconds
waveLevel++;
updateWave();
gameSpeed += 0.1;
}
// Spawn enemies
enemySpawnTimer--;
if (enemySpawnTimer <= 0) {
spawnEnemy();
enemySpawnTimer = Math.max(300 - waveLevel * 8, 120); // Increased from 180 to 300, min from 60 to 120
}
// Spawn power-ups occasionally
powerUpSpawnTimer--;
if (powerUpSpawnTimer <= 0) {
if (Math.random() < 0.3) {
spawnPowerUp();
}
powerUpSpawnTimer = Math.random() * 600 + 300; // 5-15 seconds
}
// Update fireballs
for (var i = fireballs.length - 1; i >= 0; i--) {
var fireball = fireballs[i];
// Remove if off screen
if (fireball.x > 2200) {
fireball.destroy();
fireballs.splice(i, 1);
continue;
}
// Check collision with enemy projectiles
for (var k = enemyProjectiles.length - 1; k >= 0; k--) {
var enemyProjectile = enemyProjectiles[k];
if (fireball.intersects(enemyProjectile)) {
// Destroy both projectiles
fireball.destroy();
fireballs.splice(i, 1);
enemyProjectile.destroy();
enemyProjectiles.splice(k, 1);
// Add small score bonus for defensive play
LK.setScore(LK.getScore() + 5);
updateScore();
LK.getSound('enemyHit').play();
// Create small explosion effect
createExplosion(fireball.x, fireball.y);
break;
}
}
// Skip enemy collision check if fireball was already destroyed
if (i >= fireballs.length) continue;
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (fireball.intersects(enemy)) {
if (enemy.takeDamage(fireball.damage)) {
createExplosion(enemy.x, enemy.y);
enemies.splice(j, 1);
enemiesKilled++;
LK.setScore(LK.getScore() + 10);
updateScore();
LK.getSound('enemyHit').play();
}
fireball.destroy();
fireballs.splice(i, 1);
break;
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Remove enemies that go off screen (left side)
if (enemy.x < -100) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with dragon - game over if hit
if (enemy.intersects(dragon)) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
// Update power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
// Remove if off screen
if (powerup.x < -100) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with dragon
if (powerup.intersects(dragon)) {
if (powerup.type === 'damage') {
dragon.damage = Math.min(dragon.damage + 5, 50);
} else if (powerup.type === 'firerate') {
dragon.fireRate = Math.max(dragon.fireRate - 2, 3);
} else if (powerup.type === 'speed') {
dragon.speed = Math.min(dragon.speed + 1, 15);
}
LK.getSound('powerUpCollect').play();
LK.effects.flashObject(dragon, 0xffd700, 500);
powerup.destroy();
powerups.splice(i, 1);
}
}
// Update enemy projectiles
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
var projectile = enemyProjectiles[i];
// Remove if off screen
if (projectile.x < -100 || projectile.x > 2200 || projectile.y < -100 || projectile.y > 2800) {
projectile.destroy();
enemyProjectiles.splice(i, 1);
continue;
}
// Check collision with dragon - game over if hit
if (projectile.intersects(dragon)) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
// Update tower projectiles
for (var i = towerProjectiles.length - 1; i >= 0; i--) {
var projectile = towerProjectiles[i];
// Remove if off screen (they should explode before this)
if (projectile.x > 2200 || projectile.x < -100 || projectile.y > 2800 || projectile.y < -100) {
projectile.destroy();
towerProjectiles.splice(i, 1);
continue;
}
}
// Update tower fragments
for (var i = towerFragments.length - 1; i >= 0; i--) {
var fragment = towerFragments[i];
// Remove if off screen or lifespan expired
if (fragment.x > 2200 || fragment.x < -100 || fragment.y > 2800 || fragment.y < -100 || fragment.lifespan <= 0) {
fragment.destroy();
towerFragments.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (fragment.intersects(enemy)) {
if (enemy.takeDamage(fragment.damage)) {
createExplosion(enemy.x, enemy.y);
enemies.splice(j, 1);
enemiesKilled++;
LK.setScore(LK.getScore() + 10);
updateScore();
LK.getSound('enemyHit').play();
}
fragment.destroy();
towerFragments.splice(i, 1);
break;
}
}
}
// Check if enemies hit the tower
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(tower)) {
if (tower.takeDamage(enemy.damage)) {
// Tower destroyed - game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
enemy.destroy();
enemies.splice(i, 1);
}
}
// Auto-shoot for dragon
if (LK.ticks % 20 == 0) {
dragon.shoot();
}
// Smooth movement dampening when not actively dragging
if (!isDragging) {
// Apply slight dampening to make movement feel more natural
dragon.x += (dragon.x - dragon.x) * 0.1;
dragon.y += (dragon.y - dragon.y) * 0.1;
}
};
// Start background music
LK.playMusic('bgmusic');
silver red row dragon mecha side scroller. In-Game asset. 2d. High contrast. No shadows
goblin spear ghotic fantasy warplane. side scroller. In-Game asset. 2d. High contrast. No shadows
anime image realistic ghotic medieval futuristic landscape from distance add clear blue sky day In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows