User prompt
silahı büyüt tekrar
User prompt
keskin nişancın kendisini küçült silahını biraz büyüt
User prompt
riffle sniper silahı 5 mermi normal riffle silahı 5 mermi otamatik riffle 30 mermi şeklinde şarjorler olsun mermi doldurma animasyonuda olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
silahı büyüt
User prompt
silahların boyutunu biraz büyüt
User prompt
keskin nişancıyı büyüt
User prompt
duvar fazla büyük olmuş biraz küçük
User prompt
Duvar büyüklüğü daha fazla olsun ayrıca duvar kendi assets olsun keskin nişancı ile aynı olmasın
User prompt
karakterimiz biraz daha büyük olsun
User prompt
yaptığımız duvarlar daha büyük olsun ayrıca düşmanlar duvarın içinden geçemesin ve duvarı kırmaya başlar hatta duvarı kırırken animasyon olsun kafasını geriye alıp ileri doğru hızle dönerek duvara hasar veriyormuş gibi yapsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
duvarları bir kez satın aldığımızda tekrar satın ala biliyoruz tek seferliğine satın almıyoruz ayrıca yapı mağazasında sıkıntı var onuda düzelt hit box sıkıtnıs var
User prompt
When we purchase structures, a semi-transparent wall appears in our hands. We can place this wall wherever we want. When a monster comes to the placed wall, it collides with the wall and breaks it. While the wall is breaking, its health is visible with a small bar
User prompt
yapıları satın aldığımızda elimize yarım saydam bir duvar geliyor bu duvarı istediğimiz yere koya biliyoruz ve koyduğumuz yere canavar geldiğinde canvar duvara çarpıyor ve duvarı kırıyor duvar kırlırken duvarın canı gözüküyor küçük bar ile
User prompt
yapılar mağzasını biraz daha sağ ve aşşağa haraket ettir
User prompt
sol üst köşeye yeni yapı mağzası yap içinde 3 tane yapı olsun yapıların fiyatı sırayla 10-20-30 olacak ilk baştaki duvar sonraki daha güçlü duvar diğeri ise keskin nişancı kulesi
User prompt
silah sıktığımızca silahın namlusunda ateş efekti olsun
User prompt
tamam düşmanlar öldükten sonra yan yatsın ve soluklaşarak yok olsun
User prompt
gölgeler çalışmadı düşmanlarda gözükmüyor
User prompt
düşmanların altında gölge olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
etrafta çalılar ve ağaçlar dursun ama etkileşim olmasın
User prompt
score artıkça aynanda doğan düşmanlar artsın
User prompt
etrafa çalıları yerleştir hitbox yok
User prompt
score artıkça düşman çeşidi artsın ve düşman doğmo hızı ona göre artsın
User prompt
kayayı ve keskin nişancının boyutunu artır kayayı daha fazl artır boyunu
User prompt
ilk başta 10 düşman ile başlasın sonra %25 yerine %50 artırılsın sayı istenilen sayıya ulaşıldığında otomatik olarak bütün düşmanlar ölsün
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, currency: 0 }); /**** * Classes ****/ var BuildingShop = Container.expand(function () { var self = Container.call(this); self.isOpen = false; self.buildings = [{ name: "Basic Wall", price: 10, health: 100, owned: false }, { name: "Reinforced Wall", price: 20, health: 200, owned: false }, { name: "Sniper Tower", price: 30, health: 150, damage: 2, fireRate: 2000, owned: false }]; // Shop button self.shopButton = new Text2("BUILDINGS", { size: 80, fill: 0xFFFF00 }); self.shopButton.anchor.set(0.5, 0); // Add background to make button more visible var buttonBg = LK.getAsset('bullet', { width: 300, height: 100, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); buttonBg.alpha = 0.8; buttonBg.y = self.shopButton.height / 2; self.addChild(buttonBg); self.addChild(self.shopButton); // Shop panel (hidden by default) self.panel = new Container(); self.panel.visible = false; self.addChild(self.panel); // Create building options self.buildingItems = []; for (var i = 0; i < self.buildings.length; i++) { var building = self.buildings[i]; var item = new Container(); var bg = LK.getAsset('bullet', { width: 400, height: 150, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); bg.alpha = 0.8; item.addChild(bg); var title = new Text2(building.name, { size: 40, fill: 0xFFFFFF }); title.anchor.set(0.5, 0); title.y = -50; item.addChild(title); var info; if (building.name === "Sniper Tower") { info = new Text2("Health: " + building.health + " | Damage: " + building.damage, { size: 30, fill: 0xFFFFFF }); } else { info = new Text2("Health: " + building.health, { size: 30, fill: 0xFFFFFF }); } info.anchor.set(0.5, 0); info.y = 0; item.addChild(info); var priceText = new Text2(building.owned ? "OWNED" : "$" + building.price, { size: 35, fill: building.owned ? 0x00FF00 : 0xFFFF00 }); priceText.anchor.set(0.5, 0); priceText.y = 40; item.addChild(priceText); item.y = i * 200; item.buildingIndex = i; self.buildingItems.push(item); self.panel.addChild(item); } // Position panel self.panel.y = 100; // Handle shop button press self.shopButton.down = function (x, y, obj) { self.toggleShop(); }; // Toggle shop visibility self.toggleShop = function () { self.isOpen = !self.isOpen; self.panel.visible = self.isOpen; }; // Handle building selection/purchase self.selectBuilding = function (index) { var building = self.buildings[index]; if (building.owned) { // Create a placeable wall to follow cursor var buildingType; var buildingHealth = building.health; if (index === 0) { buildingType = 'basic'; } else if (index === 1) { buildingType = 'reinforced'; } else if (index === 2) { buildingType = 'sniper'; } // Create and add placeable wall game.placeableWall = new PlaceableWall(buildingType, buildingHealth); game.addChild(game.placeableWall); game.isPlacing = true; // Close shop after selection self.toggleShop(); return true; } else if (currency >= building.price) { // Purchase building currency -= building.price; building.owned = true; // Update UI var priceText = self.buildingItems[index].children[3]; priceText.setText("OWNED", { fill: 0x00FF00 }); LK.getSound('upgrade').play(); updateUI(); // After purchase, immediately select it for placement WITHOUT recursion // Create placeable wall var buildingType; var buildingHealth = building.health; if (index === 0) { buildingType = 'basic'; } else if (index === 1) { buildingType = 'reinforced'; } else if (index === 2) { buildingType = 'sniper'; } // Create and add placeable wall game.placeableWall = new PlaceableWall(buildingType, buildingHealth); game.addChild(game.placeableWall); game.isPlacing = true; // Close shop self.toggleShop(); return true; } else { // Not enough currency LK.effects.flashScreen(0xFF0000, 300); return false; } }; // Check if an item was clicked self.checkItemClick = function (x, y) { if (!self.isOpen) return false; var pos = self.toLocal({ x: x, y: y }); for (var i = 0; i < self.buildingItems.length; i++) { var item = self.buildingItems[i]; // Improve hit detection with both x and y checks if (pos.y >= item.y - 75 && pos.y <= item.y + 75 && pos.x >= -200 && pos.x <= 200) { return self.selectBuilding(item.buildingIndex); } } return false; }; // Add down event handlers to each building item for (var i = 0; i < self.buildingItems.length; i++) { var item = self.buildingItems[i]; item.interactive = true; item.index = i; // Store the index // Using custom event handler for each item (function (index) { item.down = function (x, y, obj) { self.selectBuilding(index); }; })(i); } return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); self.graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; // Default speed, will be overridden self.damage = 1; // Default damage, will be overridden self.active = true; self.update = function () { if (!self.active) return; // Use directional movement if speedX and speedY are defined if (self.speedX !== undefined && self.speedY !== undefined) { self.x += self.speedX; self.y += self.speedY; } else { // Fallback to original vertical-only movement self.y -= self.speed; } // Bullet goes off screen (check all edges) if (self.y < -50 || self.y > 2732 + 50 || self.x < -50 || self.x > 2048 + 50) { self.active = false; } }; self.hit = function () { self.active = false; LK.getSound('enemyHit').play(); LK.effects.flashObject(self, 0xffffff, 200); }; return self; }); var Bunker = Container.expand(function () { var self = Container.call(this); self.graphics = self.attachAsset('bunker', { anchorX: 0.5, anchorY: 0.5 }); self.damageIndicator = self.attachAsset('damageIndicator', { anchorX: 0.5, anchorY: 0.5 }); self.damageIndicator.alpha = 0; self.damageIndicator.originalX = 0; self.damageIndicator.originalY = 0; self.showDamage = function (percentage) { // Make indicator more visible as health decreases self.damageIndicator.alpha = 1 - percentage; // Move the indicator based on health percentage // Lower health = more movement var moveFactor = (1 - percentage) * 10; self.damageIndicator.x = self.damageIndicator.originalX + (Math.random() * 2 - 1) * moveFactor; self.damageIndicator.y = self.damageIndicator.originalY + (Math.random() * 2 - 1) * moveFactor; // Change tint to become redder as health decreases var healthColor = Math.floor(percentage * 255); self.damageIndicator.tint = 255 << 16 | healthColor << 8 | healthColor; }; // Store original position self.onAddedToStage = function () { self.damageIndicator.originalX = self.damageIndicator.x; self.damageIndicator.originalY = self.damageIndicator.y; }; return self; }); var Bush = Container.expand(function () { var self = Container.call(this); // Random bush appearance with slight variation var type = Math.floor(Math.random() * 3); var size = Math.random() * 0.5 + 0.8; // Size between 0.8 and 1.3 var rotation = Math.random() * 0.3 - 0.15; // Slight rotation // Create the bush using bullet shape with green tint self.graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0x2E8B57, // Sea green color scaleX: size, scaleY: size }); // Apply random rotation self.graphics.rotation = rotation; // Add some details to make bushes look different from each other if (type === 0) { // First type - taller bush self.graphics.scale.y *= 1.3; self.graphics.tint = 0x228B22; // Forest green } else if (type === 1) { // Second type - wider bush self.graphics.scale.x *= 1.2; self.graphics.tint = 0x006400; // Dark green } else { // Third type - round bush self.graphics.tint = 0x3CB371; // Medium sea green } return self; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'regular'; // Set properties based on enemy type switch (self.type) { case 'fast': self.graphics = self.attachAsset('fastEnemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.5 }); self.speed = 3; self.hp = 1; self.damage = 10; self.points = 15; self.currency = 2; break; case 'tank': self.graphics = self.attachAsset('tankEnemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.5 }); self.speed = 1; self.hp = 5; self.damage = 25; self.points = 30; self.currency = 5; break; default: // regular self.graphics = self.attachAsset('regularEnemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.5 }); self.speed = 2; self.hp = 2; self.damage = 15; self.points = 10; self.currency = 1; } // Create and add shadow beneath enemy self.shadow = new Shadow(); self.shadow.y = 30; // Position shadow slightly below enemy // Update shadow size based on enemy type var baseWidth = self.graphics.width * self.graphics.scale.x; self.shadow.updateSize(baseWidth); self.addChildAt(self.shadow, 0); // Add shadow behind the enemy // Ensure the shadow is visible and properly positioned self.shadow.x = 0; self.shadow.graphics.scale.x = baseWidth * 0.8 / 100; self.shadow.graphics.alpha = 0.5; self.active = true; self.update = function () { if (!self.active) return; // Basic diagonal movement pattern if (!self.moveDirection) { self.moveDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction self.moveCounter = 0; self.maxMoveDistance = Math.random() * 30 + 20; // Random move distance self.isAttackingWall = false; self.attackTarget = null; self.attackAnimationTicks = 0; } // If enemy is attacking a wall, perform attack animation if (self.isAttackingWall && self.attackTarget) { // Increment animation counter self.attackAnimationTicks++; // Every 45 frames complete a full attack cycle if (self.attackAnimationTicks < 20) { // Pull back for attack - move head backwards if (self.attackAnimationTicks === 1) { tween(self.graphics, { rotation: -0.3, y: -10 }, { duration: 300, easing: tween.easeOut }); } } else if (self.attackAnimationTicks < 25) { // Forward strike - move head forward quickly if (self.attackAnimationTicks === 20) { tween(self.graphics, { rotation: 0.2, y: 10 }, { duration: 150, easing: tween.easeIn }); } } else { // Reset animation counter and damage the wall self.attackAnimationTicks = 0; // Apply damage to wall if (self.attackTarget) { self.attackTarget.takeDamage(self.damage / 5); // Show damage effect LK.effects.flashObject(self.attackTarget, 0xFF0000, 200); } } // When wall is destroyed, resume movement if (!self.attackTarget || self.attackTarget.health <= 0) { self.isAttackingWall = false; self.attackTarget = null; // Reset position and rotation tween(self.graphics, { rotation: 0, y: 0 }, { duration: 200, easing: tween.easeOut }); } return; // Don't move while attacking } // Move diagonally self.y += self.speed; self.x += self.moveDirection * (self.speed * 0.5); // Switch direction after a certain distance self.moveCounter += self.speed; if (self.moveCounter >= self.maxMoveDistance) { self.moveDirection *= -1; // Reverse direction self.moveCounter = 0; self.maxMoveDistance = Math.random() * 30 + 20; // New random distance } // Make the shadow grow or shrink slightly with height simulation // Calculate height simulation based on movement cycle var heightSimulation = Math.sin(LK.ticks * 0.05) * 0.1; // Update shadow properties to create floating effect self.shadow.graphics.alpha = 0.5 - heightSimulation * 0.1; // Vary opacity with more baseline visibility self.shadow.graphics.scale.x = self.graphics.width * self.graphics.scale.x * 0.8 / 100 * (1 - heightSimulation); // Vary size // Ensure shadow follows enemy even with movement self.shadow.x = 0; // Add walking animation if (LK.ticks % 10 === 0 && !self.isAttackingWall) { // Tilt the enemy slightly in the direction of movement tween(self.graphics, { rotation: self.moveDirection * 0.1 }, { duration: 250, easing: tween.easeInOut }); } // Ensure enemy stays within screen bounds if (self.x < 50) { self.x = 50; self.moveDirection = 1; } else if (self.x > 2048 - 50) { self.x = 2048 - 50; self.moveDirection = -1; } // Check if enemy reached the bunker if (self.y > bunkerY - 50) { self.attackBunker(); } }; self.takeDamage = function (amount) { self.hp -= amount; if (self.hp <= 0) { self.die(); } else { LK.effects.flashObject(self, 0xffffff, 200); } }; self.die = function () { // Fade out shadow when enemy dies tween(self.shadow.graphics, { alpha: 0 }, { duration: 300 }); // Rotate enemy to make it lie on its side (90 degrees in radians) tween(self.graphics, { rotation: Math.PI / 2, alpha: 0.2 }, { duration: 500, easing: tween.easeOut }); // After rotation, fade out completely LK.setTimeout(function () { if (self.graphics) { tween(self.graphics, { alpha: 0 }, { duration: 800, easing: tween.easeIn }); } }, 400); self.active = false; var currentScore = LK.getScore(); var scoreMultiplier = 1; // Increase rewards based on score progression if (currentScore > 300) { scoreMultiplier = 2.5; } else if (currentScore > 200) { scoreMultiplier = 2; } else if (currentScore > 100) { scoreMultiplier = 1.5; } LK.setScore(currentScore + self.points); // Set different currency values based on enemy type with score multiplier if (self.type === 'regular') { currency += Math.ceil(3 * scoreMultiplier); } else if (self.type === 'fast') { currency += Math.ceil(4 * scoreMultiplier); } else if (self.type === 'tank') { currency += Math.ceil(6 * scoreMultiplier); } else { currency += Math.ceil(self.currency * scoreMultiplier); // Fallback } updateUI(); }; self.startAttackingWall = function (wall) { self.isAttackingWall = true; self.attackTarget = wall; self.attackAnimationTicks = 0; }; self.attackBunker = function () { bunkerHealth -= self.damage; updateBunkerHealth(); LK.getSound('bunkerHit').play(); LK.effects.flashObject(bunker, 0xff0000, 500); // Make damage indicator visible when taking damage bunker.damageIndicator.alpha = 1; self.active = false; // Check if bunker is destroyed if (bunkerHealth <= 0) { gameOver(); } }; return self; }); var MuzzleFlash = Container.expand(function () { var self = Container.call(this); // Create the flash using bullet shape with yellow-white tint self.graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFF99 // Bright yellow-white color for flash }); // Initially scale small self.graphics.scale.set(0.3, 0.3); self.graphics.alpha = 0.9; // Animation lifetime self.duration = 100; // ms self.startTime = 0; self.active = false; // Start the flash effect self.flash = function () { self.active = true; self.startTime = Date.now(); self.visible = true; // Reset and start animation self.graphics.scale.set(0.8, 0.8); self.graphics.alpha = 1; }; // Update the flash animation self.update = function () { if (!self.active) return; var elapsed = Date.now() - self.startTime; var progress = elapsed / self.duration; if (progress >= 1) { // Animation complete self.active = false; self.visible = false; return; } // Animate scale and alpha self.graphics.scale.set(0.8 * (1 - progress), 0.8 * (1 - progress)); self.graphics.alpha = 1 - progress; }; // Hide initially self.visible = false; return self; }); var PlaceableWall = Container.expand(function (buildingType, buildingHealth) { var self = Container.call(this); // Create semi-transparent wall based on type if (buildingType === 'reinforced') { self.graphics = self.attachAsset('reinforcedWall', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); } else if (buildingType === 'sniper') { // Create a tower self.graphics = self.attachAsset('sniperTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); // No need to add extra sniper on top since it's included in the image } else { // Basic wall self.graphics = self.attachAsset('basicWall', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); } // Make it semi-transparent self.alpha = 0.7; // Store building properties for when it's placed self.buildingType = buildingType; self.buildingHealth = buildingHealth; return self; }); var Shadow = Container.expand(function () { var self = Container.call(this); // Create shadow using bullet shape self.graphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0x000000 }); // Set shadow properties self.graphics.alpha = 0.5; // More visible shadow // Squish the shadow to appear flat on the ground self.graphics.scale.y = 0.3; // Ensure the shadow is visible with default size self.graphics.scale.x = 0.8; // Method to update shadow size based on parent self.updateSize = function (parentWidth) { // Make shadow slightly smaller than parent self.graphics.scale.x = parentWidth * 0.8 / 100; }; return self; }); var Sniper = Container.expand(function () { var self = Container.call(this); self.graphics = self.attachAsset('sniper', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); // Add rifle that will rotate toward cursor self.rifle = self.attachAsset('rifle', { anchorX: 0, anchorY: 0.5, scaleX: 1.7, scaleY: 1.7 }); // Create references to all weapon graphics but only show the active one self.weapons = { basic: self.rifle, sniper: LK.getAsset('sniper_rifle', { anchorX: 0, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }), machine: LK.getAsset('machine_gun', { anchorX: 0, anchorY: 0.5, scaleX: 1.7, scaleY: 1.7 }) }; // Add other weapons but hide them initially self.weapons.sniper.visible = false; self.weapons.machine.visible = false; self.weapons.sniper.x = 10; self.weapons.machine.x = 10; self.addChild(self.weapons.sniper); self.addChild(self.weapons.machine); // Position rifle to appear like it's being held by the sniper self.rifle.x = 10; // Initialize weapon positions Object.keys(self.weapons).forEach(function (key) { // Standard positioning self.weapons[key].x = 10; self.weapons[key].y = 0; if (key === 'basic') { self.weapons[key].scale.x = 1.7; self.weapons[key].scale.y = 1.7; } else if (key === 'sniper') { self.weapons[key].scale.x = 2.0; self.weapons[key].scale.y = 2.0; } else { self.weapons[key].scale.x = 1.7; self.weapons[key].scale.y = 1.7; } }); // Create muzzle flash effects for each weapon self.muzzleFlashes = {}; Object.keys(self.weapons).forEach(function (key) { var flash = new MuzzleFlash(); self.weapons[key].addChild(flash); // Position at the end of each weapon flash.x = self.weapons[key].width - 10; flash.y = 0; self.muzzleFlashes[key] = flash; }); self.fireRate = 1000; // ms between shots self.lastShot = 0; self.bulletDamage = 1; self.bulletSpeed = 15; // Default bullet speed self.currentWeapon = 'basic'; // Track current weapon type // Method to update rifle rotation based on cursor position self.updateAim = function (targetX, targetY) { // Calculate angle to target var angle = Math.atan2(targetY - self.y, targetX - self.x); // Determine if target is on left or right side of the screen var isTargetOnLeftSide = targetX < 2048 / 2; // Update sniper graphics based on which side target is on if (isTargetOnLeftSide) { // Target is on left side - character faces left self.graphics.scale.x = -1; // Flip character horizontally // Adjust weapon positions for left-facing stance Object.keys(self.weapons).forEach(function (key) { self.weapons[key].x = -10; // Offset for left side self.weapons[key].scale.x = -1; // Flip weapon horizontally }); } else { // Target is on right side - character faces right self.graphics.scale.x = 1; // Normal orientation // Adjust weapon positions for right-facing stance Object.keys(self.weapons).forEach(function (key) { self.weapons[key].x = 10; // Normal position on right side self.weapons[key].scale.x = 1; // Normal weapon orientation }); } // Set all weapons rotation to aim at target, properly adjusted for direction if (isTargetOnLeftSide) { // When facing left, we need to adjust the angle self.weapons.basic.rotation = angle + Math.PI; self.weapons.sniper.rotation = angle + Math.PI; self.weapons.machine.rotation = angle + Math.PI; } else { self.weapons.basic.rotation = angle; self.weapons.sniper.rotation = angle; self.weapons.machine.rotation = angle; } return angle; }; self.canShoot = function () { var now = Date.now(); if (now - self.lastShot >= self.fireRate) { self.lastShot = now; return true; } return false; }; self.switchWeapon = function (weaponIndex) { // Hide all weapons first self.weapons.basic.visible = false; self.weapons.sniper.visible = false; self.weapons.machine.visible = false; // Show selected weapon based on index switch (weaponIndex) { case 0: self.weapons.basic.visible = true; self.currentWeapon = 'basic'; break; case 1: self.weapons.sniper.visible = true; self.currentWeapon = 'sniper'; break; case 2: self.weapons.machine.visible = true; self.currentWeapon = 'machine'; break; default: self.weapons.basic.visible = true; self.currentWeapon = 'basic'; } // Reset magazine if switching weapon var mag = magazines[self.currentWeapon]; if (mag && mag.current > mag.max) mag.current = mag.max; updateAmmoUI(); }; self.shoot = function (targetX, targetY) { // Magazine and reload logic var weapon = self.currentWeapon; var mag = magazines[weapon]; if (mag.reloading) return null; if (mag.current <= 0) { // Start reload mag.reloading = true; updateAmmoUI(); // Animate reload: move weapon down and up, and show "reloading..." in UI tween(self.weapons[weapon], { y: 60, alpha: 0.5 }, { duration: Math.floor(mag.reloadTime * 0.4), easing: tween.easeIn, onFinish: function onFinish() { tween(self.weapons[weapon], { y: 0, alpha: 1 }, { duration: Math.floor(mag.reloadTime * 0.6), easing: tween.easeOut }); } }); LK.setTimeout(function () { mag.current = mag.max; mag.reloading = false; updateAmmoUI(); }, mag.reloadTime); return null; } if (!self.canShoot()) return null; mag.current--; updateAmmoUI(); // Update rifle aim var angle = self.updateAim(targetX, targetY); var bullet = new Bullet(); // Determine if target is on left or right side of the screen var isTargetOnLeftSide = targetX < 2048 / 2; var activeWeapon = self.weapons[self.currentWeapon]; var rifleLength = activeWeapon.width; // Calculate bullet spawn position at end of rifle, with direction awareness var bulletAngle = angle; if (isTargetOnLeftSide) { // When facing left, we need to adjust calculations bulletAngle = angle + Math.PI; // Adjust for left facing } // Calculate proper bullet starting position and direction bullet.x = self.x + Math.cos(bulletAngle) * rifleLength; bullet.y = self.y + Math.sin(bulletAngle) * rifleLength; // Set bullet direction - always use the original angle for bullet direction bullet.speedX = Math.cos(angle) * bullet.speed; bullet.speedY = Math.sin(angle) * bullet.speed; bullet.damage = self.bulletDamage; bullet.speed = self.bulletSpeed; // Set bullet speed from sniper // Customize bullet appearance based on weapon type if (self.currentWeapon === 'sniper') { bullet.graphics.tint = 0x33CCFF; // Blue tint for sniper bullets bullet.graphics.scale.set(0.8, 1.5); // Thinner, longer bullets } else if (self.currentWeapon === 'machine') { bullet.graphics.tint = 0xFFCC33; // Orange tint for machine gun bullets bullet.graphics.scale.set(1.2, 0.8); // Wider, shorter bullets } // Trigger muzzle flash for current weapon var muzzleFlash = self.muzzleFlashes[self.currentWeapon]; if (muzzleFlash) { muzzleFlash.flash(); } // Add weapon recoil effect based on weapon type var recoilDistance = 10; // Default recoil for rifle var recoilDuration = 100; // Default recoil recovery time var originX = activeWeapon.x; // Set different recoil parameters based on weapon type if (self.currentWeapon === 'sniper') { recoilDistance = 20; // Stronger recoil for sniper recoilDuration = 150; } else if (self.currentWeapon === 'machine') { recoilDistance = 12; // Moderate recoil for machine gun recoilDuration = 80; } // Calculate recoil direction (opposite to shot direction) // For recoil, we need to consider which direction the weapon is facing var recoilDirection = isTargetOnLeftSide ? 1 : -1; // Reverse for left-facing var recoilX = recoilDirection * Math.cos(bulletAngle) * recoilDistance; var recoilY = -Math.sin(bulletAngle) * recoilDistance; // Apply recoil to the active weapon tween(activeWeapon, { x: originX + recoilX, y: recoilY }, { duration: 50, // Quick recoil easing: tween.easeOut, onFinish: function onFinish() { // Recover from recoil tween(activeWeapon, { x: originX, y: 0 }, { duration: recoilDuration, easing: tween.easeInOut }); } }); LK.getSound('shoot').play(); return bullet; }; return self; }); var Tree = Container.expand(function () { var self = Container.call(this); // Random tree appearance with variation var type = Math.floor(Math.random() * 3); var size = Math.random() * 0.7 + 1.2; // Size between 1.2 and 1.9 var rotation = Math.random() * 0.2 - 0.1; // Slight rotation // Create the tree trunk using bullet shape with brown tint var treeTrunk = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0x8B4513, // Saddle brown color scaleX: size * 0.3, scaleY: size * 0.8 }); // Create the tree crown using bullet shape with green tint var treeCrown = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0x228B22, // Forest green color scaleX: size * 1.2, scaleY: size * 1.0 }); // Position crown on top of trunk treeCrown.y = -treeTrunk.height * 0.5; // Apply random rotation self.rotation = rotation; // Add some details to make trees look different from each other if (type === 0) { // First type - taller tree with darker green treeCrown.scale.y *= 1.4; treeCrown.tint = 0x006400; // Dark green } else if (type === 1) { // Second type - wider tree with lighter green treeCrown.scale.x *= 1.3; treeCrown.tint = 0x32CD32; // Lime green } else { // Third type - autumn tree with different color treeCrown.tint = 0xFF8C00; // Dark orange } return self; }); var Wall = Container.expand(function (type, health) { var self = Container.call(this); // Set properties based on wall type self.type = type || 'basic'; self.maxHealth = health || 100; self.health = self.maxHealth; // Create wall graphic based on type if (self.type === 'reinforced') { self.graphics = self.attachAsset('reinforcedWall', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); } else if (self.type === 'sniper') { // Create a tower self.graphics = self.attachAsset('sniperTower', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); // No need to add extra sniper on top since it's included in the image } else { // Basic wall self.graphics = self.attachAsset('basicWall', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); } // Add health bar self.healthBar = new Container(); self.addChild(self.healthBar); // Health bar background self.healthBarBg = LK.getAsset('bullet', { anchorX: 0.5, anchorY: 0.5, tint: 0x000000, scaleX: 3, scaleY: 0.3 }); self.healthBarBg.y = -40; self.healthBar.addChild(self.healthBarBg); // Health bar fill self.healthBarFill = LK.getAsset('bullet', { anchorX: 0, anchorY: 0.5, tint: 0x00FF00, scaleX: 3, scaleY: 0.2 }); self.healthBarFill.y = -40; self.healthBarFill.x = -self.healthBarBg.width / 2; self.healthBar.addChild(self.healthBarFill); // Hide health bar initially self.healthBar.visible = false; self.update = function () { // Show health bar if damaged if (self.health < self.maxHealth) { self.healthBar.visible = true; // Update health bar fill var healthPercent = self.health / self.maxHealth; self.healthBarFill.scale.x = 3 * healthPercent; // Change color based on health if (healthPercent < 0.3) { self.healthBarFill.tint = 0xFF0000; // Red } else if (healthPercent < 0.6) { self.healthBarFill.tint = 0xFFFF00; // Yellow } else { self.healthBarFill.tint = 0x00FF00; // Green } } }; self.takeDamage = function (amount) { self.health -= amount; if (self.health <= 0) { self.destroy(); return true; // Wall destroyed } return false; // Wall still standing }; return self; }); var WaveCountdown = Container.expand(function () { var self = Container.call(this); self.countdownTime = 60; // 60 seconds default self.active = false; // Create countdown text self.countdownText = new Text2(self.countdownTime, { size: 150, fill: 0xFFFFFF }); self.countdownText.anchor.set(0.5, 0.5); self.addChild(self.countdownText); // Create skip button self.skipButton = new Text2("SKIP", { size: 80, fill: 0xFFFF00 }); self.skipButton.anchor.set(0.5, 0.5); self.skipButton.y = 100; self.addChild(self.skipButton); // Skip button background for better visibility var skipButtonBg = LK.getAsset('bullet', { width: 200, height: 100, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); skipButtonBg.alpha = 0.8; skipButtonBg.y = 100; self.addChild(skipButtonBg); // Custom swap implementation since swapChildren is not available var parent = self.skipButton.parent; var skipButtonIndex = parent.children.indexOf(skipButtonBg); var buttonIndex = parent.children.indexOf(self.skipButton); // Manual reordering of children to create swap effect if (skipButtonIndex !== -1 && buttonIndex !== -1) { // Remove both from parent parent.removeChild(skipButtonBg); parent.removeChild(self.skipButton); // Add them back in reverse order parent.addChild(self.skipButton); parent.addChild(skipButtonBg); } // Timer for countdown self.timer = null; // Start countdown self.startCountdown = function (onComplete) { self.active = true; self.visible = true; self.countdownTime = 60; self.countdownText.setText(self.countdownTime); self.onComplete = onComplete; // Update countdown every second self.timer = LK.setInterval(function () { self.countdownTime--; self.countdownText.setText(self.countdownTime); if (self.countdownTime <= 0) { self.stopCountdown(); if (self.onComplete) self.onComplete(); } }, 1000); }; // Stop countdown self.stopCountdown = function () { if (self.timer) { LK.clearInterval(self.timer); self.timer = null; } self.active = false; self.visible = false; }; // Skip button event handler self.skipButton.down = function (x, y, obj) { if (self.active) { self.stopCountdown(); if (self.onComplete) self.onComplete(); } }; return self; }); var WeaponShop = Container.expand(function () { var self = Container.call(this); self.isOpen = false; self.weapons = [{ name: "Basic Rifle", price: 0, damage: 1, speed: 15, owned: true }, { name: "Sniper Rifle", price: 50, damage: 3, speed: 30, owned: false }, { name: "Machine Gun", price: 100, damage: 2, speed: 20, owned: false }]; // Shop button self.shopButton = new Text2("WEAPONS", { size: 80, fill: 0xFFFF00 }); self.shopButton.anchor.set(0.5, 0); // Add background to make button more visible var buttonBg = LK.getAsset('bullet', { width: 300, height: 100, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); buttonBg.alpha = 0.8; buttonBg.y = self.shopButton.height / 2; self.addChild(buttonBg); self.addChild(self.shopButton); // Shop panel (hidden by default) self.panel = new Container(); self.panel.visible = false; self.addChild(self.panel); // Create weapon options self.weaponItems = []; for (var i = 0; i < self.weapons.length; i++) { var weapon = self.weapons[i]; var item = new Container(); var bg = LK.getAsset('bullet', { width: 400, height: 150, anchorX: 0.5, anchorY: 0.5, tint: 0x333333 }); bg.alpha = 0.8; item.addChild(bg); var title = new Text2(weapon.name, { size: 40, fill: 0xFFFFFF }); title.anchor.set(0.5, 0); title.y = -50; item.addChild(title); var info = new Text2("Damage: " + weapon.damage + " | Speed: " + weapon.speed, { size: 30, fill: 0xFFFFFF }); info.anchor.set(0.5, 0); info.y = 0; item.addChild(info); var priceText = new Text2(weapon.owned ? "OWNED" : "$" + weapon.price, { size: 35, fill: weapon.owned ? 0x00FF00 : 0xFFFF00 }); priceText.anchor.set(0.5, 0); priceText.y = 40; item.addChild(priceText); item.y = i * 200; item.weaponIndex = i; self.weaponItems.push(item); self.panel.addChild(item); } // Position panel self.panel.y = 100; // Handle shop button press self.shopButton.down = function (x, y, obj) { self.toggleShop(); }; // Toggle shop visibility self.toggleShop = function () { self.isOpen = !self.isOpen; self.panel.visible = self.isOpen; }; // Handle weapon selection self.selectWeapon = function (index) { var weapon = self.weapons[index]; if (weapon.owned) { // Equip weapon sniper.bulletDamage = weapon.damage; sniper.bulletSpeed = weapon.speed; sniper.switchWeapon(index); // Switch to selected weapon appearance // Visual feedback for equipped weapon for (var i = 0; i < self.weaponItems.length; i++) { var priceText = self.weaponItems[i].children[3]; if (i === index) { priceText.setText("EQUIPPED", { fill: 0x00FFFF }); } else if (self.weapons[i].owned) { priceText.setText("OWNED", { fill: 0x00FF00 }); } } LK.getSound('upgrade').play(); return true; } else if (currency >= weapon.price) { // Purchase weapon currency -= weapon.price; weapon.owned = true; // Update UI var priceText = self.weaponItems[index].children[3]; priceText.setText("EQUIPPED", { fill: 0x00FFFF }); // Reset other weapon texts to "OWNED" for (var i = 0; i < self.weaponItems.length; i++) { if (i !== index && self.weapons[i].owned) { self.weaponItems[i].children[3].setText("OWNED", { fill: 0x00FF00 }); } } // Equip weapon sniper.bulletDamage = weapon.damage; sniper.bulletSpeed = weapon.speed; sniper.switchWeapon(index); // Switch to selected weapon appearance LK.getSound('upgrade').play(); updateUI(); return true; } else { // Not enough currency LK.effects.flashScreen(0xFF0000, 300); return false; } }; // Check if an item was clicked self.checkItemClick = function (x, y) { if (!self.isOpen) return false; var pos = self.toLocal({ x: x, y: y }); for (var i = 0; i < self.weaponItems.length; i++) { var item = self.weaponItems[i]; // Improve hit detection with both x and y checks if (pos.y >= item.y - 75 && pos.y <= item.y + 75 && pos.x >= -200 && pos.x <= 200) { return self.selectWeapon(item.weaponIndex); } } return false; }; // Add down event handlers to each weapon item for (var i = 0; i < self.weaponItems.length; i++) { var item = self.weaponItems[i]; item.interactive = true; item.index = i; // Store the index // Using custom event handler for each item (function (index) { item.down = function (x, y, obj) { self.selectWeapon(index); }; })(i); } return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xC2B280 // Sandy/dry land color }); /**** * Game Code ****/ // Create background var background = game.attachAsset('background', { width: 2048, height: 2732, anchorX: 0, anchorY: 0, tint: 0xC2B280 // Apply dry land tint to the background }); // Game variables var bunkerHealth = 100; var maxBunkerHealth = 100; var bunkerY = 2732 - 100; // Position near bottom of screen var currency = 0; var difficulty = 1; var wave = 1; var enemySpawnRate = 3000; // ms between enemy spawns var lastEnemySpawn = 0; var gameActive = true; var waveInProgress = false; var enemyIncreasePerWave = 0.5; // 50% more enemies per wave var enemiesPerWave = 10; // Starting with 10 enemies var enemiesSpawned = 0; // Track enemies spawned in current wave var enemiesRequired = 10; // Initial enemies required for first wave // Magazine system for each weapon type var magazines = { basic: { max: 5, current: 5, reloading: false, reloadTime: 1200 }, sniper: { max: 5, current: 5, reloading: false, reloadTime: 1800 }, machine: { max: 30, current: 30, reloading: false, reloadTime: 2000 } }; // UI for ammo display var ammoTxt = new Text2('Ammo: 5/5', { size: 50, fill: 0xFFFF00 }); ammoTxt.anchor.set(1, 0); ammoTxt.x = 2048 - 80; ammoTxt.y = 60; LK.gui.top.addChild(ammoTxt); // Helper to update ammo UI function updateAmmoUI() { var weapon = sniper.currentWeapon; var mag = magazines[weapon]; if (mag.reloading) { ammoTxt.setText('Reloading...'); } else { ammoTxt.setText('Ammo: ' + mag.current + '/' + mag.max); } } // Upgrade costs and values var upgrades = { fireRate: { level: 1, cost: 10, value: 1000, // ms between shots increment: -100 // decrease time between shots }, bulletDamage: { level: 1, cost: 15, value: 1, increment: 1 // increase damage } }; // Arrays for tracking game objects var bullets = []; var enemies = []; var walls = []; // Create bunker var bunker = new Bunker(); bunker.x = 2048 / 2; bunker.y = bunkerY; game.addChild(bunker); // Create sniper var sniper = new Sniper(); sniper.x = 2048 / 2; sniper.y = bunkerY - 50; game.addChild(sniper); // Create weapon shop var weaponShop = new WeaponShop(); weaponShop.x = 350; // Moved more to the right for better visibility weaponShop.y = 1800; // Position higher on the screen for better visibility game.addChild(weaponShop); // Add to game instead of GUI for better positioning // Create building shop var buildingShop = new BuildingShop(); buildingShop.x = 400; // Moved further right to improve visibility and hit detection buildingShop.y = 600; // Repositioned lower on the screen for better accessibility game.addChild(buildingShop); // Create wave countdown timer var waveCountdown = new WaveCountdown(); waveCountdown.x = 2048 / 2; // Center horizontally waveCountdown.y = 2732 / 2; // Center vertically waveCountdown.visible = false; // Hide initially game.addChild(waveCountdown); // UI Elements // Score display var scoreTxt = new Text2('Score: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); scoreTxt.y = 50; LK.gui.top.addChild(scoreTxt); // Wave display var waveTxt = new Text2('Wave: 1', { size: 50, fill: 0xFFFFFF }); waveTxt.anchor.set(1, 0); LK.gui.topLeft.addChild(waveTxt); waveTxt.x = 150; // Move away from the top left corner // Health display var healthTxt = new Text2('Bunker: 100%', { size: 50, fill: 0xFFFFFF }); healthTxt.anchor.set(0.5, 0); healthTxt.y = 130; LK.gui.top.addChild(healthTxt); // Currency display var currencyTxt = new Text2('$: 0', { size: 50, fill: 0x00FF00 }); currencyTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(currencyTxt); currencyTxt.x = 150; // Move away from top left corner currencyTxt.y = 60; // Position below wave display // Upgrade buttons removed as requested // Update UI elements function updateUI() { scoreTxt.setText('Score: ' + LK.getScore()); currencyTxt.setText('$: ' + currency); waveTxt.setText('Wave: ' + wave); updateUpgradeButtons(); } function updateBunkerHealth() { var healthPercentage = Math.max(0, Math.min(100, Math.round(bunkerHealth / maxBunkerHealth * 100))); healthTxt.setText('Bunker: ' + healthPercentage + '%'); bunker.showDamage(bunkerHealth / maxBunkerHealth); // Only make damage indicator visible and shake when actually taking damage // Don't show it during initialization // Only proceed with damage indication animations if bunker is actually taking damage if (bunkerHealth < maxBunkerHealth) { // Make damage indicator visible and shake when damage is taken bunker.damageIndicator.alpha = 1; // Shake effect tween(bunker.damageIndicator, { x: bunker.damageIndicator.originalX + (Math.random() * 10 - 5), y: bunker.damageIndicator.originalY + (Math.random() * 10 - 5) }, { duration: 50, repeat: 5, yoyo: true, onFinish: function onFinish() { // Hide damage indicator after shake completes (1 second) LK.setTimeout(function () { if (gameActive) { // Fade out damage indicator tween(bunker.damageIndicator, { alpha: 0 }, { duration: 300 }); } }, 1000); } }); } // Create a visual indicator effect when health is low if (bunkerHealth / maxBunkerHealth < 0.5) { // Add continuous damage indicator update for low health LK.setTimeout(function () { if (gameActive) bunker.showDamage(bunkerHealth / maxBunkerHealth); }, 100); } } function updateUpgradeButtons() { // Upgrade buttons removed as requested } // Game mechanics functions function spawnEnemy() { var now = Date.now(); if (!waveInProgress || now - lastEnemySpawn < enemySpawnRate) return; // Check if we've already spawned enough enemies for this wave if (enemiesSpawned >= enemiesRequired) return; lastEnemySpawn = now; // Calculate number of enemies to spawn based on score var currentScore = LK.getScore(); var enemiesToSpawnAtOnce = 1; // Default spawn one enemy at a time // Increase enemies spawned at once based on score thresholds if (currentScore >= 500) { enemiesToSpawnAtOnce = 5; // Spawn 5 enemies at once at high scores } else if (currentScore >= 300) { enemiesToSpawnAtOnce = 4; // Spawn 4 enemies at once } else if (currentScore >= 200) { enemiesToSpawnAtOnce = 3; // Spawn 3 enemies at once } else if (currentScore >= 100) { enemiesToSpawnAtOnce = 2; // Spawn 2 enemies at once } // Make sure we don't spawn more enemies than required for this wave enemiesToSpawnAtOnce = Math.min(enemiesToSpawnAtOnce, enemiesRequired - enemiesSpawned); // Spawn multiple enemies at once for (var i = 0; i < enemiesToSpawnAtOnce; i++) { // Determine enemy type based on score and wave progression var enemyType = 'regular'; var random = Math.random(); // More advanced enemies appear based on score thresholds if (currentScore >= 300 && random < 0.3) { enemyType = 'tank'; } else if (currentScore >= 150 && random < 0.25) { enemyType = 'tank'; } else if (currentScore >= 100 && random < 0.35) { enemyType = 'fast'; } else if (currentScore >= 50 && random < 0.25) { enemyType = 'fast'; } var enemy = new Enemy(enemyType); // Distribute enemies across the width of the screen if (enemiesToSpawnAtOnce > 1) { // Distribute evenly but with some randomness var segment = 2048 / enemiesToSpawnAtOnce; enemy.x = i * segment + Math.random() * (segment - 100) + 50; } else { enemy.x = Math.random() * (2048 - 100) + 50; // Random x position } enemy.y = -50; // Start above the screen enemies.push(enemy); game.addChild(enemy); // Increment enemies spawned counter enemiesSpawned++; } } function checkCollisions() { for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (!bullet.active) { game.removeChild(bullet); bullets.splice(i, 1); continue; } for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (!enemy.active) { game.removeChild(enemy); enemies.splice(j, 1); continue; } if (bullet.active && enemy.active && bullet.intersects(enemy)) { enemy.takeDamage(bullet.damage); bullet.hit(); break; } } } } function upgradeFireRate() { if (currency >= upgrades.fireRate.cost) { currency -= upgrades.fireRate.cost; upgrades.fireRate.level++; upgrades.fireRate.value += upgrades.fireRate.increment; // Ensure fire rate doesn't go below minimum upgrades.fireRate.value = Math.max(200, upgrades.fireRate.value); sniper.fireRate = upgrades.fireRate.value; // Increase cost for next upgrade upgrades.fireRate.cost = Math.floor(upgrades.fireRate.cost * 1.5); LK.getSound('upgrade').play(); updateUI(); } } function upgradeBulletDamage() { if (currency >= upgrades.bulletDamage.cost) { currency -= upgrades.bulletDamage.cost; upgrades.bulletDamage.level++; upgrades.bulletDamage.value += upgrades.bulletDamage.increment; sniper.bulletDamage = upgrades.bulletDamage.value; // Increase cost for next upgrade upgrades.bulletDamage.cost = Math.floor(upgrades.bulletDamage.cost * 1.5); LK.getSound('upgrade').play(); updateUI(); } } function increaseDifficulty() { // Check if all enemies for this wave are spawned and eliminated if (waveInProgress && enemiesSpawned >= enemiesRequired && enemies.length === 0) { // All enemies in current wave defeated, prepare for next wave wave++; // Calculate new enemies required for next wave (increase by 50%) enemiesRequired = Math.ceil(enemiesPerWave * Math.pow(1 + enemyIncreasePerWave, wave - 1)); // Reset enemies spawned counter enemiesSpawned = 0; // Decrease spawn rate with each wave (faster spawns) based on score and wave var currentScore = LK.getScore(); // More aggressive spawn rate reduction based on score var scoreBasedReduction = Math.min(2000, Math.floor(currentScore / 8) * 25); // Use an exponential reduction for higher scores to make spawns much faster if (currentScore > 300) { scoreBasedReduction += Math.min(1000, Math.pow(currentScore - 300, 1.2)); } // Set a lower minimum spawn rate for higher scores var minSpawnRate = currentScore > 400 ? 100 : currentScore > 200 ? 200 : 300; enemySpawnRate = Math.max(minSpawnRate, 3000 - wave * 200 - scoreBasedReduction); // Pause wave progression and show countdown waveInProgress = false; // Start countdown for next wave waveCountdown.startCountdown(function () { // When countdown completes, start the new wave startNewWave(); }); } } function startNewWave() { // Clear all existing enemies for (var i = enemies.length - 1; i >= 0; i--) { game.removeChild(enemies[i]); } enemies = []; // Reset enemies spawned counter enemiesSpawned = 0; // Update UI to show new wave and enemy count waveTxt.setText('Wave: ' + wave + ' (' + enemiesRequired + ' enemies)'); // Start spawning enemies again waveInProgress = true; // Flash screen to indicate new wave LK.effects.flashScreen(0x00FF00, 500); // Adjust difficulty based on score var currentScore = LK.getScore(); if (currentScore > 300) { difficulty = 5; } else if (currentScore > 200) { difficulty = 4; } else if (currentScore > 100) { difficulty = 3; } else if (currentScore > 50) { difficulty = 2; } else { difficulty = 1; } } function gameOver() { gameActive = false; // Save high score if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } // Save currency for next game storage.currency = currency; // Show game over screen LK.showGameOver(); } // Event handlers game.move = function (x, y, obj) { if (gameActive) { // If placing a wall, move it with cursor if (game.isPlacing && game.placeableWall) { game.placeableWall.x = x; game.placeableWall.y = y; } else { // Otherwise update rifle aim to follow cursor var angle = sniper.updateAim(x, y); // Let the updateAim method handle the character orientation // We don't rotate the sniper character itself anymore // This prevents the character from being upside down when aiming } } }; game.down = function (x, y, obj) { if (!gameActive) return; // Check if weapon shop item was clicked if (weaponShop.checkItemClick(x, y)) { return; } // Check if building shop item was clicked if (buildingShop.checkItemClick(x, y)) { return; } // If placing a wall, place it at the clicked position if (game.isPlacing && game.placeableWall) { // Don't place near bunker or too close to top-left corner var distToBunker = Math.sqrt(Math.pow(x - bunker.x, 2) + Math.pow(y - bunker.y, 2)); var distToTopLeft = Math.sqrt(Math.pow(x - 100, 2) + Math.pow(y - 100, 2)); if (distToBunker < 150 || distToTopLeft < 100 || y > bunkerY - 50) { // Can't place here - flash red LK.effects.flashObject(game.placeableWall, 0xFF0000, 300); return; } // Create an actual wall at this position var wall = new Wall(game.placeableWall.buildingType, game.placeableWall.buildingHealth); wall.x = x; wall.y = y; game.addChild(wall); // Add to walls array if we don't have one if (!game.walls) { game.walls = []; } game.walls.push(wall); // Remove placeable wall game.removeChild(game.placeableWall); game.placeableWall = null; game.isPlacing = false; return; } // Fire at touch location var bullet = sniper.shoot(x, y); if (bullet) { bullets.push(bullet); game.addChild(bullet); } }; // Update function called every frame game.update = function () { if (!gameActive) return; // Only spawn enemies if a wave is in progress if (waveInProgress) { // Spawn enemies spawnEnemy(); // Update enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i].active) { enemies[i].update(); } } // Check for collisions checkCollisions(); } // Update bullets regardless of wave status for (var i = 0; i < bullets.length; i++) { if (bullets[i].active) { bullets[i].update(); } } // Update walls and check for wall-enemy collisions if (game.walls && game.walls.length > 0) { for (var i = game.walls.length - 1; i >= 0; i--) { var wall = game.walls[i]; // Update wall health bar wall.update(); // Check for collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (enemy.active && wall.intersects(enemy)) { // Stop enemy and set it to attack the wall if (!enemy.isAttackingWall) { enemy.isAttackingWall = true; enemy.attackTarget = wall; enemy.attackAnimationTicks = 0; } // Check if wall was destroyed after the attack if (wall.health <= 0) { // Remove wall if destroyed game.removeChild(wall); game.walls.splice(i, 1); // Reset any enemies attacking this wall for (var k = 0; k < enemies.length; k++) { if (enemies[k].attackTarget === wall) { enemies[k].isAttackingWall = false; enemies[k].attackTarget = null; // Reset enemy position and rotation tween(enemies[k].graphics, { rotation: 0, y: 0 }, { duration: 200, easing: tween.easeOut }); } } break; } } } } } // Update muzzle flashes Object.keys(sniper.muzzleFlashes).forEach(function (key) { if (sniper.muzzleFlashes[key].active) { sniper.muzzleFlashes[key].update(); } }); // Update difficulty (handles wave transitions) increaseDifficulty(); // Continuously update damage indicator when health is low if (bunkerHealth / maxBunkerHealth < 0.4) { // Move damage indicator more frequently as health gets lower if (LK.ticks % Math.max(5, Math.floor(bunkerHealth / maxBunkerHealth * 20)) === 0) { bunker.showDamage(bunkerHealth / maxBunkerHealth); } } // Update UI if (LK.ticks % 30 === 0) { updateUI(); } }; // Make sure the weapon shop starts with the appropriate weapon equipped weaponShop.selectWeapon(0); // Start with basic rifle selected updateAmmoUI(); // Show initial ammo // Initialize UI updateUI(); // Ensure damage indicator is invisible at start bunker.damageIndicator.alpha = 0; updateBunkerHealth(); // Calculate initial enemies required for first wave enemiesRequired = enemiesPerWave; // Start the first wave with countdown waveInProgress = false; waveCountdown.startCountdown(function () { startNewWave(); }); // Place random bushes and trees around the game area function placeBushes() { // Number of decorative elements to place var bushCount = 25; var treeCount = 15; // Positions to avoid (bunker and sniper area) var avoidX = 2048 / 2; var avoidY = bunkerY; var avoidRadius = 200; // Also avoid the top-left corner where menu icon is located var topLeftX = 50; var topLeftY = 50; var topLeftRadius = 100; // Add bushes for (var i = 0; i < bushCount; i++) { var bush = new Bush(); // Keep generating positions until we find a suitable one var validPosition = false; var attempts = 0; while (!validPosition && attempts < 10) { // Generate random position bush.x = Math.random() * 2048; bush.y = Math.random() * 2732; // Check distance from bunker area var distToBunker = Math.sqrt(Math.pow(bush.x - avoidX, 2) + Math.pow(bush.y - avoidY, 2)); // Check distance from top-left corner var distToTopLeft = Math.sqrt(Math.pow(bush.x - topLeftX, 2) + Math.pow(bush.y - topLeftY, 2)); // Position is valid if it's away from both areas to avoid if (distToBunker > avoidRadius && distToTopLeft > topLeftRadius) { validPosition = true; } attempts++; } // Add bush behind other game elements (insert at the beginning of children array) game.addChildAt(bush, 0); } // Add trees for (var i = 0; i < treeCount; i++) { var tree = new Tree(); // Keep generating positions until we find a suitable one var validPosition = false; var attempts = 0; while (!validPosition && attempts < 10) { // Generate random position tree.x = Math.random() * 2048; tree.y = Math.random() * 2732; // Check distance from bunker area var distToBunker = Math.sqrt(Math.pow(tree.x - avoidX, 2) + Math.pow(tree.y - avoidY, 2)); // Check distance from top-left corner var distToTopLeft = Math.sqrt(Math.pow(tree.x - topLeftX, 2) + Math.pow(tree.y - topLeftY, 2)); // Position is valid if it's away from both areas to avoid if (distToBunker > avoidRadius && distToTopLeft > topLeftRadius) { validPosition = true; } attempts++; } // Add tree behind other game elements (insert at the beginning of children array) game.addChildAt(tree, 0); } } // Add bushes to the game placeBushes(); // Start background music LK.playMusic('gameBgMusic', { fade: { start: 0, end: 0.3, duration: 1000 } });
===================================================================
--- original.js
+++ change.js
@@ -641,22 +641,26 @@
});
// Add rifle that will rotate toward cursor
self.rifle = self.attachAsset('rifle', {
anchorX: 0,
- anchorY: 0.5
+ anchorY: 0.5,
+ scaleX: 1.7,
+ scaleY: 1.7
});
// Create references to all weapon graphics but only show the active one
self.weapons = {
basic: self.rifle,
sniper: LK.getAsset('sniper_rifle', {
anchorX: 0,
anchorY: 0.5,
- scaleX: 1.4,
- scaleY: 1.4
+ scaleX: 2.0,
+ scaleY: 2.0
}),
machine: LK.getAsset('machine_gun', {
anchorX: 0,
- anchorY: 0.5
+ anchorY: 0.5,
+ scaleX: 1.7,
+ scaleY: 1.7
})
};
// Add other weapons but hide them initially
self.weapons.sniper.visible = false;
@@ -672,15 +676,16 @@
// Standard positioning
self.weapons[key].x = 10;
self.weapons[key].y = 0;
if (key === 'basic') {
- self.weapons[key].scale.x = 1.2;
- self.weapons[key].scale.y = 1.2;
+ self.weapons[key].scale.x = 1.7;
+ self.weapons[key].scale.y = 1.7;
} else if (key === 'sniper') {
- // Already set above
+ self.weapons[key].scale.x = 2.0;
+ self.weapons[key].scale.y = 2.0;
} else {
- self.weapons[key].scale.x = 1;
- self.weapons[key].scale.y = 1;
+ self.weapons[key].scale.x = 1.7;
+ self.weapons[key].scale.y = 1.7;
}
});
// Create muzzle flash effects for each weapon
self.muzzleFlashes = {};
kaya. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
sopalı düşman adam . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
koşan ninja. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
tek gözlü dev. In-Game asset. 2d. High contrast. No shadows
barbed wire wall. In-Game asset. 2d. High contrast. No shadows
gözcü kulesi. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
yazıyı sil
Çöl haydut sniper. In-Game asset. 2d. High contrast. No shadows
önden zırhlı araç . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
zırhlı aracaın arkası. In-Game asset. 2d. High contrast. No shadows
sağa giden askeri yeşil renkte zırhlı araç. In-Game asset. 2d. High contrast. No shadows