/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BigFox = Container.expand(function () {
var self = Container.call(this);
var bigFoxGraphics = self.attachAsset('bigFox', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.health = 5;
self.maxHealth = 5;
self.lastY = 0;
self.moveDirection = 'straight';
self.update = function () {
// Move towards the egg
if (egg) {
var dx = egg.x - self.x;
var dy = egg.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed * 0.7; // Slightly slower horizontal movement
self.y += dy / distance * self.speed;
} else {
// Fallback to moving down if somehow at same position
self.y += self.speed;
}
} else {
// Fallback to moving down if egg doesn't exist
self.y += self.speed;
}
// Health tracking without color changes
var healthRatio = self.health / self.maxHealth;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
return true; // BigFox is dead
}
return false;
};
return self;
});
var BlackChicken = Container.expand(function () {
var self = Container.call(this);
var chickenGraphics = self.attachAsset('blackChicken', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.shootTimer = 0;
self.shootCooldown = 60; // 1 second at 60fps
self.target = null;
self.lastTarget = null;
self.damage = 4; // 4x stronger than regular chicken
self.update = function () {
// Find nearest fox
var nearestFox = null;
var nearestDistance = Infinity;
for (var i = 0; i < foxes.length; i++) {
var fox = foxes[i];
var distance = Math.sqrt(Math.pow(fox.x - self.x, 2) + Math.pow(fox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = fox;
}
}
// Check big foxes too
for (var i = 0; i < bigFoxes.length; i++) {
var bigFox = bigFoxes[i];
var distance = Math.sqrt(Math.pow(bigFox.x - self.x, 2) + Math.pow(bigFox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = bigFox;
}
}
self.target = nearestFox;
// Move towards target
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Shoot at target
self.shootTimer++;
if (self.shootTimer >= self.shootCooldown && self.target) {
self.shootTimer = 0;
self.shoot();
}
};
self.shoot = function () {
if (self.target) {
// Fire 3 shots for black chicken with slight spread
var angles = [-0.3, 0, 0.3]; // Left, center, right spread
for (var shotIndex = 0; shotIndex < 3; shotIndex++) {
var newBullet = new Bullet();
newBullet.x = self.x;
newBullet.y = self.y;
// Add angle spread to target position
var angle = Math.atan2(self.target.y - self.y, self.target.x - self.x) + angles[shotIndex];
var distance = 500; // Arbitrary distance for target calculation
newBullet.targetX = self.x + Math.cos(angle) * distance;
newBullet.targetY = self.y + Math.sin(angle) * distance;
newBullet.damage = self.damage; // Use black chicken's damage
bullets.push(newBullet);
game.addChild(newBullet);
}
LK.getSound('shoot').play();
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.damage = 1;
// Calculate direction on creation
self.calculateDirection = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
};
self.update = function () {
if (self.directionX === 0 && self.directionY === 0) {
self.calculateDirection();
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Chicken = Container.expand(function () {
var self = Container.call(this);
var chickenGraphics = self.attachAsset('chicken', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.shootTimer = 0;
self.shootCooldown = 60; // 1 second at 60fps
self.target = null;
self.lastTarget = null;
self.update = function () {
// Find nearest fox
var nearestFox = null;
var nearestDistance = Infinity;
for (var i = 0; i < foxes.length; i++) {
var fox = foxes[i];
var distance = Math.sqrt(Math.pow(fox.x - self.x, 2) + Math.pow(fox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = fox;
}
}
// Check big foxes too
for (var i = 0; i < bigFoxes.length; i++) {
var bigFox = bigFoxes[i];
var distance = Math.sqrt(Math.pow(bigFox.x - self.x, 2) + Math.pow(bigFox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = bigFox;
}
}
self.target = nearestFox;
// Move towards target
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Shoot at target
self.shootTimer++;
if (self.shootTimer >= self.shootCooldown && self.target) {
self.shootTimer = 0;
self.shoot();
}
};
self.shoot = function () {
if (self.target) {
var newBullet = new Bullet();
newBullet.x = self.x;
newBullet.y = self.y;
newBullet.targetX = self.target.x;
newBullet.targetY = self.target.y;
bullets.push(newBullet);
game.addChild(newBullet);
LK.getSound('shoot').play();
}
};
return self;
});
var Egg = Container.expand(function () {
var self = Container.call(this);
var eggGraphics = self.attachAsset('egg', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 10;
self.maxHealth = 10;
self.hatchChance = 0.025; // 2.5% chance
self.blackChickenChance = 0.005; // 0.5% chance
self.lastHealth = self.health;
self.down = function (x, y, obj) {
self.tryHatch();
};
self.tryHatch = function () {
touchCount++;
// Check if we've reached guaranteed spawn threshold
if (touchCount >= guaranteedSpawnTouches) {
// Guaranteed spawn - reset counter and spawn chicken
touchCount = 0;
self.spawnChicken();
LK.getSound('hatch').play();
LK.effects.flashObject(self, 0xFFD700, 300);
return;
}
// Regular random spawn logic
var randomValue = Math.random();
if (randomValue < self.blackChickenChance) {
// Spawn black chicken (0.5% chance)
self.spawnBlackChicken();
LK.getSound('hatch').play();
LK.effects.flashObject(self, 0x000000, 300);
// Reset touch counter since we got a spawn
touchCount = 0;
} else if (randomValue < self.hatchChance) {
// Spawn regular chicken (remaining 2% to reach 2.5% total)
self.spawnChicken();
LK.getSound('hatch').play();
LK.effects.flashObject(self, 0xFFD700, 300);
// Reset touch counter since we got a spawn
touchCount = 0;
} else {
// Failed hatch visual feedback
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
self.spawnChicken = function () {
var newChicken = new Chicken();
// Spawn on top of the egg with random horizontal offset
newChicken.x = self.x + (Math.random() - 0.5) * 200; // Random offset between -100 and +100
newChicken.y = self.y - 400;
chickens.push(newChicken);
game.addChild(newChicken);
chickenCount++;
chickenTxt.setText('Chickens: ' + chickens.length);
};
self.spawnBlackChicken = function () {
var newBlackChicken = new BlackChicken();
// Spawn on top of the egg with random horizontal offset
newBlackChicken.x = self.x + (Math.random() - 0.5) * 200; // Random offset between -100 and +100
newBlackChicken.y = self.y - 400;
chickens.push(newBlackChicken);
game.addChild(newBlackChicken);
chickenCount++;
chickenTxt.setText('Chickens: ' + chickens.length);
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 500);
// Update egg color based on health
var healthRatio = self.health / self.maxHealth;
if (healthRatio > 0.6) {
eggGraphics.tint = 0xFFF8DC; // Beige
} else if (healthRatio > 0.3) {
eggGraphics.tint = 0xFFD700; // Yellow
} else {
eggGraphics.tint = 0xFF4500; // Red
}
if (self.health <= 0) {
return true; // Egg is destroyed
}
return false;
};
return self;
});
var Fox = Container.expand(function () {
var self = Container.call(this);
var foxGraphics = self.attachAsset('fox', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.health = 3;
self.maxHealth = 3;
self.lastY = 0;
self.moveDirection = 'straight'; // Default movement direction
self.update = function () {
// Move towards the egg
if (egg) {
var dx = egg.x - self.x;
var dy = egg.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed * 0.7; // Slightly slower horizontal movement
self.y += dy / distance * self.speed;
} else {
// Fallback to moving down if somehow at same position
self.y += self.speed;
}
} else {
// Fallback to moving down if egg doesn't exist
self.y += self.speed;
}
// Health tracking without color changes
var healthRatio = self.health / self.maxHealth;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
return true; // Fox is dead
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var egg = null;
var foxes = [];
var bigFoxes = [];
var chickens = [];
var bullets = [];
var foxSpawnTimer = 0;
var foxSpawnRate = 120; // 2 seconds at 60fps
var waveNumber = 1;
var foxesKilled = 0;
var foxesSpawned = 0;
var gameStartTime = Date.now();
var chickenCount = 0;
var lastFoxMultiplierTrigger = 0;
var touchCount = 0;
var guaranteedSpawnTouches = 50;
// Create UI elements
var healthTxt = new Text2('Egg Health: 10', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(healthTxt);
var chickenTxt = new Text2('Chickens: 0', {
size: 50,
fill: 0xFFFFFF
});
chickenTxt.anchor.set(1, 0);
chickenTxt.x = -50;
chickenTxt.y = 50;
LK.gui.topRight.addChild(chickenTxt);
// Create egg at bottom center
egg = new Egg();
egg.x = 2048 / 2;
egg.y = 2732 - 200;
game.addChild(egg);
function spawnFox() {
var newFox = new Fox();
newFox.x = Math.random() * (2048 - 160) + 80;
newFox.y = -50;
newFox.speed = 1 + Math.random() * 2 + waveNumber * 0.5;
newFox.lastY = newFox.y;
// Set diagonal movement based on spawn position
var screenCenter = 2048 / 2;
if (newFox.x < screenCenter - 300) {
// Left side - move diagonally right
newFox.moveDirection = 'diagonal-right';
} else if (newFox.x > screenCenter + 300) {
// Right side - move diagonally left
newFox.moveDirection = 'diagonal-left';
} else {
// Center - move straight down
newFox.moveDirection = 'straight';
}
foxes.push(newFox);
game.addChild(newFox);
foxesSpawned++;
}
function spawnBigFox() {
var newBigFox = new BigFox();
newBigFox.x = Math.random() * (2048 - 320) + 160;
newBigFox.y = -100;
newBigFox.speed = 1 + waveNumber * 0.3;
newBigFox.lastY = newBigFox.y;
newBigFox.moveDirection = 'straight';
bigFoxes.push(newBigFox);
game.addChild(newBigFox);
}
function updateDifficulty() {
var currentTime = Date.now();
var elapsedTime = (currentTime - gameStartTime) / 1000;
// Increase wave every 30 seconds
var newWave = Math.floor(elapsedTime / 30) + 1;
if (newWave > waveNumber) {
waveNumber = newWave;
chickenTxt.setText('Chickens: ' + chickens.length);
// Increase spawn rate
foxSpawnRate = Math.max(30, 120 - waveNumber * 10);
}
}
game.update = function () {
updateDifficulty();
// Spawn foxes
foxSpawnTimer++;
if (foxSpawnTimer >= foxSpawnRate) {
foxSpawnTimer = 0;
// Check if we need to spawn 2x foxes (every 5 chickens)
var foxesToSpawn = 1;
var currentFoxMultiplierTrigger = Math.floor(chickenCount / 5);
if (currentFoxMultiplierTrigger > lastFoxMultiplierTrigger) {
foxesToSpawn = 2;
lastFoxMultiplierTrigger = currentFoxMultiplierTrigger;
}
// Spawn the calculated number of foxes
for (var spawnIndex = 0; spawnIndex < foxesToSpawn; spawnIndex++) {
spawnFox();
// Spawn big fox every 20 foxes
if (foxesSpawned % 20 === 0) {
spawnBigFox();
}
}
}
// Update foxes
for (var i = foxes.length - 1; i >= 0; i--) {
var fox = foxes[i];
// Check if fox reached egg
if (fox.lastY < egg.y && fox.y >= egg.y && Math.abs(fox.x - egg.x) < 100) {
// Fox attacks egg
if (egg.takeDamage(1)) {
// Egg is destroyed - game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
healthTxt.setText('Egg Health: ' + egg.health);
// Remove fox after attack
fox.destroy();
foxes.splice(i, 1);
continue;
}
// Remove foxes that go off screen
if (fox.y > 2732 + 100) {
fox.destroy();
foxes.splice(i, 1);
continue;
}
fox.lastY = fox.y;
}
// Update big foxes
for (var i = bigFoxes.length - 1; i >= 0; i--) {
var bigFox = bigFoxes[i];
// Check if big fox reached egg
if (bigFox.lastY < egg.y && bigFox.y >= egg.y && Math.abs(bigFox.x - egg.x) < 150) {
// Big fox attacks egg for 3 damage
if (egg.takeDamage(3)) {
// Egg is destroyed - game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
healthTxt.setText('Egg Health: ' + egg.health);
// Remove big fox after attack
bigFox.destroy();
bigFoxes.splice(i, 1);
continue;
}
// Remove big foxes that go off screen
if (bigFox.y > 2732 + 100) {
bigFox.destroy();
bigFoxes.splice(i, 1);
continue;
}
bigFox.lastY = bigFox.y;
}
// Update bullets
for (var j = bullets.length - 1; j >= 0; j--) {
var bullet = bullets[j];
// Check bullet-fox collisions
var hit = false;
for (var k = foxes.length - 1; k >= 0; k--) {
var fox = foxes[k];
if (bullet.intersects(fox)) {
// Bullet hits fox - kill immediately with one hit
LK.getSound('foxHit').play();
foxesKilled++;
LK.setScore(foxesKilled * 10);
chickenTxt.setText('Chickens: ' + chickens.length);
fox.destroy();
foxes.splice(k, 1);
bullet.destroy();
bullets.splice(j, 1);
hit = true;
break;
}
}
// Check bullet-big fox collisions
if (!hit) {
for (var k = bigFoxes.length - 1; k >= 0; k--) {
var bigFox = bigFoxes[k];
if (bullet.intersects(bigFox)) {
// Bullet hits big fox - takes 5 bullets to kill
LK.getSound('foxHit').play();
if (bigFox.takeDamage(bullet.damage)) {
// Big fox is dead
foxesKilled++;
LK.setScore(foxesKilled * 50); // Big fox worth 50 points
chickenTxt.setText('Chickens: ' + chickens.length);
bigFox.destroy();
bigFoxes.splice(k, 1);
}
bullet.destroy();
bullets.splice(j, 1);
hit = true;
break;
}
}
}
// Remove bullets that go off screen
if (!hit && (bullet.x < -50 || bullet.x > 2048 + 50 || bullet.y < -50 || bullet.y > 2732 + 50)) {
bullet.destroy();
bullets.splice(j, 1);
}
}
// Update chickens
for (var l = chickens.length - 1; l >= 0; l--) {
var chicken = chickens[l];
// Check if chicken is still alive (no health system for chickens yet)
// Could add zombie attacks on chickens in future versions
// Check fox-chicken collisions
var chickenHit = false;
// Check regular foxes
for (var m = foxes.length - 1; m >= 0; m--) {
var fox = foxes[m];
if (chicken.intersects(fox)) {
// Fox kills chicken
chicken.destroy();
chickens.splice(l, 1);
chickenHit = true;
break;
}
}
// Check big foxes if chicken not already hit
if (!chickenHit) {
for (var m = bigFoxes.length - 1; m >= 0; m--) {
var bigFox = bigFoxes[m];
if (chicken.intersects(bigFox)) {
// Big fox kills chicken
chicken.destroy();
chickens.splice(l, 1);
chickenHit = true;
break;
}
}
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BigFox = Container.expand(function () {
var self = Container.call(this);
var bigFoxGraphics = self.attachAsset('bigFox', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.health = 5;
self.maxHealth = 5;
self.lastY = 0;
self.moveDirection = 'straight';
self.update = function () {
// Move towards the egg
if (egg) {
var dx = egg.x - self.x;
var dy = egg.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed * 0.7; // Slightly slower horizontal movement
self.y += dy / distance * self.speed;
} else {
// Fallback to moving down if somehow at same position
self.y += self.speed;
}
} else {
// Fallback to moving down if egg doesn't exist
self.y += self.speed;
}
// Health tracking without color changes
var healthRatio = self.health / self.maxHealth;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
return true; // BigFox is dead
}
return false;
};
return self;
});
var BlackChicken = Container.expand(function () {
var self = Container.call(this);
var chickenGraphics = self.attachAsset('blackChicken', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.shootTimer = 0;
self.shootCooldown = 60; // 1 second at 60fps
self.target = null;
self.lastTarget = null;
self.damage = 4; // 4x stronger than regular chicken
self.update = function () {
// Find nearest fox
var nearestFox = null;
var nearestDistance = Infinity;
for (var i = 0; i < foxes.length; i++) {
var fox = foxes[i];
var distance = Math.sqrt(Math.pow(fox.x - self.x, 2) + Math.pow(fox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = fox;
}
}
// Check big foxes too
for (var i = 0; i < bigFoxes.length; i++) {
var bigFox = bigFoxes[i];
var distance = Math.sqrt(Math.pow(bigFox.x - self.x, 2) + Math.pow(bigFox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = bigFox;
}
}
self.target = nearestFox;
// Move towards target
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Shoot at target
self.shootTimer++;
if (self.shootTimer >= self.shootCooldown && self.target) {
self.shootTimer = 0;
self.shoot();
}
};
self.shoot = function () {
if (self.target) {
// Fire 3 shots for black chicken with slight spread
var angles = [-0.3, 0, 0.3]; // Left, center, right spread
for (var shotIndex = 0; shotIndex < 3; shotIndex++) {
var newBullet = new Bullet();
newBullet.x = self.x;
newBullet.y = self.y;
// Add angle spread to target position
var angle = Math.atan2(self.target.y - self.y, self.target.x - self.x) + angles[shotIndex];
var distance = 500; // Arbitrary distance for target calculation
newBullet.targetX = self.x + Math.cos(angle) * distance;
newBullet.targetY = self.y + Math.sin(angle) * distance;
newBullet.damage = self.damage; // Use black chicken's damage
bullets.push(newBullet);
game.addChild(newBullet);
}
LK.getSound('shoot').play();
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.damage = 1;
// Calculate direction on creation
self.calculateDirection = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
};
self.update = function () {
if (self.directionX === 0 && self.directionY === 0) {
self.calculateDirection();
}
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Chicken = Container.expand(function () {
var self = Container.call(this);
var chickenGraphics = self.attachAsset('chicken', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.shootTimer = 0;
self.shootCooldown = 60; // 1 second at 60fps
self.target = null;
self.lastTarget = null;
self.update = function () {
// Find nearest fox
var nearestFox = null;
var nearestDistance = Infinity;
for (var i = 0; i < foxes.length; i++) {
var fox = foxes[i];
var distance = Math.sqrt(Math.pow(fox.x - self.x, 2) + Math.pow(fox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = fox;
}
}
// Check big foxes too
for (var i = 0; i < bigFoxes.length; i++) {
var bigFox = bigFoxes[i];
var distance = Math.sqrt(Math.pow(bigFox.x - self.x, 2) + Math.pow(bigFox.y - self.y, 2));
if (distance < nearestDistance && distance < 300) {
nearestDistance = distance;
nearestFox = bigFox;
}
}
self.target = nearestFox;
// Move towards target
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Shoot at target
self.shootTimer++;
if (self.shootTimer >= self.shootCooldown && self.target) {
self.shootTimer = 0;
self.shoot();
}
};
self.shoot = function () {
if (self.target) {
var newBullet = new Bullet();
newBullet.x = self.x;
newBullet.y = self.y;
newBullet.targetX = self.target.x;
newBullet.targetY = self.target.y;
bullets.push(newBullet);
game.addChild(newBullet);
LK.getSound('shoot').play();
}
};
return self;
});
var Egg = Container.expand(function () {
var self = Container.call(this);
var eggGraphics = self.attachAsset('egg', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 10;
self.maxHealth = 10;
self.hatchChance = 0.025; // 2.5% chance
self.blackChickenChance = 0.005; // 0.5% chance
self.lastHealth = self.health;
self.down = function (x, y, obj) {
self.tryHatch();
};
self.tryHatch = function () {
touchCount++;
// Check if we've reached guaranteed spawn threshold
if (touchCount >= guaranteedSpawnTouches) {
// Guaranteed spawn - reset counter and spawn chicken
touchCount = 0;
self.spawnChicken();
LK.getSound('hatch').play();
LK.effects.flashObject(self, 0xFFD700, 300);
return;
}
// Regular random spawn logic
var randomValue = Math.random();
if (randomValue < self.blackChickenChance) {
// Spawn black chicken (0.5% chance)
self.spawnBlackChicken();
LK.getSound('hatch').play();
LK.effects.flashObject(self, 0x000000, 300);
// Reset touch counter since we got a spawn
touchCount = 0;
} else if (randomValue < self.hatchChance) {
// Spawn regular chicken (remaining 2% to reach 2.5% total)
self.spawnChicken();
LK.getSound('hatch').play();
LK.effects.flashObject(self, 0xFFD700, 300);
// Reset touch counter since we got a spawn
touchCount = 0;
} else {
// Failed hatch visual feedback
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
self.spawnChicken = function () {
var newChicken = new Chicken();
// Spawn on top of the egg with random horizontal offset
newChicken.x = self.x + (Math.random() - 0.5) * 200; // Random offset between -100 and +100
newChicken.y = self.y - 400;
chickens.push(newChicken);
game.addChild(newChicken);
chickenCount++;
chickenTxt.setText('Chickens: ' + chickens.length);
};
self.spawnBlackChicken = function () {
var newBlackChicken = new BlackChicken();
// Spawn on top of the egg with random horizontal offset
newBlackChicken.x = self.x + (Math.random() - 0.5) * 200; // Random offset between -100 and +100
newBlackChicken.y = self.y - 400;
chickens.push(newBlackChicken);
game.addChild(newBlackChicken);
chickenCount++;
chickenTxt.setText('Chickens: ' + chickens.length);
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 500);
// Update egg color based on health
var healthRatio = self.health / self.maxHealth;
if (healthRatio > 0.6) {
eggGraphics.tint = 0xFFF8DC; // Beige
} else if (healthRatio > 0.3) {
eggGraphics.tint = 0xFFD700; // Yellow
} else {
eggGraphics.tint = 0xFF4500; // Red
}
if (self.health <= 0) {
return true; // Egg is destroyed
}
return false;
};
return self;
});
var Fox = Container.expand(function () {
var self = Container.call(this);
var foxGraphics = self.attachAsset('fox', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.health = 3;
self.maxHealth = 3;
self.lastY = 0;
self.moveDirection = 'straight'; // Default movement direction
self.update = function () {
// Move towards the egg
if (egg) {
var dx = egg.x - self.x;
var dy = egg.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed * 0.7; // Slightly slower horizontal movement
self.y += dy / distance * self.speed;
} else {
// Fallback to moving down if somehow at same position
self.y += self.speed;
}
} else {
// Fallback to moving down if egg doesn't exist
self.y += self.speed;
}
// Health tracking without color changes
var healthRatio = self.health / self.maxHealth;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
return true; // Fox is dead
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var egg = null;
var foxes = [];
var bigFoxes = [];
var chickens = [];
var bullets = [];
var foxSpawnTimer = 0;
var foxSpawnRate = 120; // 2 seconds at 60fps
var waveNumber = 1;
var foxesKilled = 0;
var foxesSpawned = 0;
var gameStartTime = Date.now();
var chickenCount = 0;
var lastFoxMultiplierTrigger = 0;
var touchCount = 0;
var guaranteedSpawnTouches = 50;
// Create UI elements
var healthTxt = new Text2('Egg Health: 10', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(healthTxt);
var chickenTxt = new Text2('Chickens: 0', {
size: 50,
fill: 0xFFFFFF
});
chickenTxt.anchor.set(1, 0);
chickenTxt.x = -50;
chickenTxt.y = 50;
LK.gui.topRight.addChild(chickenTxt);
// Create egg at bottom center
egg = new Egg();
egg.x = 2048 / 2;
egg.y = 2732 - 200;
game.addChild(egg);
function spawnFox() {
var newFox = new Fox();
newFox.x = Math.random() * (2048 - 160) + 80;
newFox.y = -50;
newFox.speed = 1 + Math.random() * 2 + waveNumber * 0.5;
newFox.lastY = newFox.y;
// Set diagonal movement based on spawn position
var screenCenter = 2048 / 2;
if (newFox.x < screenCenter - 300) {
// Left side - move diagonally right
newFox.moveDirection = 'diagonal-right';
} else if (newFox.x > screenCenter + 300) {
// Right side - move diagonally left
newFox.moveDirection = 'diagonal-left';
} else {
// Center - move straight down
newFox.moveDirection = 'straight';
}
foxes.push(newFox);
game.addChild(newFox);
foxesSpawned++;
}
function spawnBigFox() {
var newBigFox = new BigFox();
newBigFox.x = Math.random() * (2048 - 320) + 160;
newBigFox.y = -100;
newBigFox.speed = 1 + waveNumber * 0.3;
newBigFox.lastY = newBigFox.y;
newBigFox.moveDirection = 'straight';
bigFoxes.push(newBigFox);
game.addChild(newBigFox);
}
function updateDifficulty() {
var currentTime = Date.now();
var elapsedTime = (currentTime - gameStartTime) / 1000;
// Increase wave every 30 seconds
var newWave = Math.floor(elapsedTime / 30) + 1;
if (newWave > waveNumber) {
waveNumber = newWave;
chickenTxt.setText('Chickens: ' + chickens.length);
// Increase spawn rate
foxSpawnRate = Math.max(30, 120 - waveNumber * 10);
}
}
game.update = function () {
updateDifficulty();
// Spawn foxes
foxSpawnTimer++;
if (foxSpawnTimer >= foxSpawnRate) {
foxSpawnTimer = 0;
// Check if we need to spawn 2x foxes (every 5 chickens)
var foxesToSpawn = 1;
var currentFoxMultiplierTrigger = Math.floor(chickenCount / 5);
if (currentFoxMultiplierTrigger > lastFoxMultiplierTrigger) {
foxesToSpawn = 2;
lastFoxMultiplierTrigger = currentFoxMultiplierTrigger;
}
// Spawn the calculated number of foxes
for (var spawnIndex = 0; spawnIndex < foxesToSpawn; spawnIndex++) {
spawnFox();
// Spawn big fox every 20 foxes
if (foxesSpawned % 20 === 0) {
spawnBigFox();
}
}
}
// Update foxes
for (var i = foxes.length - 1; i >= 0; i--) {
var fox = foxes[i];
// Check if fox reached egg
if (fox.lastY < egg.y && fox.y >= egg.y && Math.abs(fox.x - egg.x) < 100) {
// Fox attacks egg
if (egg.takeDamage(1)) {
// Egg is destroyed - game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
healthTxt.setText('Egg Health: ' + egg.health);
// Remove fox after attack
fox.destroy();
foxes.splice(i, 1);
continue;
}
// Remove foxes that go off screen
if (fox.y > 2732 + 100) {
fox.destroy();
foxes.splice(i, 1);
continue;
}
fox.lastY = fox.y;
}
// Update big foxes
for (var i = bigFoxes.length - 1; i >= 0; i--) {
var bigFox = bigFoxes[i];
// Check if big fox reached egg
if (bigFox.lastY < egg.y && bigFox.y >= egg.y && Math.abs(bigFox.x - egg.x) < 150) {
// Big fox attacks egg for 3 damage
if (egg.takeDamage(3)) {
// Egg is destroyed - game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
healthTxt.setText('Egg Health: ' + egg.health);
// Remove big fox after attack
bigFox.destroy();
bigFoxes.splice(i, 1);
continue;
}
// Remove big foxes that go off screen
if (bigFox.y > 2732 + 100) {
bigFox.destroy();
bigFoxes.splice(i, 1);
continue;
}
bigFox.lastY = bigFox.y;
}
// Update bullets
for (var j = bullets.length - 1; j >= 0; j--) {
var bullet = bullets[j];
// Check bullet-fox collisions
var hit = false;
for (var k = foxes.length - 1; k >= 0; k--) {
var fox = foxes[k];
if (bullet.intersects(fox)) {
// Bullet hits fox - kill immediately with one hit
LK.getSound('foxHit').play();
foxesKilled++;
LK.setScore(foxesKilled * 10);
chickenTxt.setText('Chickens: ' + chickens.length);
fox.destroy();
foxes.splice(k, 1);
bullet.destroy();
bullets.splice(j, 1);
hit = true;
break;
}
}
// Check bullet-big fox collisions
if (!hit) {
for (var k = bigFoxes.length - 1; k >= 0; k--) {
var bigFox = bigFoxes[k];
if (bullet.intersects(bigFox)) {
// Bullet hits big fox - takes 5 bullets to kill
LK.getSound('foxHit').play();
if (bigFox.takeDamage(bullet.damage)) {
// Big fox is dead
foxesKilled++;
LK.setScore(foxesKilled * 50); // Big fox worth 50 points
chickenTxt.setText('Chickens: ' + chickens.length);
bigFox.destroy();
bigFoxes.splice(k, 1);
}
bullet.destroy();
bullets.splice(j, 1);
hit = true;
break;
}
}
}
// Remove bullets that go off screen
if (!hit && (bullet.x < -50 || bullet.x > 2048 + 50 || bullet.y < -50 || bullet.y > 2732 + 50)) {
bullet.destroy();
bullets.splice(j, 1);
}
}
// Update chickens
for (var l = chickens.length - 1; l >= 0; l--) {
var chicken = chickens[l];
// Check if chicken is still alive (no health system for chickens yet)
// Could add zombie attacks on chickens in future versions
// Check fox-chicken collisions
var chickenHit = false;
// Check regular foxes
for (var m = foxes.length - 1; m >= 0; m--) {
var fox = foxes[m];
if (chicken.intersects(fox)) {
// Fox kills chicken
chicken.destroy();
chickens.splice(l, 1);
chickenHit = true;
break;
}
}
// Check big foxes if chicken not already hit
if (!chickenHit) {
for (var m = bigFoxes.length - 1; m >= 0; m--) {
var bigFox = bigFoxes[m];
if (chicken.intersects(bigFox)) {
// Big fox kills chicken
chicken.destroy();
chickens.splice(l, 1);
chickenHit = true;
break;
}
}
}
}
};