/****
* 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