User prompt
Giants will continuously respawn and keep coming without end.
User prompt
Giants will keep coming without stopping. They will only stop when the giant boss appears. If the giant boss is defeated, the giants will immediately start coming again.
User prompt
Giants will spawn every minute during the game.
User prompt
Giants will keep coming without stopping. They will only stop when the giant boss appears. If the giant boss is defeated, the giants will immediately start coming again. 'Chapter 2' will appear on the screen.
User prompt
And let the giants keep coming...
User prompt
When the boss giant arrives, it will stay inside the sky image. David will be able to shoot at him once the boss giant appears. Give him a stick and have him keep moving it constantly. To hit David, the boss giant will strike downward.
User prompt
The giant will keep coming continuously. The laser will come in a purple color. For each giant that appears, a gold coin will respawn somewhere.
User prompt
The incoming enemies will keep coming until the hero dies, meaning until he loses all his health. The giant boss will throw bombs at you if you're far away. He will also have a whip and will constantly swing it toward you. Every time he hits you with the whip, you will lose one health point.
User prompt
In the game, backpacks will appear at specific points on the screen and will stay in place until the hero picks them up, even as the game continues to scroll. Each weapon backpack will have a distinct color and square shape: Red square backpack = Laser weapon Orange square backpack = Plasma weapon Purple square backpack = Bazooka The giant boss will try to chase and strike the hero. The boss giant will have a visible health bar, displayed like a tube, which decreases as the player deals damage. Once the boss is defeated, the screen will show "Next Chapter", and small giants will start spawning again. As the game progresses, small giants will continuously appear, ensuring the screen is never empty. When a heart appears, it will be a pink square. If the hero collects it, one life point will be restored.
User prompt
Don't forget the heart — it will appear once and will spawn near the center of the screen. If the player collects it, they will gain one extra life. The weapon spawn times will be fixed: 0–2 minutes: The hero uses the catapult. 2–5 minutes: A backpack appears containing the laser weapon. 5–7 minutes: A backpack appears containing the plasma weapon. 7–8 minutes: A backpack appears containing the bazooka. If the hero is hit and loses health, they will return to the previously used weapon. At minute 8, the largest giant (final boss of the chapter) will appear — this timing will be fixed. While small giants are coming, gold coins will also spawn. Once collected, new coins will respawn from different locations. After defeating the boss giant at the 8th minute, the screen will display “Next Chapter”. There will be a total of 3 chapters in the game. Each map will have different hills and trees, and as the game progresses, the environment will continuously change. The boss giant at the end of each chapter will be twice as large as the one before — increasing in size with each new chapter. He will try to hit the hero by swinging the battle axe in his right hand. If the hit lands, the hero loses health.
User prompt
The largest giant will move at a normal speed, slightly faster than the previous one. He will constantly swing a battle axe with his right hand, trying to hit the hero as he approaches. Different weapons will appear on the screen throughout the game. The hero starts with a catapult from 0 to 2 minutes. Then, a backpack appears containing a laser weapon, available from 2 to 5 minutes. If the player collects it, it will fire a red laser beam vertically from bottom to top, covering the whole screen. After that, another backpack appears between 5 to 7 minutes, containing a plasma weapon. If collected, it will fire yellow shots, instantly destroying enemies with a single hit. Finally, the last backpack contains a bazooka. If the player collects it, it will be powerful enough to destroy two giants with a single shot. However, if the hero loses health, they will revert to the previously used weapon and continue with that one. In the game, a heart will appear only once at the 5th minute. If the player collects it, they will gain one health point. Gold coins will not appear all at once. Instead, new coins will spawn in different locations only after the player collects the current ones.
User prompt
Remove the Top 5 leaderboard from the screen. As the game progresses, different weapons will start to appear. The map will constantly change, offering varied and unique environments. Giants will continue to appear endlessly, making the game feel like it has infinite progression. However, every 8 minutes, the largest giant (the ultimate boss) will appear. During this time, no smaller giants will spawn. At that point, only our hero and the largest giant will remain on the screen. The boss giant will slowly move toward the hero, trying to kill him by swinging a large axe. However, his movements will be slow and deliberate. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
The movement flow of the screen and the giants will not be from left to right — instead, the screen will scroll from bottom to top continuously. The objects and elements within the game will constantly change as the screen scrolls upward. The hero can only shoot upward, and all the giants will enter the screen from the top. The game will continuously scroll upward slowly. At any given time, there will be a maximum of 5 giants on the screen. The giants will always follow the same movement patterns and will consistently appear from the upper part of the screen.
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var lb = storage.get('leaderboard');' Line Number: 347 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var lb = storage.getItem('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var lb = storage.get('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var lb = storage.getItem('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var lb = storage.get('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var lb = storage.getItem('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var lb = storage.get('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var lb = storage.getItem('leaderboard');' Line Number: 347
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var lb = storage.get('leaderboard') || [];' Line Number: 347
User prompt
The game will be changed to a full-screen view, allowing the hero to move freely across the entire screen. The giants will keep coming toward you in predefined patterns, always moving closer to your position. Other elements will appear too. For example, chickens will show up and perform specific animations. When you collect them, your health bar will increase slightly. Gold coins will continue to appear as the game progresses through its stages. The locations where they spawn will be fixed, with a maximum of five coins per level, each appearing in different positions. The map will include trees, houses, and towers, all with varied designs to create diverse environments. In certain areas of the screen, players can earn extra points by collecting specific items. A high score leaderboard will be displayed on the screen, showing the top 5 players. Anyone who achieves a high score will be able to enter their name to save their ranking.
User prompt
The game will be vertical (portrait orientation), and there will be no mouse cursor. Instead of a cursor, our hero will appear and act as the mouse pointer. The player will be able to move the hero using the mouse to dodge enemies and shoot at them. Every time the player clicks the left mouse button, the hero will fire a shot, regardless of which weapon is currently equipped. The giants will approach the player following specific paths (trajectories).
User prompt
Please fix the bug: 'Uncaught TypeError: setTimeout is not a function' in or related to this line: 'setTimeout(function () {' Line Number: 338
/****
* 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; // can destroy two giants
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 pivots at shoulder
var arm = self.attachAsset('davidArm', {
anchorX: 0.5,
anchorY: 0.1,
x: body.width / 2 - 10,
y: -body.height + 40
});
self.arm = arm;
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;
if (weapon === WEAPON_CATAPULT) {
proj = new Stone();
proj.x = sx;
proj.y = sy;
proj.vx = 0;
proj.vy = -32;
} else 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_CATAPULT) {
weaponUnlocked[weapon] = false;
weapon = weaponLast;
weaponTxt.setText(weaponNames[weapon]);
}
};
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;
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: 2200,
color: 0x9c27b0 // purple
});
self.active = true;
self.damage = 2;
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
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;
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);
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;
var weaponNames = ["Catapult", "Laser", "Plasma", "Bazooka"];
var weaponColors = [0xaaaaaa, 0xff0000, 0xffe600, 0x00ff00];
var weapon = WEAPON_CATAPULT;
var weaponUnlocked = [true, false, false, false];
var weaponLast = WEAPON_CATAPULT; // for reverting on damage
var weaponTimeouts = [0, 0, 0, 0]; // for time-limited weapons if needed
// Weapon UI
var weaponTxt = new Text2('Catapult', {
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);
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 SPAWN EVERY MINUTE TIMER ---
var giantMinuteTimer = 0;
var giantMinuteInterval = 60 * 60; // 60 seconds * 60 FPS
game.update = function () {
if (!gameActive) return;
// Spawn a new giant every minute, regardless of other spawn logic (unless boss is active)
if (!bossActive) {
giantMinuteTimer++;
if (giantMinuteTimer >= giantMinuteInterval) {
var g = new Giant();
g.x = 400 + Math.random() * 1200;
g.y = -200;
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);
giantMinuteTimer = 0;
}
} else {
// Reset timer if boss is active so we don't get a burst after boss
giantMinuteTimer = 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
for (var k = stones.length - 1; k >= 0; k--) {
var s2 = stones[k];
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_CATAPULT;
weaponUnlocked = [true, false, false, false];
weaponLast = WEAPON_CATAPULT;
weaponTxt.setText(weaponNames[weapon]);
// 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
@@ -1357,29 +1357,7 @@
spawnCollectiblesForWave(wave - 1); // spawn for boss wave
}
}
}
- // Resume giants immediately after boss defeat
- if (bossDefeated && !bossActive) {
- bossDefeated = false;
- // Show "Chapter 2" after first boss defeat
- if (chapter === 2) {
- var chapter2Txt = new Text2('Chapter 2', {
- size: 200,
- fill: "#fff"
- });
- chapter2Txt.anchor.set(0.5, 0.5);
- chapter2Txt.x = 1024;
- chapter2Txt.y = 1200;
- LK.gui.center.addChild(chapter2Txt);
- LK.setTimeout(function () {
- LK.gui.center.removeChild(chapter2Txt);
- }, 2000);
- }
- // Continue spawning giants forever
- wave++;
- giantsToSpawn += 3;
- giantsSpawned = 0;
- spawnTimer = 60;
- spawnCollectiblesForWave((wave - 1) % chickenSpawns.length);
- }
+ // Giants will continuously respawn and keep coming without end
+ // (Removed bossDefeated check and chapter2 popup, giants always respawn)
};
\ No newline at end of file
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."