/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Animal base class var Animal = Container.expand(function () { var self = Container.call(this); self.type = 'animal'; self.value = 0; self.speed = 0; self.caught = false; self.init = function (animalType) { self.animalType = animalType; var assetId; if (animalType === 'trex') { assetId = 'trex'; self.value = 146; self.speed = 2.2 + Math.random() * 0.8; } else if (animalType === 'lion') { assetId = 'lion'; self.value = 55; self.speed = 3.2 + Math.random() * 1.2; } else if (animalType === 'zebra') { assetId = 'zebra'; self.value = 35; self.speed = 3.8 + Math.random() * 1.5; } else if (animalType === 'bird') { assetId = 'bird'; self.value = 15; self.speed = 5.5 + Math.random() * 2.5; } else if (animalType === 'spider') { assetId = 'spider'; self.value = 10; self.speed = 2.2 + Math.random() * 1.2; } else if (animalType === 'stork') { assetId = 'bird'; self.value = 100; self.speed = 4.5 + Math.random() * 1.5; // Tint the stork to make it visually distinct // (LK.getAsset does not support dynamic tint, so we use the same asset for now) } else if (animalType === 'unicorn') { assetId = 'unicorn'; self.value = 126; self.speed = 3.5 + Math.random() * 1.2; } self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.direction = Math.random() < 0.5 ? 1 : -1; if (animalType === 'lion') { // Let lions roam farther away from the player (avoid center) // Top or bottom 1/3 of the screen if (Math.random() < 0.5) { self.y = 500 + Math.random() * 400; // Top band } else { self.y = 1900 + Math.random() * 300; // Bottom band } } else { self.y = 500 + Math.random() * 1700; } if (self.direction === 1) { self.x = -self.asset.width / 2; } else { self.x = 2048 + self.asset.width / 2; self.asset.scaleX = -1; } }; self.update = function () { if (self.caught) return; self.x += self.speed * self.direction; // Remove if off screen if (self.direction === 1 && self.x > 2048 + self.asset.width / 2 || self.direction === -1 && self.x < -self.asset.width / 2) { self.destroy(); var idx = animals.indexOf(self); if (idx !== -1) animals.splice(idx, 1); } }; self.getSellValue = function () { return self.value; }; return self; }); // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); self.speed = 0; self.range = 0; self.gunType = 'basic'; self.init = function (gunType) { self.gunType = gunType; var assetId; if (gunType === 'basic') { assetId = 'bullet_basic'; self.speed = 28; self.range = 1200; } else if (gunType === 'rapid') { assetId = 'bullet_rapid'; self.speed = 36; self.range = 900; } else if (gunType === 'sniper') { assetId = 'bullet_sniper'; self.speed = 44; self.range = 1800; } else if (gunType === 'blaster') { assetId = 'bullet_sniper'; self.speed = 60; self.range = 2200; } self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.distance = 0; }; self.update = function () { if (typeof self.dirX === "number" && typeof self.dirY === "number") { self.x += self.speed * self.dirX; self.y += self.speed * self.dirY; self.distance += self.speed; } else { self.x += self.speed; self.distance += self.speed; } if (self.distance > self.range || self.x < -100 || self.x > 2200 || self.y < -100 || self.y > 2832) { self.destroy(); var idx = bullets.indexOf(self); if (idx !== -1) bullets.splice(idx, 1); } }; return self; }); // Gun class var Gun = Container.expand(function () { var self = Container.call(this); self.gunType = 'basic'; self.reloadTime = 0; self.lastShotTick = 0; self.init = function (gunType) { self.gunType = gunType; var assetId; if (gunType === 'basic') { assetId = 'gun_basic'; self.reloadTime = 30; } else if (gunType === 'rapid') { assetId = 'gun_rapid'; self.reloadTime = 12; } else if (gunType === 'sniper') { assetId = 'gun_sniper'; self.reloadTime = 60; } else if (gunType === 'blaster') { assetId = 'gun_sniper'; self.reloadTime = 18; } self.asset = self.attachAsset(assetId, { anchorX: 0.1, anchorY: 0.5 }); }; self.canShoot = function () { return LK.ticks - self.lastShotTick >= self.reloadTime; }; self.shoot = function () { self.lastShotTick = LK.ticks; }; return self; }); // Turret class var Turret = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('turret', { anchorX: 0.5, anchorY: 0.5 }); self.fireCooldown = 0; self.update = function () { // Find nearest animal within 700px var closest = null; var minDist = 99999; for (var i = 0; i < animals.length; i++) { var a = animals[i]; if (a.caught) continue; var dx = a.x - self.x; var dy = a.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 700 && dist < minDist) { minDist = dist; closest = a; } } // Fire at nearest animal every 18 ticks (~3.3 shots/sec) if (closest && self.fireCooldown <= 0) { var bullet = new Bullet(); bullet.init('rapid'); bullet.x = self.x + self.asset.width * 0.5; bullet.y = self.y; var dx = closest.x - bullet.x; var dy = closest.y - bullet.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; bullet.dirX = dx / dist; bullet.dirY = dy / dist; bullet.rotation = Math.atan2(dy, dx); game.addChild(bullet); bullets.push(bullet); LK.getSound('shoot').play(); self.fireCooldown = 18; } if (self.fireCooldown > 0) self.fireCooldown--; }; return self; }); /**** * Initialize Game ****/ // Helper: spawn animal var game = new LK.Game({ backgroundColor: 0x2e5d2c }); /**** * Game Code ****/ // Turret asset // Music // Sounds // Bullets // Guns // Animals // Game state variables var animals = []; var bullets = []; var caughtAnimals = []; var money = 0; var killCount = 0; // Track total kills var gunLevel = 0; // 0: basic, 1: rapid, 2: sniper, 3: blaster var gunTypes = ['basic', 'rapid', 'sniper', 'blaster']; var gunPrices = [0, 350, 600, 1500]; var gunNames = ['Basic Gun', 'Rapid Gun', 'Sniper Gun', 'Blaster']; var gun; var animalsSpedUp = false; // Track if animals have been sped up // Tree spawn timer variables var treeSpawnTimer = 0; var treeSpawnInterval = 300; // 5 seconds at 60 FPS // UI var moneyTxt = new Text2('$0', { size: 90, fill: 0xFFF700 }); moneyTxt.anchor.set(0.5, 0); LK.gui.top.addChild(moneyTxt); var caughtTxt = new Text2('Bag: 0', { size: 70, fill: 0xFFFFFF }); caughtTxt.anchor.set(0.5, 0); LK.gui.top.addChild(caughtTxt); caughtTxt.y = 110; var killTxt = new Text2('Kills: 0', { size: 70, fill: 0xFF4444 }); killTxt.anchor.set(0, 1); // anchor bottom left LK.gui.bottomLeft.addChild(killTxt); killTxt.x = 0; killTxt.y = 0; var gunTxt = new Text2('Gun: Basic', { size: 60, fill: 0xFFFFFF }); gunTxt.anchor.set(0.5, 0); LK.gui.top.addChild(gunTxt); gunTxt.y = 200; var sellBtn = new Text2('Sell', { size: 70, fill: 0xFF8800 }); sellBtn.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(sellBtn); sellBtn.y = -200; var upgradeBtn = new Text2('Upgrade', { size: 70, fill: 0x00FF00 }); upgradeBtn.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(upgradeBtn); upgradeBtn.y = -120; // --- Buy Turret Button --- var buyTurretBtn = new Text2('Buy Turret ($1500)', { size: 70, fill: 0x00BFFF }); buyTurretBtn.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(buyTurretBtn); buyTurretBtn.y = -40; // Track if player owns a turret var hasTurret = false; var playerTurret = null; // Gun gun = new Gun(); gun.init(gunTypes[gunLevel]); game.addChild(gun); gun.x = 2048 / 2; gun.y = 2732 / 2; // Friend button removed // Track if skin is bought var skinBought = false; // Turret spawn timer variables var turretSpawnInterval = 660; // 11 seconds at 60 FPS var turretSpawnTicks = 0; var turrets = []; var turretStayDuration = 300; // 5 seconds at 60 FPS function spawnTurret() { var turret = new Turret(); // Place turrets in a circle around the gun, up to 6 turrets var turretCount = turrets.length; var angle = turretCount % 6 * (Math.PI * 2 / 6); var radius = 500; turret.x = gun.x + Math.cos(angle) * radius; turret.y = gun.y + Math.sin(angle) * radius; game.addChild(turret); // Add a timer property to track how long the turret has been alive turret.ticksAlive = 0; turrets.push(turret); // Reset turret spawn timer turretSpawnTicks = 0; } // Helper: spawn animal function spawnAnimal() { // Very rarely, spawn a unicorn if (Math.random() < 0.0015) { var unicorn = new Animal(); unicorn.init('unicorn'); game.addChild(unicorn); animals.push(unicorn); return; } // Very rarely, spawn a stork if (Math.random() < 0.003) { var stork = new Animal(); stork.init('stork'); game.addChild(stork); animals.push(stork); return; } var r = Math.random(); var animalType; // After killCount >= 34, do not spawn spiders or birds if (killCount >= 34) { // Only spawn trex, lion, zebra, unicorn, stork if (r < 0.01) { animalType = 'trex'; } else if (r < 0.10) { animalType = 'lion'; } else if (r < 0.20) { animalType = 'zebra'; } else if (r < 0.21) { animalType = 'unicorn'; } else { animalType = 'stork'; } } else if (killCount >= 16) { if (r < 0.01) { animalType = 'trex'; } else if (r < 0.10) { animalType = 'lion'; } else if (r < 0.20) { animalType = 'zebra'; } else if (r < 0.35) { animalType = 'bird'; // birds increased } else { // spiders dominate animalType = 'spider'; } } else if (killCount >= 15) { if (r < 0.01) { animalType = 'trex'; } else if (r < 0.10) { animalType = 'lion'; } else if (r < 0.20) { animalType = 'zebra'; } else if (r < 0.23) { animalType = 'bird'; } else { // spiders dominate animalType = 'spider'; } } else if (killCount >= 11) { if (r < 0.01) { // more trex animalType = 'trex'; } else if (r < 0.18) { animalType = 'lion'; } else if (r < 0.38) { animalType = 'zebra'; } else if (r < 0.48) { animalType = 'bird'; } else { // even more spiders animalType = 'spider'; } } else if (killCount >= 5) { // More spiders when killCount >= 5 if (r < 0.005) { animalType = 'trex'; } else if (r < 0.13) { animalType = 'lion'; } else if (r < 0.33) { animalType = 'zebra'; } else if (r < 0.60) { animalType = 'bird'; } else { // more spiders animalType = 'spider'; } } else { if (r < 0.005) { animalType = 'trex'; } else if (r < 0.13) { animalType = 'lion'; } else if (r < 0.33) { animalType = 'zebra'; } else if (r < 0.70) { animalType = 'bird'; } else { animalType = 'spider'; } } var animal = new Animal(); animal.init(animalType); game.addChild(animal); animals.push(animal); } // Helper: update UI function updateUI() { moneyTxt.setText('$' + money); caughtTxt.setText('Bag: ' + caughtAnimals.length); killTxt.setText('Kills: ' + Math.floor(killCount)); gunTxt.setText('Gun: ' + gunNames[gunLevel]); if (gunLevel < 3) { upgradeBtn.setText('Upgrade ($' + gunPrices[gunLevel + 1] + ')'); upgradeBtn.alpha = money >= gunPrices[gunLevel + 1] ? 1 : 0.5; } else { upgradeBtn.setText('Maxed'); upgradeBtn.alpha = 0.5; } // Update Buy Turret button UI if (typeof buyTurretBtn !== "undefined") { if (hasTurret) { buyTurretBtn.setText('Turret Owned'); buyTurretBtn.alpha = 0.5; } else { buyTurretBtn.setText('Buy Turret ($1500)'); buyTurretBtn.alpha = money >= 1500 ? 1 : 0.5; } } // Friend button UI removed // Reset animalsSpedUp if game is reset (killCount is 0) if (killCount < 8) { game.animalsSpedUp = false; } // Reset animalsSuperSpedUp if game is reset (killCount is 0) if (killCount < 11) { game.animalsSuperSpedUp = false; } } // Helper: sell animals function sellAnimals() { if (caughtAnimals.length === 0) return; var total = 0; for (var i = 0; i < caughtAnimals.length; i++) { total += caughtAnimals[i].getSellValue(); } money += total; caughtAnimals = []; LK.getSound('sell').play(); updateUI(); } // Helper: upgrade gun function upgradeGun() { if (gunLevel >= 3) return; var price = gunPrices[gunLevel + 1]; if (money < price) return; money -= price; gunLevel++; gun.destroy(); gun = new Gun(); gun.init(gunTypes[gunLevel]); game.addChild(gun); gun.x = 2048 / 2; gun.y = 2732 / 2; // Hat logic removed (Friend button gone) LK.getSound('upgrade').play(); updateUI(); } // UI events upgradeBtn.down = function (x, y, obj) { upgradeGun(); }; sellBtn.down = function (x, y, obj) { LK.getSound('sell').play(); sellAnimals(); }; // Buy Turret button event buyTurretBtn.down = function (x, y, obj) { if (hasTurret) return; if (money < 1500) return; money -= 1500; hasTurret = true; // Spawn turret next to player (right side) playerTurret = new Turret(); playerTurret.x = gun.x + gun.asset.width * 1.2 + 80; playerTurret.y = gun.y; game.addChild(playerTurret); updateUI(); // Update button state buyTurretBtn.setText('Turret Owned'); buyTurretBtn.alpha = 0.5; }; // Touch to shoot game.down = function (x, y, obj) { // Don't shoot if touch is on GUI (bottom 300px) if (y > 2732 - 300) return; if (!gun.canShoot()) return; var bullet = new Bullet(); bullet.init(gunTypes[gunLevel]); bullet.x = gun.x + gun.asset.width * 0.9; bullet.y = gun.y; game.addChild(bullet); bullets.push(bullet); gun.shoot(); // Animate gun recoil tween(gun, { x: gun.x - 30 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(gun, { x: 300 }, { duration: 80, easing: tween.cubicIn }); } }); }; // Gun is fixed in the center; no dragging needed game.move = function (x, y, obj) { // No dragging logic }; // Shoot from the center gun position game.down = function (x, y, obj) { // Don't shoot if touch is on GUI (bottom 300px) if (y > 2732 - 300) return; if (!gun.canShoot()) return; if (gunTypes[gunLevel] === 'blaster') { // Fire 3 bullets in a spread var gunMuzzleX = gun.x + gun.asset.width * 0.9; var gunMuzzleY = gun.y; var dx = x - gunMuzzleX; var dy = y - gunMuzzleY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; var baseAngle = Math.atan2(dy, dx); var spread = Math.PI / 16; // ~11.25 degrees for (var i = -1; i <= 1; i++) { var bullet = new Bullet(); bullet.init('blaster'); bullet.x = gunMuzzleX; bullet.y = gunMuzzleY; var angle = baseAngle + i * spread; bullet.dirX = Math.cos(angle); bullet.dirY = Math.sin(angle); bullet.rotation = angle; game.addChild(bullet); bullets.push(bullet); } gun.shoot(); LK.getSound('shoot').play(); } else { var bullet = new Bullet(); bullet.init(gunTypes[gunLevel]); // Always shoot from the center gun position var gunMuzzleX = gun.x + gun.asset.width * 0.9; var gunMuzzleY = gun.y; bullet.x = gunMuzzleX; bullet.y = gunMuzzleY; var dx = x - gunMuzzleX; var dy = y - gunMuzzleY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) dist = 1; // prevent division by zero bullet.dirX = dx / dist; bullet.dirY = dy / dist; bullet.rotation = Math.atan2(dy, dx); game.addChild(bullet); bullets.push(bullet); gun.shoot(); LK.getSound('shoot').play(); } // Animate gun recoil tween(gun, { x: gun.x - 30 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(gun, { x: 2048 / 2 }, { duration: 80, easing: tween.cubicIn }); } }); }; game.up = function (x, y, obj) { // No dragging logic }; // Main update loop game.update = function () { // Spawn animals if (LK.ticks % 45 === 0 && animals.length < 7) { spawnAnimal(); } // Update animals for (var i = animals.length - 1; i >= 0; i--) { animals[i].update(); } // Update bullets for (var j = bullets.length - 1; j >= 0; j--) { bullets[j].update(); } // Bullet-animal collision for (var b = bullets.length - 1; b >= 0; b--) { var bullet = bullets[b]; for (var a = animals.length - 1; a >= 0; a--) { var animal = animals[a]; if (animal.caught) continue; if (bullet.intersects(animal)) { animal.caught = true; caughtAnimals.push(animal); // Increment killCount based on animal type: bird/spider = 0.5, zebra = 1, lion = 2, unicorn = 4, trex = 3.5, else 0.07 if (animal.animalType === 'bird' || animal.animalType === 'spider') { killCount += 0.5; } else if (animal.animalType === 'zebra') { killCount += 1; } else if (animal.animalType === 'lion') { killCount += 2; } else if (animal.animalType === 'unicorn') { killCount += 4; } else if (animal.animalType === 'trex') { killCount += 3.5; } else { killCount += 0.07; } // (tree spawn at killCount 4 removed) // Speed up all animals when kill counter passes 7 (only once, and make them very fast) if (!game.animalsSpedUp && killCount >= 7) { for (var ai = 0; ai < animals.length; ai++) { if (!animals[ai].caught) { animals[ai].speed *= 2.5; } } game.animalsSpedUp = true; } // Make all animals much faster and more difficult when killCount >= 11 (only once) if (!game.animalsSuperSpedUp && killCount >= 11) { for (var ai = 0; ai < animals.length; ai++) { if (!animals[ai].caught) { animals[ai].speed *= 1.5; } } game.animalsSuperSpedUp = true; } tween(animal, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { animal.destroy(); var idx = animals.indexOf(animal); if (idx !== -1) animals.splice(idx, 1); } }); bullet.destroy(); bullets.splice(b, 1); break; } } } // Turret spawn logic turretSpawnTicks++; if (turretSpawnTicks >= turretSpawnInterval) { if (Math.random() < 0.25) { spawnTurret(); } turretSpawnTicks = 0; } // Update turrets for (var i = turrets.length - 1; i >= 0; i--) { var turret = turrets[i]; if (typeof turret.update === "function") { turret.update(); } // Turret stay/leave logic if (typeof turret.ticksAlive === "number") { turret.ticksAlive++; if (turret.ticksAlive >= turretStayDuration) { // Remove turret from game and array turret.destroy(); turrets.splice(i, 1); } } } // Remove all spiders and birds from the game when killCount >= 34 (only once) if (!game.spidersAndBirdsGone && killCount >= 34) { for (var i = animals.length - 1; i >= 0; i--) { var a = animals[i]; if ((a.animalType === 'spider' || a.animalType === 'bird') && !a.caught) { a.destroy(); animals.splice(i, 1); } } game.spidersAndBirdsGone = true; } // (tree spawn logic after killCount >= 23 removed) updateUI(); }; // Play music LK.playMusic('forest_theme', { fade: { start: 0, end: 1, duration: 1200 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Animal base class
var Animal = Container.expand(function () {
var self = Container.call(this);
self.type = 'animal';
self.value = 0;
self.speed = 0;
self.caught = false;
self.init = function (animalType) {
self.animalType = animalType;
var assetId;
if (animalType === 'trex') {
assetId = 'trex';
self.value = 146;
self.speed = 2.2 + Math.random() * 0.8;
} else if (animalType === 'lion') {
assetId = 'lion';
self.value = 55;
self.speed = 3.2 + Math.random() * 1.2;
} else if (animalType === 'zebra') {
assetId = 'zebra';
self.value = 35;
self.speed = 3.8 + Math.random() * 1.5;
} else if (animalType === 'bird') {
assetId = 'bird';
self.value = 15;
self.speed = 5.5 + Math.random() * 2.5;
} else if (animalType === 'spider') {
assetId = 'spider';
self.value = 10;
self.speed = 2.2 + Math.random() * 1.2;
} else if (animalType === 'stork') {
assetId = 'bird';
self.value = 100;
self.speed = 4.5 + Math.random() * 1.5;
// Tint the stork to make it visually distinct
// (LK.getAsset does not support dynamic tint, so we use the same asset for now)
} else if (animalType === 'unicorn') {
assetId = 'unicorn';
self.value = 126;
self.speed = 3.5 + Math.random() * 1.2;
}
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = Math.random() < 0.5 ? 1 : -1;
if (animalType === 'lion') {
// Let lions roam farther away from the player (avoid center)
// Top or bottom 1/3 of the screen
if (Math.random() < 0.5) {
self.y = 500 + Math.random() * 400; // Top band
} else {
self.y = 1900 + Math.random() * 300; // Bottom band
}
} else {
self.y = 500 + Math.random() * 1700;
}
if (self.direction === 1) {
self.x = -self.asset.width / 2;
} else {
self.x = 2048 + self.asset.width / 2;
self.asset.scaleX = -1;
}
};
self.update = function () {
if (self.caught) return;
self.x += self.speed * self.direction;
// Remove if off screen
if (self.direction === 1 && self.x > 2048 + self.asset.width / 2 || self.direction === -1 && self.x < -self.asset.width / 2) {
self.destroy();
var idx = animals.indexOf(self);
if (idx !== -1) animals.splice(idx, 1);
}
};
self.getSellValue = function () {
return self.value;
};
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.speed = 0;
self.range = 0;
self.gunType = 'basic';
self.init = function (gunType) {
self.gunType = gunType;
var assetId;
if (gunType === 'basic') {
assetId = 'bullet_basic';
self.speed = 28;
self.range = 1200;
} else if (gunType === 'rapid') {
assetId = 'bullet_rapid';
self.speed = 36;
self.range = 900;
} else if (gunType === 'sniper') {
assetId = 'bullet_sniper';
self.speed = 44;
self.range = 1800;
} else if (gunType === 'blaster') {
assetId = 'bullet_sniper';
self.speed = 60;
self.range = 2200;
}
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.distance = 0;
};
self.update = function () {
if (typeof self.dirX === "number" && typeof self.dirY === "number") {
self.x += self.speed * self.dirX;
self.y += self.speed * self.dirY;
self.distance += self.speed;
} else {
self.x += self.speed;
self.distance += self.speed;
}
if (self.distance > self.range || self.x < -100 || self.x > 2200 || self.y < -100 || self.y > 2832) {
self.destroy();
var idx = bullets.indexOf(self);
if (idx !== -1) bullets.splice(idx, 1);
}
};
return self;
});
// Gun class
var Gun = Container.expand(function () {
var self = Container.call(this);
self.gunType = 'basic';
self.reloadTime = 0;
self.lastShotTick = 0;
self.init = function (gunType) {
self.gunType = gunType;
var assetId;
if (gunType === 'basic') {
assetId = 'gun_basic';
self.reloadTime = 30;
} else if (gunType === 'rapid') {
assetId = 'gun_rapid';
self.reloadTime = 12;
} else if (gunType === 'sniper') {
assetId = 'gun_sniper';
self.reloadTime = 60;
} else if (gunType === 'blaster') {
assetId = 'gun_sniper';
self.reloadTime = 18;
}
self.asset = self.attachAsset(assetId, {
anchorX: 0.1,
anchorY: 0.5
});
};
self.canShoot = function () {
return LK.ticks - self.lastShotTick >= self.reloadTime;
};
self.shoot = function () {
self.lastShotTick = LK.ticks;
};
return self;
});
// Turret class
var Turret = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('turret', {
anchorX: 0.5,
anchorY: 0.5
});
self.fireCooldown = 0;
self.update = function () {
// Find nearest animal within 700px
var closest = null;
var minDist = 99999;
for (var i = 0; i < animals.length; i++) {
var a = animals[i];
if (a.caught) continue;
var dx = a.x - self.x;
var dy = a.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 700 && dist < minDist) {
minDist = dist;
closest = a;
}
}
// Fire at nearest animal every 18 ticks (~3.3 shots/sec)
if (closest && self.fireCooldown <= 0) {
var bullet = new Bullet();
bullet.init('rapid');
bullet.x = self.x + self.asset.width * 0.5;
bullet.y = self.y;
var dx = closest.x - bullet.x;
var dy = closest.y - bullet.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
bullet.dirX = dx / dist;
bullet.dirY = dy / dist;
bullet.rotation = Math.atan2(dy, dx);
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('shoot').play();
self.fireCooldown = 18;
}
if (self.fireCooldown > 0) self.fireCooldown--;
};
return self;
});
/****
* Initialize Game
****/
// Helper: spawn animal
var game = new LK.Game({
backgroundColor: 0x2e5d2c
});
/****
* Game Code
****/
// Turret asset
// Music
// Sounds
// Bullets
// Guns
// Animals
// Game state variables
var animals = [];
var bullets = [];
var caughtAnimals = [];
var money = 0;
var killCount = 0; // Track total kills
var gunLevel = 0; // 0: basic, 1: rapid, 2: sniper, 3: blaster
var gunTypes = ['basic', 'rapid', 'sniper', 'blaster'];
var gunPrices = [0, 350, 600, 1500];
var gunNames = ['Basic Gun', 'Rapid Gun', 'Sniper Gun', 'Blaster'];
var gun;
var animalsSpedUp = false; // Track if animals have been sped up
// Tree spawn timer variables
var treeSpawnTimer = 0;
var treeSpawnInterval = 300; // 5 seconds at 60 FPS
// UI
var moneyTxt = new Text2('$0', {
size: 90,
fill: 0xFFF700
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
var caughtTxt = new Text2('Bag: 0', {
size: 70,
fill: 0xFFFFFF
});
caughtTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(caughtTxt);
caughtTxt.y = 110;
var killTxt = new Text2('Kills: 0', {
size: 70,
fill: 0xFF4444
});
killTxt.anchor.set(0, 1); // anchor bottom left
LK.gui.bottomLeft.addChild(killTxt);
killTxt.x = 0;
killTxt.y = 0;
var gunTxt = new Text2('Gun: Basic', {
size: 60,
fill: 0xFFFFFF
});
gunTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(gunTxt);
gunTxt.y = 200;
var sellBtn = new Text2('Sell', {
size: 70,
fill: 0xFF8800
});
sellBtn.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(sellBtn);
sellBtn.y = -200;
var upgradeBtn = new Text2('Upgrade', {
size: 70,
fill: 0x00FF00
});
upgradeBtn.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(upgradeBtn);
upgradeBtn.y = -120;
// --- Buy Turret Button ---
var buyTurretBtn = new Text2('Buy Turret ($1500)', {
size: 70,
fill: 0x00BFFF
});
buyTurretBtn.anchor.set(0.5, 0.5);
LK.gui.bottom.addChild(buyTurretBtn);
buyTurretBtn.y = -40;
// Track if player owns a turret
var hasTurret = false;
var playerTurret = null;
// Gun
gun = new Gun();
gun.init(gunTypes[gunLevel]);
game.addChild(gun);
gun.x = 2048 / 2;
gun.y = 2732 / 2;
// Friend button removed
// Track if skin is bought
var skinBought = false;
// Turret spawn timer variables
var turretSpawnInterval = 660; // 11 seconds at 60 FPS
var turretSpawnTicks = 0;
var turrets = [];
var turretStayDuration = 300; // 5 seconds at 60 FPS
function spawnTurret() {
var turret = new Turret();
// Place turrets in a circle around the gun, up to 6 turrets
var turretCount = turrets.length;
var angle = turretCount % 6 * (Math.PI * 2 / 6);
var radius = 500;
turret.x = gun.x + Math.cos(angle) * radius;
turret.y = gun.y + Math.sin(angle) * radius;
game.addChild(turret);
// Add a timer property to track how long the turret has been alive
turret.ticksAlive = 0;
turrets.push(turret);
// Reset turret spawn timer
turretSpawnTicks = 0;
}
// Helper: spawn animal
function spawnAnimal() {
// Very rarely, spawn a unicorn
if (Math.random() < 0.0015) {
var unicorn = new Animal();
unicorn.init('unicorn');
game.addChild(unicorn);
animals.push(unicorn);
return;
}
// Very rarely, spawn a stork
if (Math.random() < 0.003) {
var stork = new Animal();
stork.init('stork');
game.addChild(stork);
animals.push(stork);
return;
}
var r = Math.random();
var animalType;
// After killCount >= 34, do not spawn spiders or birds
if (killCount >= 34) {
// Only spawn trex, lion, zebra, unicorn, stork
if (r < 0.01) {
animalType = 'trex';
} else if (r < 0.10) {
animalType = 'lion';
} else if (r < 0.20) {
animalType = 'zebra';
} else if (r < 0.21) {
animalType = 'unicorn';
} else {
animalType = 'stork';
}
} else if (killCount >= 16) {
if (r < 0.01) {
animalType = 'trex';
} else if (r < 0.10) {
animalType = 'lion';
} else if (r < 0.20) {
animalType = 'zebra';
} else if (r < 0.35) {
animalType = 'bird'; // birds increased
} else {
// spiders dominate
animalType = 'spider';
}
} else if (killCount >= 15) {
if (r < 0.01) {
animalType = 'trex';
} else if (r < 0.10) {
animalType = 'lion';
} else if (r < 0.20) {
animalType = 'zebra';
} else if (r < 0.23) {
animalType = 'bird';
} else {
// spiders dominate
animalType = 'spider';
}
} else if (killCount >= 11) {
if (r < 0.01) {
// more trex
animalType = 'trex';
} else if (r < 0.18) {
animalType = 'lion';
} else if (r < 0.38) {
animalType = 'zebra';
} else if (r < 0.48) {
animalType = 'bird';
} else {
// even more spiders
animalType = 'spider';
}
} else if (killCount >= 5) {
// More spiders when killCount >= 5
if (r < 0.005) {
animalType = 'trex';
} else if (r < 0.13) {
animalType = 'lion';
} else if (r < 0.33) {
animalType = 'zebra';
} else if (r < 0.60) {
animalType = 'bird';
} else {
// more spiders
animalType = 'spider';
}
} else {
if (r < 0.005) {
animalType = 'trex';
} else if (r < 0.13) {
animalType = 'lion';
} else if (r < 0.33) {
animalType = 'zebra';
} else if (r < 0.70) {
animalType = 'bird';
} else {
animalType = 'spider';
}
}
var animal = new Animal();
animal.init(animalType);
game.addChild(animal);
animals.push(animal);
}
// Helper: update UI
function updateUI() {
moneyTxt.setText('$' + money);
caughtTxt.setText('Bag: ' + caughtAnimals.length);
killTxt.setText('Kills: ' + Math.floor(killCount));
gunTxt.setText('Gun: ' + gunNames[gunLevel]);
if (gunLevel < 3) {
upgradeBtn.setText('Upgrade ($' + gunPrices[gunLevel + 1] + ')');
upgradeBtn.alpha = money >= gunPrices[gunLevel + 1] ? 1 : 0.5;
} else {
upgradeBtn.setText('Maxed');
upgradeBtn.alpha = 0.5;
}
// Update Buy Turret button UI
if (typeof buyTurretBtn !== "undefined") {
if (hasTurret) {
buyTurretBtn.setText('Turret Owned');
buyTurretBtn.alpha = 0.5;
} else {
buyTurretBtn.setText('Buy Turret ($1500)');
buyTurretBtn.alpha = money >= 1500 ? 1 : 0.5;
}
}
// Friend button UI removed
// Reset animalsSpedUp if game is reset (killCount is 0)
if (killCount < 8) {
game.animalsSpedUp = false;
}
// Reset animalsSuperSpedUp if game is reset (killCount is 0)
if (killCount < 11) {
game.animalsSuperSpedUp = false;
}
}
// Helper: sell animals
function sellAnimals() {
if (caughtAnimals.length === 0) return;
var total = 0;
for (var i = 0; i < caughtAnimals.length; i++) {
total += caughtAnimals[i].getSellValue();
}
money += total;
caughtAnimals = [];
LK.getSound('sell').play();
updateUI();
}
// Helper: upgrade gun
function upgradeGun() {
if (gunLevel >= 3) return;
var price = gunPrices[gunLevel + 1];
if (money < price) return;
money -= price;
gunLevel++;
gun.destroy();
gun = new Gun();
gun.init(gunTypes[gunLevel]);
game.addChild(gun);
gun.x = 2048 / 2;
gun.y = 2732 / 2;
// Hat logic removed (Friend button gone)
LK.getSound('upgrade').play();
updateUI();
}
// UI events
upgradeBtn.down = function (x, y, obj) {
upgradeGun();
};
sellBtn.down = function (x, y, obj) {
LK.getSound('sell').play();
sellAnimals();
};
// Buy Turret button event
buyTurretBtn.down = function (x, y, obj) {
if (hasTurret) return;
if (money < 1500) return;
money -= 1500;
hasTurret = true;
// Spawn turret next to player (right side)
playerTurret = new Turret();
playerTurret.x = gun.x + gun.asset.width * 1.2 + 80;
playerTurret.y = gun.y;
game.addChild(playerTurret);
updateUI();
// Update button state
buyTurretBtn.setText('Turret Owned');
buyTurretBtn.alpha = 0.5;
};
// Touch to shoot
game.down = function (x, y, obj) {
// Don't shoot if touch is on GUI (bottom 300px)
if (y > 2732 - 300) return;
if (!gun.canShoot()) return;
var bullet = new Bullet();
bullet.init(gunTypes[gunLevel]);
bullet.x = gun.x + gun.asset.width * 0.9;
bullet.y = gun.y;
game.addChild(bullet);
bullets.push(bullet);
gun.shoot();
// Animate gun recoil
tween(gun, {
x: gun.x - 30
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(gun, {
x: 300
}, {
duration: 80,
easing: tween.cubicIn
});
}
});
};
// Gun is fixed in the center; no dragging needed
game.move = function (x, y, obj) {
// No dragging logic
};
// Shoot from the center gun position
game.down = function (x, y, obj) {
// Don't shoot if touch is on GUI (bottom 300px)
if (y > 2732 - 300) return;
if (!gun.canShoot()) return;
if (gunTypes[gunLevel] === 'blaster') {
// Fire 3 bullets in a spread
var gunMuzzleX = gun.x + gun.asset.width * 0.9;
var gunMuzzleY = gun.y;
var dx = x - gunMuzzleX;
var dy = y - gunMuzzleY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1;
var baseAngle = Math.atan2(dy, dx);
var spread = Math.PI / 16; // ~11.25 degrees
for (var i = -1; i <= 1; i++) {
var bullet = new Bullet();
bullet.init('blaster');
bullet.x = gunMuzzleX;
bullet.y = gunMuzzleY;
var angle = baseAngle + i * spread;
bullet.dirX = Math.cos(angle);
bullet.dirY = Math.sin(angle);
bullet.rotation = angle;
game.addChild(bullet);
bullets.push(bullet);
}
gun.shoot();
LK.getSound('shoot').play();
} else {
var bullet = new Bullet();
bullet.init(gunTypes[gunLevel]);
// Always shoot from the center gun position
var gunMuzzleX = gun.x + gun.asset.width * 0.9;
var gunMuzzleY = gun.y;
bullet.x = gunMuzzleX;
bullet.y = gunMuzzleY;
var dx = x - gunMuzzleX;
var dy = y - gunMuzzleY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) dist = 1; // prevent division by zero
bullet.dirX = dx / dist;
bullet.dirY = dy / dist;
bullet.rotation = Math.atan2(dy, dx);
game.addChild(bullet);
bullets.push(bullet);
gun.shoot();
LK.getSound('shoot').play();
}
// Animate gun recoil
tween(gun, {
x: gun.x - 30
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(gun, {
x: 2048 / 2
}, {
duration: 80,
easing: tween.cubicIn
});
}
});
};
game.up = function (x, y, obj) {
// No dragging logic
};
// Main update loop
game.update = function () {
// Spawn animals
if (LK.ticks % 45 === 0 && animals.length < 7) {
spawnAnimal();
}
// Update animals
for (var i = animals.length - 1; i >= 0; i--) {
animals[i].update();
}
// Update bullets
for (var j = bullets.length - 1; j >= 0; j--) {
bullets[j].update();
}
// Bullet-animal collision
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
for (var a = animals.length - 1; a >= 0; a--) {
var animal = animals[a];
if (animal.caught) continue;
if (bullet.intersects(animal)) {
animal.caught = true;
caughtAnimals.push(animal);
// Increment killCount based on animal type: bird/spider = 0.5, zebra = 1, lion = 2, unicorn = 4, trex = 3.5, else 0.07
if (animal.animalType === 'bird' || animal.animalType === 'spider') {
killCount += 0.5;
} else if (animal.animalType === 'zebra') {
killCount += 1;
} else if (animal.animalType === 'lion') {
killCount += 2;
} else if (animal.animalType === 'unicorn') {
killCount += 4;
} else if (animal.animalType === 'trex') {
killCount += 3.5;
} else {
killCount += 0.07;
}
// (tree spawn at killCount 4 removed)
// Speed up all animals when kill counter passes 7 (only once, and make them very fast)
if (!game.animalsSpedUp && killCount >= 7) {
for (var ai = 0; ai < animals.length; ai++) {
if (!animals[ai].caught) {
animals[ai].speed *= 2.5;
}
}
game.animalsSpedUp = true;
}
// Make all animals much faster and more difficult when killCount >= 11 (only once)
if (!game.animalsSuperSpedUp && killCount >= 11) {
for (var ai = 0; ai < animals.length; ai++) {
if (!animals[ai].caught) {
animals[ai].speed *= 1.5;
}
}
game.animalsSuperSpedUp = true;
}
tween(animal, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
animal.destroy();
var idx = animals.indexOf(animal);
if (idx !== -1) animals.splice(idx, 1);
}
});
bullet.destroy();
bullets.splice(b, 1);
break;
}
}
}
// Turret spawn logic
turretSpawnTicks++;
if (turretSpawnTicks >= turretSpawnInterval) {
if (Math.random() < 0.25) {
spawnTurret();
}
turretSpawnTicks = 0;
}
// Update turrets
for (var i = turrets.length - 1; i >= 0; i--) {
var turret = turrets[i];
if (typeof turret.update === "function") {
turret.update();
}
// Turret stay/leave logic
if (typeof turret.ticksAlive === "number") {
turret.ticksAlive++;
if (turret.ticksAlive >= turretStayDuration) {
// Remove turret from game and array
turret.destroy();
turrets.splice(i, 1);
}
}
}
// Remove all spiders and birds from the game when killCount >= 34 (only once)
if (!game.spidersAndBirdsGone && killCount >= 34) {
for (var i = animals.length - 1; i >= 0; i--) {
var a = animals[i];
if ((a.animalType === 'spider' || a.animalType === 'bird') && !a.caught) {
a.destroy();
animals.splice(i, 1);
}
}
game.spidersAndBirdsGone = true;
}
// (tree spawn logic after killCount >= 23 removed)
updateUI();
};
// Play music
LK.playMusic('forest_theme', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
Spider pixel. In-Game asset. 2d. High contrast. No shadows
Lion pixel. In-Game asset. 2d. High contrast. No shadows
Zebra pixel. In-Game asset. 2d. High contrast. No shadows
Trex pixel. In-Game asset. 2d. High contrast. No shadows
Bird pixel. In-Game asset. 2d. High contrast. No shadows
person with glock18 in hand pixel. In-Game asset. 2d. High contrast. No shadows
man with sniper
Person with m4a1 in hand
Bullet pixel. In-Game asset. 2d. High contrast. No shadows
Turret pixel. In-Game asset. 2d. High contrast. No shadows
Unicorn pixel. In-Game asset. 2d. High contrast. No shadows
Tree pixel. In-Game asset. 2d. High contrast. No shadows
man with laser gun