User prompt
David should fire just from middle of davidbody
User prompt
Let the fire come out only from the center.
User prompt
David shoot from middle of the body
User prompt
David should shoot straight to the middle of the body
User prompt
If the enemy spaceship hits David, he will lose only 1 life per hit. The enemy spaceship shoots a missile-shaped bullet, which moves slightly slower than normal speed, so David has a chance to dodge it.
User prompt
Please fix the bug: 'ReferenceError: enemySpaceshipActive is not defined' in or related to this line: 'if (!bossActive && !enemySpaceshipActive) {' Line Number: 1178
User prompt
We will set up an invisible timeline in the game. From now on, everything in the game will happen based on a timed schedule. We will plan some extra features. A new enemy spaceship will be designed — it will shoot at us. This enemy ship will appear every two minutes. It will fire for only 10 seconds, based on David’s current position. However, the center of the screen will be its boundary — it won't go further than that. After 10 seconds, it will exit quickly from either the right or left side. Each hit from this new enemy spaceship will reduce David’s health by one. The new enemy ship will appear from the same side as the giants.
User prompt
The game should have only one screen view: the sky. Fix the sky image so that it remains static and always visible on the screen.
User prompt
Remove the giant's head from the code as it is unnecessary.
User prompt
The machine gun shots should disappear when they reach their maximum range
User prompt
Please fix the bug: 'ReferenceError: minutes is not defined' in or related to this line: 'if (minutes === 5 && !heart && !heartCollected) {' Line Number: 1084
User prompt
Replace the catapult with a machine gun and design the firing mechanism accordingly. David should only use the machine gun.
User prompt
Make David fire like a machine gun (automatic rifle). David shots should only go upwards.
User prompt
Make it fire like a machine gun (automatic rifle)
User prompt
Disable the laser and use the catapult instead
User prompt
Each giant should die after 2 hits
User prompt
There is a bug in the game: when giants come from the front, the laser fires but is not visible on the screen. Adjust it so that whenever I press the left mouse button, the laser firing is always visible on the screen. The laser shot must be visible even when giants appear.
User prompt
Shorten the laser's range so that its firing distance matches that of the catapult.
User prompt
The laser disappears when firing at giants coming from the front; the laser isn't visible on the screen. It takes two hits with the laser to defeat each giant.The laser should always be visible when fired. The laser only reduces the health of the giant closest to David.
User prompt
The laser should appear on the screen every time I press fire. Even when giants appear, the laser must be visible without any issues when fired.
User prompt
If giants appear, the laser is not visible. The giants die, but the laser isn't seen. Make sure the laser is visible.
User prompt
Disable the catapult for David. He should only use the laser.
User prompt
The sky assets should remain constantly active. They should never turn off or disappear.
User prompt
remove the david arm
User prompt
Giants will come every 5 seconds in groups of 3 to 5.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Backpack class (for weapon upgrades) var Backpack = Container.expand(function () { var self = Container.call(this); // Determine color and shape by type after instantiation self.type = 0; // 1=laser, 2=plasma, 3=bazooka self.collected = false; self._bag = null; function updateBagVisual() { // Remove old bag if exists if (self._bag) { self.removeChild(self._bag); self._bag = null; } var color = 0x888888; if (self.type === 1) color = 0xff0000; // Laser: red else if (self.type === 2) color = 0xff9800; // Plasma: orange else if (self.type === 3) color = 0x9c27b0; // Bazooka: purple self._bag = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, width: 90, height: 90, color: color, shape: 'box' }); } updateBagVisual(); self.update = function () { // Bobbing animation self.y += Math.sin(LK.ticks / 10 + self.x) * 0.7; }; self.collect = function () { if (self.collected) return; self.collected = true; tween(self, { alpha: 0, y: self.y - 60 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Bazooka projectile (green, can destroy two giants) var Bazooka = Container.expand(function () { var self = Container.call(this); var bazooka = self.attachAsset('slingStone', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0x00ff00 }); self.vx = 0; self.vy = -28; self.active = true; self.damage = 2; // Bazooka deals 2 damage (kills a giant in 1 hit) self.pierce = 2; // can hit two targets self.update = function () { if (!self.active) return; self.x += self.vx; self.y += self.vy; }; return self; }); // Boss Bomb projectile (thrown by boss) var BossBomb = Container.expand(function () { var self = Container.call(this); var bomb = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0x333333, shape: 'ellipse' }); self.vx = 0; self.vy = 0; self.hit = false; self._exploded = false; self.update = function () { if (self._exploded) return; self.x += self.vx; self.y += self.vy; self.vy += 1.2; // gravity // Simple spin bomb.rotation += 0.2; }; self.explode = function () { if (self._exploded) return; self._exploded = true; tween(self, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); // Optional: play explosion sound here }; return self; }); // Boss Giant var BossGiant = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('bossBody', { anchorX: 0.5, anchorY: 1 }); var head = self.attachAsset('bossHead', { anchorX: 0.5, anchorY: 1, y: -body.height }); self.hp = 15; self.speed = 2.2; self.active = true; self.update = function () { if (!self.active) return; // Move toward David (slightly faster than before) if (david && david.y < self.y) { // Move down (with world scrolling up) self.y += self.speed + 1.2; // Track David horizontally if (Math.abs(self.x - david.x) > 10) { if (self.x < david.x) self.x += 2.5;else self.x -= 2.5; } } else { self.y += self.speed + 1.2; } // Keep boss inside sky image area if (self.x < 150) self.x = 150; if (self.x > 2048 - 150) self.x = 2048 - 150; if (self.y < 200) self.y = 200; if (self.y > 1800) self.y = 1800; // --- Boss Stick (right hand) --- // Add stick if not present if (!self._stick) { self._stick = self.attachAsset('davidArm', { anchorX: 0.5, anchorY: 0.1, width: 30, height: 180, color: 0x8d5524, x: self.width / 2 + 80, y: -self.height + 120 }); self._stickSwingAngle = 0; self._stickSwingDown = true; self._stickBaseX = self._stick.x; self._stickBaseY = self._stick.y; } // Animate stick swinging downward to hit David if (typeof self._stickSwingAngle !== "number") self._stickSwingAngle = 0; if (typeof self._stickSwingDown !== "boolean") self._stickSwingDown = true; if (self._stickSwingDown) { self._stickSwingAngle += 0.10 + Math.random() * 0.03; if (self._stickSwingAngle > 1.2) self._stickSwingDown = false; } else { self._stickSwingAngle -= 0.08 + Math.random() * 0.02; if (self._stickSwingAngle < -0.3) self._stickSwingDown = true; } self._stick.rotation = self._stickSwingAngle + 1.1; // Keep stick attached to boss's right side self._stick.x = self.width / 2 + 80; self._stick.y = -self.height + 120; // --- End Boss Stick --- // Axe swing animation (right arm) if (!self._axe) { self._axe = self.attachAsset('davidArm', { anchorX: 0.5, anchorY: 0.1, x: self.width / 2 + 60, y: -self.height + 80, color: 0x444444 }); } if (!self._axeAngle) self._axeAngle = 0; self._axeAngle += 0.13 + Math.random() * 0.04; self._axe.rotation = Math.sin(self._axeAngle) * 1.2 + 1.2; // Boss health bar (tube) above boss if (!self._hpBarBg) { self._hpBarBg = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, width: 220, height: 32, color: 0x222222, shape: 'box', y: -self.height - 60 }); } if (!self._hpBar) { self._hpBar = self.attachAsset('coin', { anchorX: 0, anchorY: 0.5, width: 210, height: 20, color: 0x43a047, shape: 'box', x: -105, y: -self.height - 60 }); } if (self._hpBar) { var maxHp = self.maxHp || (self.hp > 0 ? self.hp : 1); if (!self.maxHp) self.maxHp = self.hp; var frac = Math.max(0, Math.min(1, self.hp / self.maxHp)); self._hpBar.width = 210 * frac; // Color: green to red var col = 0x43a047; if (frac < 0.5) col = 0xffa000; if (frac < 0.25) col = 0xd32f2f; self._hpBar.tint = col; } }; self.takeDamage = function (dmg) { self.hp -= dmg; if (self.hp <= 0) { self.active = false; LK.getSound('giantVanish').play(); tween(self, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { // Remove health bar assets if present if (self._hpBarBg) { self.removeChild(self._hpBarBg); self._hpBarBg = null; } if (self._hpBar) { self.removeChild(self._hpBar); self._hpBar = null; } self.destroy(); } }); } else { LK.getSound('hit').play(); tween(self, { tint: 0xff7043 }, { duration: 180, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 180 }); } }); } }; return self; }); // Boss Whip hitbox (short-lived, for boss whip attack) var BossWhip = Container.expand(function () { var self = Container.call(this); var whip = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, width: 180, height: 40, color: 0x8d5524, shape: 'box' }); self._life = 0; self.hit = false; return self; }); // Chicken class var Chicken = Container.expand(function () { var self = Container.call(this); var chicken = self.attachAsset('chicken', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.animTimer = 0; self.update = function () { // Simple idle animation (bobbing) self.animTimer++; self.y += Math.sin(self.animTimer / 10) * 1.2; }; self.collect = function () { if (self.collected) return; self.collected = true; tween(self, { alpha: 0, y: self.y - 60 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Coin class var Coin = Container.expand(function () { var self = Container.call(this); var coin = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.animTimer = 0; self.update = function () { // Simple spin animation self.animTimer++; coin.rotation += 0.15; self.y += Math.sin(self.animTimer / 12) * 0.8; }; self.collect = function () { if (self.collected) return; self.collected = true; tween(self, { alpha: 0, y: self.y - 40 }, { duration: 200, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Spawn chickens and coins for the current wave // David (player) var David = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('davidBody', { anchorX: 0.5, anchorY: 1 }); // Arm removed (no davidArm asset) self.arm = { width: 100, height: 100 }; // dummy object to prevent errors self.armAngle = 0; self.armSpeed = 0.18; // radians per frame self.armRadius = 70; self.slingReady = true; self.stoneCooldown = 0; self.hp = 5; self.maxHp = 5; self.regenTimer = 0; self.update = function () { // Spin arm self.armAngle += self.armSpeed; if (self.armAngle > Math.PI * 2) self.armAngle -= Math.PI * 2; // Arm rotates in a circle self.arm.rotation = self.armAngle; // Stone cooldown if (self.stoneCooldown > 0) self.stoneCooldown--; // Health regen if (self.hp < self.maxHp) { self.regenTimer++; if (self.regenTimer > 180) { // 3 seconds self.hp++; self.regenTimer = 0; } } else { self.regenTimer = 0; } }; self.throwStone = function () { if (!self.slingReady || self.stoneCooldown > 0) return null; self.slingReady = false; self.stoneCooldown = 30; // half a second LK.getSound('throw').play(); // Calculate projectile start position (end of arm) var angle = self.armAngle; var sx = self.x + Math.cos(angle) * (body.width / 2 + self.arm.height * 0.9); var sy = self.y - body.height + 40 + Math.sin(angle) * (self.arm.height * 0.9); var proj = null; // Only allow Laser, Plasma, Bazooka if (weapon === WEAPON_LASER) { proj = new Laser(); proj.x = self.x; proj.y = self.y - body.height - 100; } else if (weapon === WEAPON_PLASMA) { proj = new Plasma(); proj.x = sx; proj.y = sy; } else if (weapon === WEAPON_BAZOOKA) { proj = new Bazooka(); proj.x = sx; proj.y = sy; } return proj; }; self.takeDamage = function (dmg) { self.hp -= dmg; if (self.hp < 0) self.hp = 0; LK.effects.flashObject(self, 0xff0000, 400); // Weapon revert on damage if (weapon > WEAPON_LASER) { weaponUnlocked[weapon] = false; weapon = WEAPON_LASER; weaponTxt.setText(weaponNames[0]); } }; return self; }); // Giant enemy var Giant = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('giantBody', { anchorX: 0.5, anchorY: 1 }); var head = self.attachAsset('giantHead', { anchorX: 0.5, anchorY: 1, y: -body.height }); self.hp = 2; // Each giant requires 2 hits to die self.speed = 3 + Math.random() * 2; self.active = true; self.update = function () { if (!self.active) return; // Giants move downward (with world scrolling up, so add speed to y) self.y += self.speed; }; self.takeDamage = function (dmg) { self.hp -= dmg; if (self.hp <= 0) { self.active = false; LK.getSound('giantVanish').play(); tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); } else { LK.getSound('hit').play(); tween(self, { tint: 0xffe082 }, { duration: 120, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 120 }); } }); } }; return self; }); // Heart class (for health pickup) var Heart = Container.expand(function () { var self = Container.call(this); var heart = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, width: 90, height: 90, color: 0xff69b4, // pink shape: 'box' }); self.collected = false; self.update = function () { self.y += Math.sin(LK.ticks / 12 + self.x) * 0.8; }; self.collect = function () { if (self.collected) return; self.collected = true; tween(self, { alpha: 0, y: self.y - 60 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Laser projectile (covers whole screen, instant) var Laser = Container.expand(function () { var self = Container.call(this); var laser = self.attachAsset('slingStone', { anchorX: 0.5, anchorY: 1, width: 30, height: 400, // Match catapult (stone) range color: 0x9c27b0 // purple }); self.active = true; self.damage = 1; // Laser deals 1 damage to giants, so 2 hits are required self.update = function () { // Laser is instant, doesn't move, but can fade out if (!self.active) return; // Fade out after a few frames if (!self._life) self._life = 0; self._life++; if (self._life > 10) { self.active = false; self.destroy(); } }; return self; }); // Plasma projectile (fast, yellow, destroys instantly) var Plasma = Container.expand(function () { var self = Container.call(this); var plasma = self.attachAsset('slingStone', { anchorX: 0.5, anchorY: 0.5, width: 44, height: 44, color: 0xffe600 }); self.vx = 0; self.vy = -40; self.active = true; self.damage = 99; // always kills (plasma is instant kill) self.update = function () { if (!self.active) return; self.x += self.vx; self.y += self.vy; }; return self; }); // Stone projectile var Stone = Container.expand(function () { var self = Container.call(this); var stone = self.attachAsset('slingStone', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.active = true; self.damage = 1; // Stone deals 1 damage to giants self.update = function () { if (!self.active) return; self.x += self.vx; self.y += self.vy; // Gravity self.vy += 0.7; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb }); /**** * Game Code ****/ // Character (David) // --- ENVIRONMENT --- var sky = LK.getAsset('sky', { x: 0, y: 0 }); game.addChild(sky); // Ensure sky is always at the bottom of the display list and never removed if (typeof game._skyLock === "undefined") { game._skyLock = true; var originalRemoveChild = game.removeChild; game.removeChild = function (child) { if (child === sky) { // Prevent sky from being removed return; } return originalRemoveChild.call(this, child); }; // Always keep sky at the bottom var originalAddChild = game.addChild; game.addChild = function (child) { if (child === sky) { // Only add sky if not already present if (this.children && this.children[0] !== sky) { originalAddChild.call(this, child); // Move sky to index 0 if (this.children && this.children.length > 1) { this.children.splice(this.children.indexOf(sky), 1); this.children.unshift(sky); } } return sky; } var result = originalAddChild.call(this, child); // After adding any child, ensure sky is at index 0 if (this.children && this.children[0] !== sky && this.children.indexOf(sky) !== -1) { this.children.splice(this.children.indexOf(sky), 1); this.children.unshift(sky); } return result; }; } var ground = LK.getAsset('ground', { x: 0, y: 2532 }); ground.y = 2532; // bottom of screen game.addChild(ground); // --- PLAYER --- var david = new David(); david.x = 1024; // center horizontally david.y = 2300; // near bottom, above ground game.addChild(david); // --- WEAPON SYSTEM --- var WEAPON_CATAPULT = 0; var WEAPON_LASER = 1; var WEAPON_PLASMA = 2; var WEAPON_BAZOOKA = 3; // Only allow Laser, Plasma, Bazooka in UI and logic var weaponNames = ["Laser", "Plasma", "Bazooka"]; var weaponColors = [0xff0000, 0xffe600, 0x00ff00]; // Start with Laser, Catapult is disabled var weapon = WEAPON_LASER; var weaponUnlocked = [true, false, false]; // Only Laser unlocked at start var weaponLast = WEAPON_LASER; // for reverting on damage var weaponTimeouts = [0, 0, 0]; // for time-limited weapons if needed // Weapon UI var weaponTxt = new Text2('Laser', { size: 80, fill: "#fff" }); weaponTxt.anchor.set(0.5, 0); LK.gui.top.addChild(weaponTxt); weaponTxt.y = 220; // --- BACKPACKS & HEART --- var backpacks = []; var heart = null; var heartCollected = false; // --- SCROLLING STATE --- var scrollY = 0; // how much the world has scrolled up var scrollSpeed = 4; // px per frame, adjust for desired speed // --- UI --- var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var hpTxt = new Text2('♥♥♥♥♥', { size: 90, fill: 0xE53935 }); hpTxt.anchor.set(0.5, 0); LK.gui.top.addChild(hpTxt); hpTxt.y = 120; // --- LEADERBOARD --- // Leaderboard UI and logic removed as per new requirements // --- GAME STATE --- var stones = []; var giants = []; var boss = null; var chickens = []; var coins = []; var wave = 1; var giantsToSpawn = 5; var giantsSpawned = 0; var spawnTimer = 0; var gameActive = true; var bossActive = false; var bossDefeated = false; // --- CHAPTER STATE --- var chapter = 1; var bossScale = 1; // Chicken and coin spawn positions per level (max 5 coins per level) var chickenSpawns = [ // For each wave, array of {x, y} [{ x: 600, y: 1800 }, { x: 1500, y: 800 }], [{ x: 400, y: 1200 }, { x: 1700, y: 600 }, { x: 1200, y: 2000 }], [{ x: 900, y: 900 }, { x: 1800, y: 400 }, { x: 300, y: 2200 }]]; var coinSpawns = [[{ x: 400, y: 400 }, { x: 800, y: 600 }, { x: 1200, y: 800 }, { x: 1600, y: 1000 }, { x: 200, y: 2000 }], [{ x: 600, y: 500 }, { x: 1000, y: 700 }, { x: 1400, y: 900 }, { x: 1800, y: 1100 }, { x: 400, y: 2100 }], [{ x: 800, y: 300 }, { x: 1200, y: 500 }, { x: 1600, y: 700 }, { x: 200, y: 900 }, { x: 1800, y: 2300 }]]; // Spawn chickens and coins for the current wave function spawnCollectiblesForWave(waveIdx) { // Remove old for (var i = chickens.length - 1; i >= 0; i--) { chickens[i].destroy(); chickens.splice(i, 1); } for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); coins.splice(i, 1); } // Chickens var cSpawns = chickenSpawns[waveIdx % chickenSpawns.length]; for (var i = 0; i < cSpawns.length; i++) { var c = new Chicken(); c.x = cSpawns[i].x; c.y = cSpawns[i].y; chickens.push(c); game.addChild(c); } // Coins var coinSp = coinSpawns[waveIdx % coinSpawns.length]; for (var i = 0; i < coinSp.length; i++) { var coin = new Coin(); coin.x = coinSp[i].x; coin.y = coinSp[i].y; coins.push(coin); game.addChild(coin); } } // --- MUSIC --- LK.playMusic('mainTheme'); // --- MAPS/ENVIRONMENTS --- var environments = [{ sky: 0x87ceeb, ground: 0x7ec850 }, // blue sky, green grass { sky: 0xf7e9a0, ground: 0xe0c97f }, // desert { sky: 0x9ecae1, ground: 0x8c8c8c } // mountain/rocky ]; var currentEnv = 0; function setEnvironment(idx) { sky.tint = environments[idx].sky; ground.tint = environments[idx].ground; } setEnvironment(currentEnv); // Leaderboard name entry/update function removed as per new requirements // --- UI UPDATE --- function updateScore() { scoreTxt.setText(score); } function updateHp() { var s = ''; for (var i = 0; i < david.hp; i++) s += '♥'; for (var i = david.hp; i < david.maxHp; i++) s += '♡'; hpTxt.setText(s); } updateScore(); updateHp(); // --- INPUT --- var isTouching = false; var lastTouchTick = 0; game.down = function (x, y, obj) { isTouching = true; lastTouchTick = LK.ticks; // Move David to pointer/touch position (centered, free movement) if (gameActive && !bossDefeated) { var minX = david.arm.width / 2 + 60; var maxX = 2048 - david.arm.width / 2 - 60; var minY = 0 + david.arm.height / 2 + 60; var maxY = 2532; var newX = x; var newY = y; if (newX < minX) newX = minX; if (newX > maxX) newX = maxX; if (newY < minY) newY = minY; if (newY > maxY) newY = maxY; david.x = newX; david.y = newY; } }; game.up = function (x, y, obj) { isTouching = false; // Only allow throw if touch was short (tap) if (gameActive && !bossDefeated && LK.ticks - lastTouchTick < 30) { var stone = david.throwStone(); if (stone) { stones.push(stone); // If the stone is a Laser, add it after all giants to ensure it's above them if (stone instanceof Laser) { // Always add the laser to the top of the display list so it is visible above all giants and other objects // Remove if already present, then add to top var idx = game.children.indexOf(stone); if (idx !== -1) { game.children.splice(idx, 1); } game.addChild(stone); if (game.children[game.children.length - 1] !== stone) { var idx2 = game.children.indexOf(stone); if (idx2 !== -1) { game.children.splice(idx2, 1); game.children.push(stone); } } stone.parent = game; if (typeof stone.onAdded === "function") stone.onAdded(); } else { game.addChild(stone); } // Arm can't throw again until next full rotation LK.setTimeout(function () { david.slingReady = true; }, 400); } } }; game.move = function (x, y, obj) { // Move David to pointer/touch position (centered, free movement) if (gameActive && !bossDefeated) { var minX = david.arm.width / 2 + 60; var maxX = 2048 - david.arm.width / 2 - 60; var minY = 0 + david.arm.height / 2 + 60; var maxY = 2532; // bottom of screen var newX = x; var newY = y; if (newX < minX) newX = minX; if (newX > maxX) newX = maxX; if (newY < minY) newY = minY; if (newY > maxY) newY = maxY; david.x = newX; david.y = newY; } }; // --- GAME LOOP --- // --- GIANT GROUP SPAWN EVERY 5 SECONDS (3-5 GIANTS PER GROUP) --- var giantGroupTimer = 0; var giantGroupInterval = 5 * 60; // 5 seconds * 60 FPS game.update = function () { if (!gameActive) return; // Spawn a group of 3-5 giants every 5 seconds, unless boss is active if (!bossActive) { giantGroupTimer++; if (giantGroupTimer >= giantGroupInterval) { var groupSize = 3 + Math.floor(Math.random() * 3); // 3, 4, or 5 for (var i = 0; i < groupSize; i++) { var g = new Giant(); g.x = 400 + Math.random() * 1200; g.y = -200 - i * 80; // stagger vertically so they don't overlap exactly giants.push(g); game.addChild(g); // Also spawn a gold coin for this giant var newCoin = new Coin(); newCoin.x = 400 + Math.random() * 1200; newCoin.y = 400 + Math.random() * 1800; coins.push(newCoin); game.addChild(newCoin); } giantGroupTimer = 0; } } else { // Reset timer if boss is active so we don't get a burst after boss giantGroupTimer = 0; } // --- SCROLLING LOGIC --- scrollY += scrollSpeed; // Move all world elements up by scrollSpeed sky.y = -scrollY; ground.y = 2532 - scrollY; david.y -= scrollSpeed; // Environment change per wave if (wave - 1 < environments.length) { setEnvironment(wave - 1); } // --- WEAPON/ITEM SPAWNS --- // Timed weapon unlocks var minutes = Math.floor(LK.ticks / 60 / 60); var seconds = Math.floor(LK.ticks / 60 % 60); // Laser backpack: appears at 2:00, disappears at 5:00 or if collected if (minutes === 2 && !weaponUnlocked[WEAPON_LASER] && !backpacks.some(function (b) { return b.type === WEAPON_LASER; })) { var bp = new Backpack(); bp.type = WEAPON_LASER; bp.x = 400 + Math.random() * 1200; bp.y = 800 + Math.random() * 800; backpacks.push(bp); game.addChild(bp); } // Plasma backpack: appears at 5:00, disappears at 7:00 or if collected if (minutes === 5 && !weaponUnlocked[WEAPON_PLASMA] && !backpacks.some(function (b) { return b.type === WEAPON_PLASMA; })) { var bp = new Backpack(); bp.type = WEAPON_PLASMA; bp.x = 400 + Math.random() * 1200; bp.y = 800 + Math.random() * 800; backpacks.push(bp); game.addChild(bp); } // Bazooka backpack: appears at 7:00, no time limit if (minutes === 7 && !weaponUnlocked[WEAPON_BAZOOKA] && !backpacks.some(function (b) { return b.type === WEAPON_BAZOOKA; })) { var bp = new Backpack(); bp.type = WEAPON_BAZOOKA; bp.x = 400 + Math.random() * 1200; bp.y = 800 + Math.random() * 800; backpacks.push(bp); game.addChild(bp); } // Heart: appears at 5:00, only once, near center if (minutes === 5 && !heart && !heartCollected) { heart = new Heart(); heart.x = 1024; heart.y = 1366; game.addChild(heart); } // David update david.update(); // Stones update for (var i = stones.length - 1; i >= 0; i--) { var s = stones[i]; s.update(); s.y -= scrollSpeed; // move stone up with world // Remove if off screen (top or bottom) if (s.x > 2048 || s.y < -100 || s.x < -100 || s.y > 2732) { s.destroy(); stones.splice(i, 1); continue; } } // Chickens update and collect for (var i = chickens.length - 1; i >= 0; i--) { var c = chickens[i]; c.update(); c.y -= scrollSpeed; // move up with world if (!c.collected && c.intersects(david)) { c.collect(); chickens.splice(i, 1); if (david.hp < david.maxHp) { david.hp++; updateHp(); } // Optional: play sound here if you have a chicken collect sound } } // Backpacks update and collect for (var i = backpacks.length - 1; i >= 0; i--) { var bp = backpacks[i]; bp.update(); bp.y -= scrollSpeed; if (!bp.collected && bp.intersects(david)) { bp.collect(); backpacks.splice(i, 1); weaponLast = weapon; weapon = bp.type; weaponUnlocked[weapon] = true; weaponTxt.setText(weaponNames[weapon]); } } // Heart update and collect if (heart && !heart.collected) { heart.update(); heart.y -= scrollSpeed; if (heart.intersects(david)) { heart.collect(); heartCollected = true; if (david.hp < david.maxHp) { david.hp++; updateHp(); } heart = null; } } // Coins update and collect for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; coin.update(); coin.y -= scrollSpeed; // move up with world if (!coin.collected && coin.intersects(david)) { coin.collect(); coins.splice(i, 1); score += 5; updateScore(); // Optional: play sound here if you have a coin collect sound // Respawn a new coin at a random location after collection var newCoin = new Coin(); newCoin.x = 400 + Math.random() * 1200; newCoin.y = 400 + Math.random() * 1800; coins.push(newCoin); game.addChild(newCoin); } } // Giants update for (var j = giants.length - 1; j >= 0; j--) { var g = giants[j]; g.update(); g.y -= scrollSpeed; // move up with world // Remove if off screen (bottom) if (g.y < -300) { g.destroy(); giants.splice(j, 1); continue; } // Collision with David if (g.active && g.intersects(david)) { g.active = false; g.destroy(); giants.splice(j, 1); david.takeDamage(1); updateHp(); if (david.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameActive = false; return; } continue; } // Stones/projectiles hit giant // --- Laser: only damage the closest giant in front of David, and always visible above giants --- for (var k = stones.length - 1; k >= 0; k--) { var s2 = stones[k]; if (s2 instanceof Laser && s2.active) { // Find the closest active giant in front of David (y > 0, lowest y) var closestGiant = null; var minDist = Infinity; for (var m = 0; m < giants.length; m++) { var g2 = giants[m]; if (g2.active && g2.y < david.y && g2.y > -300) { var dist = Math.abs(g2.y - david.y); if (dist < minDist) { minDist = dist; closestGiant = g2; } } } if (closestGiant && closestGiant.active && s2.active && closestGiant.intersects(s2)) { closestGiant.takeDamage(s2.damage); s2.active = false; s2.destroy(); stones.splice(k, 1); if (!closestGiant.active) { score += 1; updateScore(); } } // Always keep the laser above all giants and other objects, every frame if (s2.parent === game) { var idx = game.children.indexOf(s2); if (idx !== -1 && idx !== game.children.length - 1) { game.children.splice(idx, 1); game.children.push(s2); } } continue; } // Non-laser projectiles if (g.active && s2.active && g.intersects(s2)) { g.takeDamage(s2.damage); if (s2 instanceof Bazooka) { s2.pierce--; if (s2.pierce <= 0) { s2.active = false; s2.destroy(); stones.splice(k, 1); } } else { s2.active = false; s2.destroy(); stones.splice(k, 1); } if (!g.active) { score += 1; updateScore(); } break; } } } // Boss update if (bossActive && boss && boss.active) { boss.update(); boss.y -= scrollSpeed; // move up with world // David can shoot at boss as soon as boss appears david.slingReady = true; // --- BOSS BOMB THROWING LOGIC --- // Boss throws bombs if David is far away (horizontally) if (!boss._bombCooldown) boss._bombCooldown = 0; boss._bombCooldown--; var bossToDavidDist = Math.abs(boss.x - david.x); if (bossToDavidDist > 400 && boss._bombCooldown <= 0) { // Throw a bomb toward David if (!boss._bombs) boss._bombs = []; var bomb = new BossBomb(); bomb.x = boss.x; bomb.y = boss.y - boss.height * boss.scale.y / 2; // Calculate velocity toward David's current position var dx = david.x - boss.x; var dy = david.y - boss.y; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 18 + Math.random() * 4; bomb.vx = dx / dist * speed; bomb.vy = dy / dist * speed * 0.7 - 6; // arc upward boss._bombs.push(bomb); game.addChild(bomb); boss._bombCooldown = 90 + Math.floor(Math.random() * 60); // 1.5s cooldown } // Update boss bombs if (boss._bombs) { for (var b = boss._bombs.length - 1; b >= 0; b--) { var bomb = boss._bombs[b]; bomb.update(); bomb.y -= scrollSpeed; // Bomb hits David if (!bomb.hit && bomb.intersects(david)) { bomb.hit = true; bomb.explode(); boss._bombs.splice(b, 1); david.takeDamage(1); updateHp(); if (david.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameActive = false; return; } continue; } // Remove if off screen or exploded if (bomb.y > 2732 || bomb.y < -100 || bomb._exploded) { bomb.destroy(); boss._bombs.splice(b, 1); } } } // --- BOSS WHIP ATTACK LOGIC --- // Boss whips if David is close horizontally if (!boss._whipCooldown) boss._whipCooldown = 0; boss._whipCooldown--; if (bossToDavidDist <= 400 && boss._whipCooldown <= 0) { // Whip attack: create a whip hitbox in front of boss if (!boss._whipHitbox) { boss._whipHitbox = new BossWhip(); boss._whipHitbox.x = boss.x + (boss.x < david.x ? 120 * boss.scale.x : -120 * boss.scale.x); boss._whipHitbox.y = boss.y - boss.height * boss.scale.y / 2 + 80 * boss.scale.y; boss._whipHitbox.scale.x = boss.scale.x; boss._whipHitbox.scale.y = boss.scale.y; game.addChild(boss._whipHitbox); } boss._whipHitbox._life = 0; boss._whipCooldown = 60 + Math.floor(Math.random() * 30); // 1s cooldown } // Update whip hitbox if (boss._whipHitbox) { boss._whipHitbox._life++; boss._whipHitbox.y -= scrollSpeed; // Whip lasts for 15 frames if (boss._whipHitbox._life > 15) { boss._whipHitbox.destroy(); boss._whipHitbox = null; } else if (!boss._whipHitbox.hit && boss._whipHitbox.intersects(david)) { boss._whipHitbox.hit = true; david.takeDamage(1); updateHp(); if (david.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameActive = false; return; } } } // Boss hits David (body collision) if (boss.intersects(david)) { boss.active = false; boss.destroy(); david.takeDamage(2); updateHp(); LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameActive = false; return; } // Stones/projectiles hit boss for (var k = stones.length - 1; k >= 0; k--) { var s2 = stones[k]; if (boss.active && s2.active && boss.intersects(s2)) { boss.takeDamage(s2.damage); if (s2 instanceof Bazooka) { s2.pierce--; if (s2.pierce <= 0) { s2.active = false; s2.destroy(); stones.splice(k, 1); } } else { s2.active = false; s2.destroy(); stones.splice(k, 1); } if (!boss.active) { score += 10; updateScore(); bossDefeated = true; LK.effects.flashScreen(0x00ff00, 1200); // Show "Next Chapter" if not last chapter, else show "You Win" if (chapter < 3) { // Show "Next Chapter" overlay var nextChapterTxt = new Text2('Next Chapter', { size: 200, fill: "#fff" }); nextChapterTxt.anchor.set(0.5, 0.5); nextChapterTxt.x = 1024; nextChapterTxt.y = 1200; LK.gui.center.addChild(nextChapterTxt); // Prepare for next chapter after short delay LK.setTimeout(function () { LK.gui.center.removeChild(nextChapterTxt); // Advance chapter, reset state chapter++; wave = 1; giantsToSpawn = 5; giantsSpawned = 0; spawnTimer = 60; bossActive = false; bossDefeated = false; gameActive = true; // Scale up boss for next chapter bossScale = bossScale * 2; // Cycle environment currentEnv = (currentEnv + 1) % environments.length; setEnvironment(currentEnv); // Move David back to start david.x = 1024; david.y = 2300; // Remove all stones, chickens, coins, backpacks, heart for (var i = stones.length - 1; i >= 0; i--) { stones[i].destroy(); stones.splice(i, 1); } for (var i = chickens.length - 1; i >= 0; i--) { chickens[i].destroy(); chickens.splice(i, 1); } for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); coins.splice(i, 1); } for (var i = backpacks.length - 1; i >= 0; i--) { backpacks[i].destroy(); backpacks.splice(i, 1); } if (heart) { heart.destroy(); heart = null; } heartCollected = false; // Reset scroll scrollY = 0; sky.y = 0; ground.y = 2532; // Reset weapons weapon = WEAPON_LASER; weaponUnlocked = [true, false, false]; weaponLast = WEAPON_LASER; weaponTxt.setText(weaponNames[0]); // Reset HP david.hp = david.maxHp; updateHp(); // Spawn collectibles for new wave spawnCollectiblesForWave(wave - 1); }, 2200); } else { // Last chapter, keep spawning giants forever bossActive = false; bossDefeated = false; gameActive = true; // Remove all stones, chickens, coins, backpacks, heart for (var i = stones.length - 1; i >= 0; i--) { stones[i].destroy(); stones.splice(i, 1); } for (var i = chickens.length - 1; i >= 0; i--) { chickens[i].destroy(); chickens.splice(i, 1); } for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); coins.splice(i, 1); } for (var i = backpacks.length - 1; i >= 0; i--) { backpacks[i].destroy(); backpacks.splice(i, 1); } if (heart) { heart.destroy(); heart = null; } heartCollected = false; // Reset scroll scrollY = 0; sky.y = 0; ground.y = 2532; // Move David back to start david.x = 1024; david.y = 2300; // Reset HP david.hp = david.maxHp; updateHp(); // Continue spawning giants forever wave++; giantsToSpawn += 3; giantsSpawned = 0; spawnTimer = 60; spawnCollectiblesForWave((wave - 1) % chickenSpawns.length); } return; } break; } } } // --- SPAWN LOGIC (vertical, from top) --- // Giants only spawn if boss is not active if (!bossActive) { // Only allow up to 5 giants at a time if (giants.length < 5 && giantsSpawned < giantsToSpawn) { spawnTimer--; if (spawnTimer <= 0) { var g = new Giant(); g.x = 400 + Math.random() * 1200; // random horizontal position g.y = -200; // spawn just above the top giants.push(g); game.addChild(g); giantsSpawned++; // --- SPAWN GOLD COIN FOR EACH GIANT --- var newCoin = new Coin(); newCoin.x = 400 + Math.random() * 1200; newCoin.y = 400 + Math.random() * 1800; coins.push(newCoin); game.addChild(newCoin); spawnTimer = 60 + Math.floor(Math.random() * 60); } } else if (giants.length === 0) { // Next wave or boss if (wave < 3) { wave++; giantsToSpawn += 3; giantsSpawned = 0; spawnTimer = 60; spawnCollectiblesForWave(wave - 1); // spawn chickens and coins for new wave } else { // Boss time: pause giants, spawn boss bossActive = true; boss = new BossGiant(); // Scale boss size and HP per chapter boss.x = 1024; // center horizontally boss.y = -300; // spawn above the top boss.scale.x = bossScale; boss.scale.y = bossScale; boss.hp = 15 * bossScale; game.addChild(boss); spawnCollectiblesForWave(wave - 1); // spawn for boss wave } } } // Giants will continuously respawn and keep coming without end // (Removed bossDefeated check and chapter2 popup, giants always respawn) };
===================================================================
--- original.js
+++ change.js
@@ -65,9 +65,9 @@
});
self.vx = 0;
self.vy = -28;
self.active = true;
- self.damage = 2; // can destroy two giants
+ self.damage = 2; // Bazooka deals 2 damage (kills a giant in 1 hit)
self.pierce = 2; // can hit two targets
self.update = function () {
if (!self.active) return;
self.x += self.vx;
@@ -434,9 +434,9 @@
anchorX: 0.5,
anchorY: 1,
y: -body.height
});
- self.hp = 2;
+ self.hp = 2; // Each giant requires 2 hits to die
self.speed = 3 + Math.random() * 2;
self.active = true;
self.update = function () {
if (!self.active) return;
@@ -516,9 +516,9 @@
// Match catapult (stone) range
color: 0x9c27b0 // purple
});
self.active = true;
- self.damage = 2;
+ self.damage = 1; // Laser deals 1 damage to giants, so 2 hits are required
self.update = function () {
// Laser is instant, doesn't move, but can fade out
if (!self.active) return;
// Fade out after a few frames
@@ -543,9 +543,9 @@
});
self.vx = 0;
self.vy = -40;
self.active = true;
- self.damage = 99; // always kills
+ self.damage = 99; // always kills (plasma is instant kill)
self.update = function () {
if (!self.active) return;
self.x += self.vx;
self.y += self.vy;
@@ -561,9 +561,9 @@
});
self.vx = 0;
self.vy = 0;
self.active = true;
- self.damage = 1;
+ self.damage = 1; // Stone deals 1 damage to giants
self.update = function () {
if (!self.active) return;
self.x += self.vx;
self.y += self.vy;
@@ -582,10 +582,10 @@
/****
* Game Code
****/
-// --- ENVIRONMENT ---
// Character (David)
+// --- ENVIRONMENT ---
var sky = LK.getAsset('sky', {
x: 0,
y: 0
});
Create a spaceship as the main hero. It will be in the center, with the front tip pointing upwards. There will be a firing mechanism on both sides.
Imagine a multi-legged space machine, its legs sprawling at varied, dynamic angles, giving it an organic yet mechanical feel. Encased within a transparent tube, a one-eyed green alien watches intently. Beneath the ship, vivid rocket flames burst forth, illuminating the dark void of space with fiery intensity.
The background will be a dynamic space scene, featuring only blue and dark navy colors. top to bottom, creating a lively and immersive environment."