/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Removed plugin import to fix 'Unable to load plugins' error
var Animal = Container.expand(function () {
var self = Container.call(this);
self.animalAsset = null;
self.setAnimalImage = function (imageId) {
if (self.animalAsset) {
self.animalAsset.destroy();
}
self.animalAsset = self.attachAsset(imageId, {
anchorX: 0.5,
anchorY: 0.5
});
};
return self;
});
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
// Create the bird asset
var birdAsset = self.attachAsset('Bird', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1,
scaleX: 0.8,
scaleY: 0.8
});
// Variables for movement
self.speed = 1.0; // Faster than clouds
self.lifeTime = 3000; // 50 seconds at 60fps
self.lifeCounter = 0; // Track how long bird has been visible
self.flyHeight = 0; // Vertical position offset for flying pattern
// Initialize bird
self.init = function () {
self.lifeCounter = 0;
self.alpha = 1;
// Start movement animation using tween
self.startMoving();
};
// Start the left to right movement with slight up/down wave pattern
self.startMoving = function () {
// Move bird to the right side of screen
var targetX = 2048 + birdAsset.width / 2; // Move past right edge
// Create the movement tween
tween(self, {
x: targetX
}, {
duration: 20000,
// Faster than clouds - 20 seconds to cross screen
easing: tween.linear
});
};
// Update function called every frame
self.update = function () {
// Increment life counter
self.lifeCounter++;
// Create a small wavy flight pattern
self.y = self.y + Math.sin(self.lifeCounter * 0.03) * 1.5;
// If bird has reached the right edge of the screen
if (self.x >= 2048 + birdAsset.width / 2) {
// Stop any existing tweens on this bird
tween.stop(self);
// Fade out animation
tween(self, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove bird from game
self.destroy();
}
});
}
};
return self;
});
// CarrotSlot class for area 2
var CarrotSlot = Container.expand(function () {
var self = Container.call(this);
self.slotAsset = self.attachAsset('carrot', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 1; // Area 2
self.regrowing = false;
// Show/hide carrot and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide carrot with animation
tween(self.slotAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
// Show sprout with animation
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show carrot with animation
tween(self.slotAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Hide sprout with animation
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to carrot size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to carrot and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
// Cloud class
var Cloud = Container.expand(function () {
var self = Container.call(this);
// Create the cloud asset
var cloudAsset = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8 // Semi-transparent clouds
});
// Variables for movement
self.speed = 0.2; // Very slow speed for smooth movement
self.lifeTime = 6000; // 100 seconds at 60fps - longer lifetime
self.lifeCounter = 0; // Track how long cloud has been visible
self.layer = 0; // Layer for visual depth (0 = front, 1 = back)
// Initialize cloud
self.init = function () {
self.lifeCounter = 0;
self.alpha = 1;
// Apply layer-specific settings
if (self.layer === 1) {
// Back layer cloud (slightly smaller and more transparent)
self.scale.set(0.8, 0.8);
self.alpha = 0.7;
}
// Start movement animation using tween
self.startMoving();
};
// Start the left to right movement only
self.startMoving = function () {
// Move cloud to the right side of screen
var targetX = 2048 + cloudAsset.width / 2; // Move past right edge
// Create the movement tween
tween(self, {
x: targetX
}, {
duration: 60000,
// Slower movement - 60 seconds to cross screen
easing: tween.linear
});
};
// Update function called every frame
self.update = function () {
// Increment life counter
self.lifeCounter++;
// Track lastX for edge detection
if (typeof self.lastX === "undefined") {
self.lastX = self.x;
}
// If cloud has just reached the right edge of the screen (crossed this frame)
if (self.lastX < 2048 + cloudAsset.width / 2 && self.x >= 2048 + cloudAsset.width / 2) {
// Stop any existing tweens on this cloud
tween.stop(self);
// Fade out animation
tween(self, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove cloud from game
self.destroy();
}
});
}
// Update lastX for next frame
self.lastX = self.x;
};
return self;
});
// EggplantSlot class for area 4
var EggplantSlot = Container.expand(function () {
var self = Container.call(this);
self.slotAsset = self.attachAsset('eggplant', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 3; // Area 4
self.regrowing = false;
// Show/hide eggplant and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide eggplant with animation
tween(self.slotAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
// Show sprout with animation
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show eggplant with animation
tween(self.slotAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Hide sprout with animation
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to eggplant size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to eggplant and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
// Farmer class
var Farmer = Container.expand(function () {
var self = Container.call(this);
// Create animation frames
var idleFrame = self.attachAsset('farmer', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
// Frame 2 (running)
var runningFrame = self.attachAsset('farmer_walk', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Frame 3 (right step)
var rightStepFrame = self.attachAsset('farmer_walk', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
rotation: 0.1
});
self.speed = 18; // px per move
self.targetX = self.x;
self.targetY = self.y;
self.moving = false;
self.lastMoving = false;
self.animationTimer = 0;
self.animationFrame = 0;
self.frameTime = 18; // 0.3 seconds at 60fps
// Animation frame switching
self.switchToFrame = function (frameNum) {
idleFrame.alpha = 0;
runningFrame.alpha = 0;
rightStepFrame.alpha = 0;
if (frameNum === 0) {
// Idle
idleFrame.alpha = 1;
} else if (frameNum === 1) {
// Running
runningFrame.alpha = 1;
} else if (frameNum === 2) {
// Right step
rightStepFrame.alpha = 1;
}
};
// Move farmer towards target
self.update = function () {
// Track movement direction and update image
if (self.moving) {
var dx = self.targetX - self.x;
// Check if moving right or left
if (dx > 0) {
// Moving right - use player_right asset
idleFrame.scaleX = 1;
runningFrame.scaleX = 1;
rightStepFrame.scaleX = 1;
// Switch to player_right image
if (self.currentAsset !== idleFrame || idleFrame.texture !== LK.getAsset('player_right', {}).texture) {
if (self.currentAsset) {
self.currentAsset.alpha = 0;
}
var rightAsset = LK.getAsset('player_right', {
anchorX: 0.5,
anchorY: 0.5
});
rightAsset.alpha = 1;
self.addChild(rightAsset);
self.currentAsset = rightAsset;
}
} else if (dx < 0) {
// Moving left - use player_left asset
idleFrame.scaleX = -1;
runningFrame.scaleX = -1;
rightStepFrame.scaleX = -1;
// Switch to player_left image
if (self.currentAsset !== idleFrame || idleFrame.texture !== LK.getAsset('player_left', {}).texture) {
if (self.currentAsset) {
self.currentAsset.alpha = 0;
}
var leftAsset = LK.getAsset('player_left', {
anchorX: 0.5,
anchorY: 0.5
});
leftAsset.alpha = 1;
self.addChild(leftAsset);
self.currentAsset = leftAsset;
}
}
// Animation handling
self.animationTimer++;
if (self.animationTimer >= self.frameTime) {
self.animationTimer = 0;
self.animationFrame = self.animationFrame === 1 ? 2 : 1; // Toggle between frames 1 and 2
self.switchToFrame(self.animationFrame);
}
} else if (!self.moving && self.lastMoving) {
// Just stopped moving - switch to idle
self.switchToFrame(0);
}
self.lastMoving = self.moving;
if (!self.moving) {
return;
}
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.speed) {
self.x = self.targetX;
self.y = self.targetY;
self.moving = false;
// Switch to idle frame when stopping
self.switchToFrame(0);
} else {
self.x += self.speed * dx / dist;
self.y += self.speed * dy / dist;
}
};
// Set movement target
self.moveTo = function (x, y) {
self.targetX = x;
self.targetY = y;
// Start movement
if (!self.moving) {
self.moving = true;
self.animationFrame = 1;
self.animationTimer = 0;
self.switchToFrame(self.animationFrame);
}
};
// Attach sickle to farmer's hand
var sickle = self.attachAsset('sickle', {
anchorX: 0.2,
// hand position, left side of ellipse
anchorY: 0.7,
// slightly below center
x: 0,
y: 30
});
sickle.alpha = 1;
// Add attack animation for sickle
self.attack = function () {
tween(sickle, {
rotation: Math.PI * 2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
sickle.rotation = 0;
}
});
};
return self;
});
// Field class
var Field = Container.expand(function () {
var self = Container.call(this);
self.index = 0; // 0-3
self.locked = false;
self.lockCost = 0;
self.lockNode = null;
self.fenceNodes = [];
self.wheats = [];
self.unlockBtn = null;
// Draw fences - Empty implementation to eliminate fences
self.drawFences = function (x, y, w, h) {
self.fenceNodes = [];
// No fences or gates are created
};
// Place wheat
self.placeWheats = function (x, y, w, h, count) {
self.wheats = [];
// Define grid size
var rows = 5;
var cols = 10;
// Choose vegetable asset per area
var vegAssetId = 'wheat';
if (self.index === 1) {
vegAssetId = 'carrot';
}
if (self.index === 2) {
vegAssetId = 'tomato';
}
if (self.index === 3) {
vegAssetId = 'eggplant';
}
// Fallback if asset not found, use wheat
if (!LK.assets || !LK.assets[vegAssetId]) {
vegAssetId = 'wheat';
}
// Calculate asset size for spacing (use wheat size as reference for all)
var vegAsset = LK.getAsset('wheat', {
anchorX: 0.5,
anchorY: 1
});
var wheatW = vegAsset.width;
var wheatH = vegAsset.height;
// Padding from fences
var padX = 60;
var padY = 60;
// Compute available area for wheat grid
var gridW = w - 2 * padX;
var gridH = h - 2 * padY;
// Compute spacing between wheat plants
var spacingX = (gridW - wheatW) / (cols - 1);
var spacingY = (gridH - wheatH) / (rows - 1);
// Place appropriate vegetable in grid based on field index
for (var row = 0; row < rows; ++row) {
for (var col = 0; col < cols; ++col) {
var wx = x + padX + col * spacingX + wheatW / 2;
var wy = y + padY + row * spacingY + wheatH;
var veg;
// Create appropriate vegetable based on area/field index
if (self.index === 1) {
veg = new CarrotSlot();
} else if (self.index === 2) {
veg = new TomatoSlot();
} else if (self.index === 3) {
veg = new EggplantSlot();
} else {
veg = new Wheat();
veg.fieldIndex = self.index;
veg.vegAssetId = vegAssetId;
veg.setVegAsset && veg.setVegAsset(vegAssetId);
}
veg.x = wx;
veg.y = wy;
self.addChild(veg);
self.wheats.push(veg);
}
}
};
// Lock overlay
self.showLock = function (centerX, centerY) {
if (self.lockNode) {
return;
}
self.lockNode = LK.getAsset('lock', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX,
y: centerY
});
self.addChild(self.lockNode);
// Unlock text
var unlockTxt = new Text2('Unlock\n$' + self.lockCost, {
size: 60,
fill: "#fff"
});
unlockTxt.anchor.set(0.5, 0.5);
unlockTxt.x = centerX;
unlockTxt.y = centerY + 70;
self.unlockBtn = unlockTxt;
self.addChild(unlockTxt);
};
self.hideLock = function () {
if (self.lockNode) {
self.lockNode.destroy();
self.lockNode = null;
}
if (self.unlockBtn) {
self.unlockBtn.destroy();
self.unlockBtn = null;
}
};
return self;
});
// Zombie respawn is now handled after being killed by the player;
// IntroScreen class for game intro animation with improved loading
var IntroScreen = Container.expand(function () {
var self = Container.call(this);
// Track loading state
self.loadingPhase = 0; // 0=Loading core, 1=Loading intro, 2=Loading game assets, 3=Complete
self.animationStarted = false;
self.introAssetsLoaded = false;
self.gameAssetsLoaded = false;
// Create a dark overlay as background
var overlay = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0,
scaleX: 30,
scaleY: 40,
alpha: 1,
tint: 0x000000
});
self.addChild(overlay);
// Loading text
var loadingText = new Text2('Loading Core Assets...', {
size: 120,
fill: 0xFFFFFF
});
loadingText.anchor.set(0.5, 0.5);
loadingText.x = 2048 / 2;
loadingText.y = 2732 / 2;
self.addChild(loadingText);
// Animation references
var sunriseBackground = null;
var introClouds = [];
var maleFarmer = null;
var femaleFarmer = null;
var sproutAsset = null;
var wheatAsset = null;
var carrotAsset = null;
var tomatoAsset = null;
var titleText = null;
var subtitleText = null;
var introZombie = null;
var introSickle = null;
var startButtonBg = null;
var startText = null;
// Loading dots animation
self.updateLoadingText = function () {
if (self.loadingPhase >= 3) {
return;
}
var dots = '';
if (loadingText && loadingText.text) {
var baseTxt = '';
if (self.loadingPhase === 0) {
baseTxt = 'Loading Core Assets';
} else if (self.loadingPhase === 1) {
baseTxt = 'Loading Intro Assets';
} else if (self.loadingPhase === 2) {
baseTxt = 'Loading Game Assets';
}
if (loadingText.text.indexOf(baseTxt) === 0) {
var parts = loadingText.text.split(baseTxt);
dots = parts.length > 1 ? parts[1] : '';
}
}
// Cycle through dot patterns
if (dots === '...') {
dots = '';
} else if (dots === '') {
dots = '.';
} else if (dots === '.') {
dots = '..';
} else if (dots === '..') {
dots = '...';
}
// Update text based on current loading phase
var baseTxt = '';
if (self.loadingPhase === 0) {
baseTxt = 'Loading Core Assets';
} else if (self.loadingPhase === 1) {
baseTxt = 'Loading Intro Assets';
} else if (self.loadingPhase === 2) {
baseTxt = 'Loading Game Assets';
}
loadingText.setText(baseTxt + dots);
// Continue animation until all assets are loaded
LK.setTimeout(self.updateLoadingText, 500);
};
// Check if intro assets are loaded
self.checkIntroAssetsLoaded = function () {
if (!self.introAssetsLoaded) {
var allAssetsLoaded = true;
var testAssets = ['centerCircle', 'cloud'];
for (var i = 0; i < testAssets.length; i++) {
var testAsset = LK.getAsset(testAssets[i], {
anchorX: 0.5,
anchorY: 0.5
});
if (!testAsset || !testAsset.width) {
allAssetsLoaded = false;
break;
}
}
if (allAssetsLoaded) {
self.introAssetsLoaded = true;
self.loadingPhase = 1;
// Now that intro assets are loaded, create the intro elements
self.createIntroElements();
// Start loading game assets
LK.setTimeout(self.checkGameAssetsLoaded, 100);
} else {
// Check again in a moment
LK.setTimeout(self.checkIntroAssetsLoaded, 100);
}
}
};
// Check if game assets are loaded
self.checkGameAssetsLoaded = function () {
if (!self.gameAssetsLoaded) {
var allAssetsLoaded = true;
var testAssets = ['farmer', 'wheat', 'zombie_1', 'tomato', 'carrot', 'eggplant', 'sickle'];
for (var i = 0; i < testAssets.length; i++) {
var testAsset = LK.getAsset(testAssets[i], {
anchorX: 0.5,
anchorY: 0.5
});
if (!testAsset || !testAsset.width) {
allAssetsLoaded = false;
break;
}
}
if (allAssetsLoaded) {
self.gameAssetsLoaded = true;
self.loadingPhase = 3;
// Fade out the loading text
tween(loadingText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
loadingText.destroy();
// Start the intro animation once all loading is complete
if (!self.animationStarted) {
self.animationStarted = true;
self.startAnimation();
}
}
});
} else {
// Update loading phase
self.loadingPhase = 2;
// Check again in a moment
LK.setTimeout(self.checkGameAssetsLoaded, 100);
}
}
};
// Create intro elements once basic assets are loaded
self.createIntroElements = function () {
// Add a sunrise effect background
sunriseBackground = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 30,
scaleY: 40,
alpha: 0,
tint: 0xf5cb6c // Sunrise yellow color
});
self.addChild(sunriseBackground);
// Create animated clouds for intro
introClouds = [];
for (var i = 0; i < 3; i++) {
var cloudAsset = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
x: -300 + i * 500,
y: 400 + i * 150,
alpha: 0,
scaleX: 0.8 + i * 0.3,
scaleY: 0.8 + i * 0.3
});
self.addChild(cloudAsset);
introClouds.push(cloudAsset);
}
// Create title text
titleText = new Text2('FARM HARVESTER', {
size: 180,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 2732 / 4;
titleText.alpha = 0;
self.addChild(titleText);
// Create subtitle text
subtitleText = new Text2('Grow crops, earn money, expand your farm!', {
size: 90,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = titleText.y + 200;
subtitleText.alpha = 0;
self.addChild(subtitleText);
// Create start text only, no background
startText = new Text2('TAP TO START', {
size: 100,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startText.x = 2048 / 2;
startText.y = 2732 / 2 + 600;
startText.alpha = 0;
self.addChild(startText);
};
// Start the loading process
self.updateLoadingText();
self.checkIntroAssetsLoaded();
// Lazy creation of game assets for intro only when needed
self.createGameIntroAssets = function () {
// Create male and female farmer for intro animation only when needed
if (!maleFarmer) {
maleFarmer = LK.getAsset('farmer', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 300,
y: 2732 / 2 + 200,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
});
self.addChild(maleFarmer);
}
if (!femaleFarmer) {
femaleFarmer = LK.getAsset('farmer_walk', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 300,
y: 2732 / 2 + 200,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
});
self.addChild(femaleFarmer);
}
// Create growing plant animation elements only when needed
if (!sproutAsset) {
sproutAsset = LK.getAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(sproutAsset);
}
if (!wheatAsset) {
wheatAsset = LK.getAsset('wheat', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(wheatAsset);
}
// Create vegetables that will grow from sprout
if (!carrotAsset) {
carrotAsset = LK.getAsset('carrot', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 - 200,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(carrotAsset);
}
if (!tomatoAsset) {
tomatoAsset = LK.getAsset('tomato', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 + 200,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(tomatoAsset);
}
// Add zombie for intro animation
if (!introZombie) {
introZombie = LK.getAsset('zombie_1', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 + 300,
y: 2732 / 2 + 300,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
});
self.addChild(introZombie);
}
// Add sickle for intro animation
if (!introSickle) {
introSickle = LK.getAsset('sickle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 200,
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: -Math.PI / 4
});
self.addChild(introSickle);
}
};
// Start animation sequence
self.startAnimation = function () {
// Make sure assets are loaded before starting animation
if (self.loadingPhase < 3) {
LK.setTimeout(self.checkGameAssetsLoaded, 100);
return;
}
// Create game assets needed for intro animation
self.createGameIntroAssets();
// Fade in sunrise effect
tween(sunriseBackground, {
alpha: 0.5
}, {
duration: 2000,
easing: tween.easeOut
});
// Animate clouds drifting in
for (var i = 0; i < introClouds.length; i++) {
(function (index) {
var cloud = introClouds[index];
LK.setTimeout(function () {
tween(cloud, {
alpha: 0.7,
x: cloud.x + 400
}, {
duration: 4000,
easing: tween.easeOut
});
}, 500 * index);
})(i);
}
// Fade in and animate farmers running in from sides
LK.setTimeout(function () {
// Animate male farmer running in from left
tween(maleFarmer, {
alpha: 1,
x: 2048 / 2 - 150
}, {
duration: 1500,
easing: tween.easeOut
});
// Animate female farmer running in from right
tween(femaleFarmer, {
alpha: 1,
x: 2048 / 2 + 150
}, {
duration: 1500,
easing: tween.easeOut
});
}, 1000);
// Animate farmers meeting in middle and "planting" sprout
LK.setTimeout(function () {
// Move farmers to center
tween(maleFarmer, {
x: 2048 / 2 - 50
}, {
duration: 800,
easing: tween.easeInOut
});
tween(femaleFarmer, {
x: 2048 / 2 + 50
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Show sprout growing
sproutAsset.alpha = 1;
tween(sproutAsset, {
scaleX: 1,
scaleY: 1
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Show wheat growing from sprout
wheatAsset.alpha = 1;
tween(wheatAsset, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
easing: tween.easeOut
});
// Show carrot and tomato growing
carrotAsset.alpha = 1;
tween(carrotAsset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut
});
tomatoAsset.alpha = 1;
tween(tomatoAsset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut
});
}
});
}
});
}, 3000);
// Animate zombie coming in from right
LK.setTimeout(function () {
introZombie.alpha = 1;
tween(introZombie, {
x: 2048 / 2 + 450
}, {
duration: 1500,
easing: tween.easeIn
});
}, 5000);
// Animate sickle appearing and swinging
LK.setTimeout(function () {
introSickle.alpha = 1;
tween(introSickle, {
rotation: Math.PI
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(introZombie, {
alpha: 0,
y: introZombie.y + 100
}, {
duration: 500,
easing: tween.easeIn
});
}
});
}, 6000);
// Fade in title with a fancy effect
LK.setTimeout(function () {
titleText.alpha = 0.1;
tween(titleText, {
alpha: 1,
y: titleText.y + 50
}, {
duration: 1200,
easing: tween.easeOut
});
// Flash effect for title
var _flashTitle = function flashTitle(count) {
if (count <= 0) {
return;
}
tween(titleText, {
alpha: 0.7
}, {
duration: 100,
onFinish: function onFinish() {
tween(titleText, {
alpha: 1
}, {
duration: 100,
onFinish: function onFinish() {
_flashTitle(count - 1);
}
});
}
});
};
LK.setTimeout(function () {
_flashTitle(3);
}, 1200);
}, 7000);
// Fade in subtitle with delay
LK.setTimeout(function () {
tween(subtitleText, {
alpha: 1,
y: subtitleText.y + 30
}, {
duration: 800,
easing: tween.easeOut
});
}, 8000);
// Fade out animation elements and transition to game UI
LK.setTimeout(function () {
// Fade out animation elements
if (maleFarmer) {
tween(maleFarmer, {
alpha: 0
}, {
duration: 800
});
}
if (femaleFarmer) {
tween(femaleFarmer, {
alpha: 0
}, {
duration: 800
});
}
if (sproutAsset) {
tween(sproutAsset, {
alpha: 0
}, {
duration: 800
});
}
if (wheatAsset) {
tween(wheatAsset, {
alpha: 0
}, {
duration: 800
});
}
if (carrotAsset) {
tween(carrotAsset, {
alpha: 0
}, {
duration: 800
});
}
if (tomatoAsset) {
tween(tomatoAsset, {
alpha: 0
}, {
duration: 800
});
}
if (introSickle) {
tween(introSickle, {
alpha: 0
}, {
duration: 800
});
}
// Fade in start text only - startButtonBg is removed
tween(startText, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// No need to pulse since startButtonBg is removed
}
});
}, 9500);
};
// Pulse animation for start button (modified to check if element exists)
self.startPulse = function () {
// Just pulse the start text since background is removed
tween(startText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startText, {
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: self.startPulse
});
}
});
};
// Handle intro screen tap to start the game
self.down = function (x, y, obj) {
// Prevent multiple taps
if (self._startingGame) {
return;
}
self._startingGame = true;
// Play tap animation for text instead
tween(startText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Transition to yellow background
tween(sunriseBackground, {
alpha: 1,
tint: 0xf8e9c0
}, {
duration: 800,
easing: tween.easeOut
});
// Fade out all elements
if (titleText) {
tween(titleText, {
alpha: 0
}, {
duration: 600
});
}
if (subtitleText) {
tween(subtitleText, {
alpha: 0
}, {
duration: 600
});
}
tween(startText, {
alpha: 0
}, {
duration: 600
});
for (var i = 0; i < introClouds.length; i++) {
tween(introClouds[i], {
alpha: 0
}, {
duration: 600
});
}
// Fade out entire intro screen with delay
LK.setTimeout(function () {
tween(self, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
// Start/enable actual game
startActualGame();
}
});
}, 800);
}
});
return true; // Prevent event bubbling
};
return self;
});
// Rooster class with 4-frame animation cycling smoothly
var Rooster = Container.expand(function () {
var self = Container.call(this);
// Animation frame asset ids
var frameIds = ['rooster_1', 'rooster_2', 'rooster_3', 'rooster_4'];
self.roosterFrames = [];
self.currentFrame = 0;
self.frameTimer = 0;
self.frameInterval = 10; // ~0.16s per frame at 60fps (smooth)
// Attach all frames, only show the first
for (var i = 0; i < frameIds.length; ++i) {
var frame = self.attachAsset(frameIds[i], {
anchorX: 0.5,
anchorY: 0.5,
alpha: i === 0 ? 1 : 0
});
self.roosterFrames.push(frame);
}
// Animation update
self.update = function () {
self.frameTimer++;
if (self.frameTimer >= self.frameInterval) {
// Hide current frame
self.roosterFrames[self.currentFrame].alpha = 0;
// Advance to next frame
self.currentFrame = (self.currentFrame + 1) % self.roosterFrames.length;
// Show new frame
self.roosterFrames[self.currentFrame].alpha = 1;
self.frameTimer = 0;
}
};
return self;
});
// TomatoSlot class for area 3
var TomatoSlot = Container.expand(function () {
var self = Container.call(this);
self.slotAsset = self.attachAsset('tomato', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 2; // Area 3
self.regrowing = false;
// Show/hide tomato and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide tomato with animation
tween(self.slotAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
// Show sprout with animation
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show tomato with animation
tween(self.slotAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Hide sprout with animation
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to tomato size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to tomato and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
// Wheat class
var Wheat = Container.expand(function () {
var self = Container.call(this);
self.vegAssetId = 'wheat';
self.wheatAsset = self.attachAsset('wheat', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 0; // which field this wheat belongs to
self.regrowing = false;
self.removeAfter = 0;
// Change vegetable asset if needed
self.setVegAsset = function (assetId) {
if (self.wheatAsset) {
self.wheatAsset.destroy();
}
self.vegAssetId = assetId || 'wheat';
// Only allow wheat, carrot, tomato, eggplant
var validAssets = {
wheat: 1,
carrot: 1,
tomato: 1,
eggplant: 1
};
if (!validAssets[self.vegAssetId]) {
self.vegAssetId = 'wheat';
}
self.wheatAsset = self.attachAsset(self.vegAssetId, {
anchorX: 0.5,
anchorY: 1
});
// Make sure sprout is on top
self.removeChild(sproutAsset);
self.addChild(sproutAsset);
};
// Show/hide wheat and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide wheat, show sprout
if (self.wheatAsset) {
// Animate wheat harvesting with tween
tween(self.wheatAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
}
// Show and animate sprout growing from nothing
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show wheat/veg, hide sprout with animation
if (self.wheatAsset) {
tween(self.wheatAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
// Fade out sprout
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic and removal after 5 seconds
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to wheat/veg size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to wheat/veg and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
// Create the zombie frames (two different assets)
var zombieFrame1 = self.attachAsset('zombie_1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
var zombieFrame2 = self.attachAsset('zombie_2', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Animation variables
self.currentFrame = 0;
self.frameTimer = 0;
self.frameInterval = 15; // Frame switch interval
self.speed = 2; // Movement speed
self.lastX = 0; // Track previous X for collision detection
self.lastY = 0; // Track previous Y for collision detection
self.lastWasIntersecting = false; // Track previous intersection state
self.isDead = false; // Track if zombie is dead
// Handle click/tap on zombie
self.down = function (x, y, obj) {
// Mark zombie as clicked and initiate death sequence
if (!self.isDead) {
self.isDead = true;
// Flash zombie yellow to indicate hit
LK.effects.flashObject(self, 0xFFFF00, 300);
// Death animation - fade out and scale down
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove zombie from game
self.destroy();
// Create new zombie after a 40s delay
LK.setTimeout(createZombie, 40000);
}
});
// Prevent event from bubbling to game (stop farmer movement)
return true;
}
};
// Zombie animation and movement
self.update = function () {
// Don't update if dead
if (self.isDead) {
return;
}
// Save previous position for collision detection
self.lastX = self.x;
self.lastY = self.y;
// Frame animation
self.frameTimer++;
if (self.frameTimer >= self.frameInterval) {
// Toggle between frames
self.currentFrame = self.currentFrame === 0 ? 1 : 0;
// Show current frame
zombieFrame1.alpha = self.currentFrame === 0 ? 1 : 0;
zombieFrame2.alpha = self.currentFrame === 1 ? 1 : 0;
self.frameTimer = 0;
}
// Move zombie toward the farmer
if (farmer) {
var dx = farmer.x - self.x;
var dy = farmer.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > self.speed) {
self.x += self.speed * dx / dist;
self.y += self.speed * dy / dist;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4caf50 // Grass green
});
/****
* Game Code
****/
// Area 4
// Area 3
// Area 2
// Lock icon (ellipse, gray)
// Sickle (ellipse, yellow)
// House (box)
// Farmer (box)
// Wheat (ellipse)
// Field fence (rectangle)
// --- Game constants ---
// Rooster animation frames (replace id values with your own image ids)
var FIELD_W = 900;
var FIELD_H = 900;
var FIELD_GAP = 120; // Increased gap to move fences further from center
var FIELD_COUNT = 4;
var WHEAT_PER_FIELD = 10;
// Area unlock prices and reward multipliers
var FIELD_LOCK_COSTS = [0, 20000, 40000, 60000]; // Area 1 open, others locked
var FIELD_REWARD_MULT = [1, 2, 3, 4]; // Area 1=1x, 2=2x, 3=3x, 4=4x
// --- Area constants ---
// Define the distance from center for all areas (equal distance)
var AREA_DISTANCE = 600;
// Create an array to hold the areas
var areas = [];
var animals = [];
// --- Game state ---
var fields = [];
var farmer = null;
var money = 0;
var moneyTxt = null;
var sickle = null;
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var unlockFieldIndex = -1;
var playerMovementBlockedByUIClick = false; // Flag to indicate UI handled the click
// --- Layout calculation ---
// Fields: 2x2 grid, with house in center
// [0][1]
// [2][3]
var fieldPositions = [{
x: 0,
y: 0
},
// top-left
{
x: FIELD_W + FIELD_GAP,
y: 0
},
// top-right
{
x: 0,
y: FIELD_H + FIELD_GAP
},
// bottom-left
{
x: FIELD_W + FIELD_GAP,
y: FIELD_H + FIELD_GAP
} // bottom-right
];
// Center everything in game area
var totalW = FIELD_W * 2 + FIELD_GAP;
var totalH = FIELD_H * 2 + FIELD_GAP;
var offsetX = Math.floor((2048 - totalW) / 2);
var offsetY = Math.floor((2732 - totalH) / 2);
// --- Setup actual game start function ---
var gameInitialized = false;
var introScreen = null;
function initializeGameElements() {
if (gameInitialized) {
return;
}
// --- Create fields ---
for (var i = 0; i < FIELD_COUNT; ++i) {
var f = new Field();
f.index = i;
f.locked = FIELD_LOCK_COSTS[i] > 0;
f.lockCost = FIELD_LOCK_COSTS[i];
var pos = fieldPositions[i];
var fx = offsetX + pos.x;
var fy = offsetY + pos.y;
// Skip drawing fences
f.placeWheats(fx, fy, FIELD_W, FIELD_H, WHEAT_PER_FIELD);
if (f.locked) {
// Center of field
f.showLock(fx + FIELD_W / 2, fy + FIELD_H / 2);
}
game.addChild(f);
fields.push(f);
}
gameInitialized = true;
}
function startActualGame() {
// The assets should already be loaded due to the optimized intro loading process
// Initialize game elements if not already done
initializeGameElements();
// Set game elements active
game.gameActive = true;
// Play background music
LK.playMusic('backgroundMusic', {
loop: true
});
// Start game timers and events
createClouds();
LK.setTimeout(createBird, 60000);
spawnRooster();
LK.setTimeout(createZombie, 40000);
}
// Create intro screen with enhanced animations
introScreen = new IntroScreen();
game.addChild(introScreen);
// Set game to inactive until intro completes
game.gameActive = false;
// Start intro animation sequence
introScreen.startAnimation();
// Don't initialize game elements yet - wait for intro to complete
// They will be created when the player taps the start button
// Center reference point for positions
var centerX = offsetX + FIELD_W;
var centerY = offsetY + FIELD_H - 250;
// --- Create farmer ---
farmer = new Farmer();
farmer.x = centerX;
farmer.y = centerY - 120; // Start at center area
game.addChild(farmer);
// --- Create sickle (attached to farmer's hand) ---
sickle = LK.getAsset('sickle', {
anchorX: 0.2,
// hand position, left side of ellipse
anchorY: 0.7,
// slightly below center
x: 0,
y: 30
});
sickle.alpha = 1;
// --- Money display ---
moneyTxt = new Text2('$0', {
size: 100,
fill: "#fff"
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
// Buttons removed to simplify the game interface
// --- Missions UI ---
// "Missions" title
var missionsTitle = new Text2('Missions', {
size: 90,
fill: "#fff"
});
missionsTitle.anchor.set(0, 0); // Left align, top
// Place on the left side of the center part of the screen
var missionAreaX = 180; // 180px from left edge, safe from menu
var missionAreaY = 120; // Below top menu area
missionsTitle.x = missionAreaX;
missionsTitle.y = missionAreaY;
game.addChild(missionsTitle);
// Mission bar background (smaller, left side)
var missionBarBg = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0,
x: missionAreaX,
y: missionsTitle.y + missionsTitle.height + 18,
scaleX: 2.2,
scaleY: 0.5,
alpha: 0.25
});
game.addChild(missionBarBg);
// Mission bar fill (progress)
var missionBarFill = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0,
x: missionAreaX,
y: missionsTitle.y + missionsTitle.height + 18,
scaleX: 0,
// Will be set dynamically
scaleY: 0.5,
tint: 0xFFD700,
// Gold color
alpha: 0.85
});
game.addChild(missionBarFill);
// Mission text
var missionText = new Text2('Reach $100,000', {
size: 60,
fill: "#fff"
});
missionText.anchor.set(0, 0);
missionText.x = missionAreaX + 10;
missionText.y = missionBarBg.y + missionBarBg.height + 8;
game.addChild(missionText);
// Store for update
var missionBarMaxWidth = 200; // px, visually (not used, but kept for reference)
var missionBarFillMaxScale = 2.2;
// --- Helper: update money display ---
function updateMoneyDisplay() {
moneyTxt.setText('$' + money);
// --- Missions progress update ---
if (typeof missionBarFill !== "undefined") {
// Clamp progress between 0 and 1
var progress = Math.max(0, Math.min(1, money / 100000));
missionBarFill.scaleX = missionBarFillMaxScale * progress;
}
// --- Mission complete: You Win! ---
if (money >= 100000 && !game._missionWinShown) {
game._missionWinShown = true;
LK.showYouWin();
}
}
// --- Helper: unlock field if enough money ---
function tryUnlockField(fieldIdx) {
var f = fields[fieldIdx];
if (!f.locked) {
return;
}
if (money >= f.lockCost) {
money -= f.lockCost;
updateMoneyDisplay();
f.locked = false;
f.hideLock();
// Flash field green
for (var i = 0; i < f.fenceNodes.length; ++i) {
LK.effects.flashObject(f.fenceNodes[i], 0x00ff00, 600);
}
} else {
// Not enough money, flash red
LK.effects.flashScreen(0xff0000, 400);
}
}
// --- Touch/mouse handling ---
var lastDownX = 0,
lastDownY = 0;
var harvestMode = false;
var harvestWheat = null;
// Helper: find harvestable vegetable under (x, y) in unlocked fields
function findHarvestableWheat(x, y) {
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
if (f.locked) {
continue;
}
for (var j = 0; j < f.wheats.length; ++j) {
var w = f.wheats[j];
if (w.isHarvestable()) {
// Use bounding box for hit
var wx = w.x,
wy = w.y;
var ww = 60,
wh = 80;
if (x >= wx - ww / 2 && x <= wx + ww / 2 && y >= wy - wh && y <= wy) {
return w;
}
}
}
}
return null;
}
// Helper: find locked field under (x, y)
function findLockedField(x, y) {
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
if (!f.locked) {
continue;
}
// Use field area
var pos = fieldPositions[i];
var fx = offsetX + pos.x;
var fy = offsetY + pos.y;
if (x >= fx && x <= fx + FIELD_W && y >= fy && y <= fy + FIELD_H) {
return i;
}
}
return -1;
}
// --- Game event handlers ---
// Move farmer or harvest wheat
game.down = function (x, y, obj) {
// Don't process game inputs if game is not active yet
if (!game.gameActive) {
return;
}
// Shop system completely removed
// No shopButton references needed anymore
// Continue with normal game control flow
// No shop button checks needed
//
lastDownX = x;
lastDownY = y;
// Check if tapping on locked field unlock button
var lockedIdx = findLockedField(x, y);
if (lockedIdx >= 0) {
var f = fields[lockedIdx];
// If tap is near lock icon or unlock text
var centerX = offsetX + fieldPositions[lockedIdx].x + FIELD_W / 2;
var centerY = offsetY + fieldPositions[lockedIdx].y + FIELD_H / 2;
var dist = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
if (dist < 120) {
tryUnlockField(lockedIdx);
return;
}
}
// Check for wheat
var w = findHarvestableWheat(x, y);
if (w) {
harvestMode = true;
harvestWheat = w;
// Change player to face forward during harvest
// Switch to player_down for harvesting
if (farmer.currentAsset) {
farmer.currentAsset.alpha = 0;
}
var playerDown = LK.getAsset('player_down', {
anchorX: 0.5,
anchorY: 0.5
});
playerDown.alpha = 1;
farmer.addChild(playerDown);
farmer.currentAsset = playerDown;
// Trigger sickle attack animation
farmer.attack();
// Show harvest animation effect
var harvestEffect = LK.getAsset('sprout', {
anchorX: 0.5,
anchorY: 0.5,
x: w.x,
y: w.y - 50,
alpha: 0.8,
scaleX: 2,
scaleY: 2
});
game.addChild(harvestEffect);
// Animate the harvest effect
tween(harvestEffect, {
alpha: 0,
y: harvestEffect.y - 100
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
harvestEffect.destroy();
}
});
// Harvest
w.setHarvested(true);
var reward = 100 * (FIELD_REWARD_MULT[w.fieldIndex] || 1);
money += reward;
updateMoneyDisplay();
// Flash wheat
LK.effects.flashObject(w, 0xffff00, 300);
// No setHarvested(false) here; regrow/removal handled in Wheat.update
harvestMode = false;
harvestWheat = null;
return;
}
// Move farmer with animation
farmer.moveTo(x, y);
dragging = true;
dragOffsetX = x - farmer.x;
dragOffsetY = y - farmer.y;
};
// Drag farmer
game.move = function (x, y, obj) {
// Don't process game inputs if game is not active yet
if (!game.gameActive) {
return;
}
// Shop system completely removed
//
if (dragging) {
farmer.moveTo(x - dragOffsetX, y - dragOffsetY);
}
if (harvestMode && harvestWheat) {
sickle.x = x;
sickle.y = y;
}
};
// End drag/harvest
game.up = function (x, y, obj) {
// Don't process game inputs if game is not active yet
if (!game.gameActive) {
return;
}
// Shop system completely removed
//
//
dragging = false;
harvestMode = false;
harvestWheat = null;
};
// --- Main update loop ---
// Defensive: If game is reset, clear win timer
game.update = function () {
// Only update game elements if game is active (after intro)
if (!game.gameActive) {
// If there's an intro screen, allow it to animate even while game is inactive
if (introScreen && introScreen.parent) {
// Still allow intro screen animations to update
if (introScreen.updateLoadingText && !introScreen.assetsLoaded) {
// Loading animation is handled by setTimeout
}
}
return;
}
// Update farmer if initialized
if (farmer) {
farmer.update();
}
// Update wheat regrow
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
f.wheats.forEach(function (wheat) {
wheat.update();
});
}
// Update clouds
for (var i = 0; i < clouds.length; i++) {
clouds[i].update();
}
// Update birds
for (var i = 0; i < birds.length; i++) {
birds[i].update();
}
};
// --- Create areas and place animals ---
// Calculate center of game screen
var gameWidth = 2048;
var gameHeight = 2732;
var gameCenterX = gameWidth / 2;
var gameCenterY = gameHeight / 2;
// Create the four areas at equal distances from center
// Area_Left
var areaLeft = new Container();
areaLeft.x = gameCenterX - AREA_DISTANCE;
areaLeft.y = gameCenterY;
areaLeft.name = "Area_Left";
game.addChild(areaLeft);
areas.push(areaLeft);
// Area_Right
var areaRight = new Container();
areaRight.x = gameCenterX + AREA_DISTANCE;
areaRight.y = gameCenterY;
areaRight.name = "Area_Right";
game.addChild(areaRight);
areas.push(areaRight);
// Area_Top
var areaTop = new Container();
areaTop.x = gameCenterX;
areaTop.y = gameCenterY - AREA_DISTANCE;
areaTop.name = "Area_Top";
game.addChild(areaTop);
areas.push(areaTop);
// Area_Bottom
var areaBottom = new Container();
areaBottom.x = gameCenterX;
areaBottom.y = gameCenterY + AREA_DISTANCE;
areaBottom.name = "Area_Bottom";
game.addChild(areaBottom);
areas.push(areaBottom);
// Place animals in the areas
// Animal_Right at bottom right of screen
var animalRight = new Animal();
animalRight.setAnimalImage('animal_right');
animalRight.name = "Animal_Right";
// Place at bottom right, accounting for anchor (0.5, 0.5) and asset size
var animalRightAsset = LK.getAsset('animal_right', {
anchorX: 0.5,
anchorY: 0.5
});
animalRight.x = gameWidth - animalRightAsset.width / 2 - 10; // 10px padding from right
animalRight.y = gameHeight - animalRightAsset.height / 2 - 10; // 10px padding from bottom
game.addChild(animalRight);
animals.push(animalRight);
// Area_Bottom has no animal
// --- Create clouds ---
var clouds = [];
// Create two clouds at different positions
function createClouds() {
// Remove any existing clouds
for (var i = 0; i < clouds.length; i++) {
clouds[i].destroy();
}
clouds = [];
// Cloud width for calculations
var cloudWidth = 500;
// Create first cloud (front layer)
var cloud1 = new Cloud();
cloud1.x = -cloudWidth / 2; // Start from off-screen left
cloud1.y = 180; // Higher position near the top
cloud1.layer = 0; // Front layer - this will be in front
cloud1.init(); // Initialize movement and timing
game.addChild(cloud1);
clouds.push(cloud1);
// Create second cloud (back layer)
var cloud2 = new Cloud();
cloud2.x = -cloudWidth / 2 - 200; // Start more separated from first cloud
cloud2.y = 280; // Position below first cloud with more separation
cloud2.layer = 1; // Back layer - this will be behind
cloud2.init(); // Initialize movement and timing
game.addChild(cloud2);
clouds.push(cloud2);
// Schedule creation of new clouds after these disappear
LK.setTimeout(createClouds, 61000); // 61 seconds to ensure smooth transition
}
// Start creating clouds
createClouds();
// Shop system completely removed
// --- Create zombie ---
var zombie = null;
var zombieDamageTimer = 0; // Timer to prevent continuous damage
var zombieDamageAmount = 500; // Initial zombie damage/cost
var zombieAppearCount = 0; // How many times zombie has appeared
// --- Create birds ---
var birds = [];
// Create a bird that starts at the top, flies across, disappears, and restarts in a loop
function createBird() {
// Remove any existing birds that might be stuck
for (var i = 0; i < birds.length; i++) {
birds[i].destroy();
}
birds = [];
// Bird asset for size
var tempBirdAsset = LK.getAsset('Bird', {
anchorX: 0.5,
anchorY: 0.5
});
var birdWidth = tempBirdAsset.width;
var birdHeight = tempBirdAsset.height;
// Start at the top of the screen, just off the left edge
var bird = new Bird();
bird.x = -birdWidth / 2;
bird.y = birdHeight / 2 + 20; // 20px padding from the very top
bird.init();
game.addChild(bird);
birds.push(bird);
// Set up a watcher to restart the bird after 60 seconds (3600 ticks at 60fps)
bird._birdLoopCheck = function () {
// Only restart if bird is gone (destroyed)
if (!bird.parent) {
LK.setTimeout(createBird, 60000); // 60 seconds delay before next bird
} else {
LK.setTimeout(bird._birdLoopCheck, 200); // Check again in 200ms
}
};
LK.setTimeout(bird._birdLoopCheck, 200);
}
// Start creating birds after 1 minute (60000 ms)
LK.setTimeout(createBird, 60000);
// Background music will be played when the game starts after the intro sequence completes
// Music playback is now handled in startActualGame()
// --- Initial money display ---
updateMoneyDisplay();
// --- Place trees at corners ---
// Tree size
var treeWidth = 400;
var treeHeight = 532;
// Top left corner tree
var topLeftTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: offsetX / 2,
y: offsetY / 2
});
game.addChild(topLeftTree);
// Top right corner tree
var topRightTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - offsetX / 2,
y: offsetY / 2
});
game.addChild(topRightTree);
// Bottom left corner tree
var bottomLeftTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: offsetX / 2,
y: 2732 - offsetY / 2
});
game.addChild(bottomLeftTree);
// Bottom right corner tree
var bottomRightTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - offsetX / 2,
y: 2732 - offsetY / 2
});
game.addChild(bottomRightTree);
// --- Place trees at middle sides aligned with corner trees ---
// Tree to the left of center
var leftCenterTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: offsetX / 2,
y: topRightTree.y
});
game.addChild(leftCenterTree);
// Tree to the right of center
var rightCenterTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - offsetX / 2,
y: topRightTree.y
});
game.addChild(rightCenterTree);
// --- Add Rooster that moves left-to-right, disappears at right edge, reappears after 40s and repeats ---
var rooster = null;
var roosterTimeout = null;
function spawnRooster() {
// Remove any existing rooster
if (rooster && rooster.parent) {
rooster.destroy();
}
rooster = new Rooster();
// Start at the left center of the screen
rooster.y = 2732 / 2;
rooster.x = rooster.roosterFrames[0].width / 2 + 10;
game.addChild(rooster);
// Rooster path: left-to-right, horizontally centered
var roosterStartX = rooster.roosterFrames[0].width / 2 + 10;
var roosterEndX = 2048 - rooster.roosterFrames[0].width / 2 - 10;
var roosterSpeed = 1; // px per frame, very slow movement
rooster.targetX = roosterEndX;
rooster.direction = 1; // 1: moving right
rooster.updateRoosterMovement = function () {
// Track lastX for edge detection
if (typeof rooster.lastX === "undefined") {
rooster.lastX = rooster.x;
}
// Move only horizontally in the center
var dx = rooster.targetX - rooster.x;
var dist = Math.abs(dx);
if (dist < roosterSpeed) {
rooster.x = rooster.targetX;
} else {
rooster.x += roosterSpeed * (dx > 0 ? 1 : -1);
}
// Call animation update
if (typeof rooster.update === "function") {
rooster.update();
}
// Check if rooster just reached the right edge (disappear trigger)
if (rooster.lastX < roosterEndX && rooster.x >= roosterEndX) {
// Fade out and destroy, then respawn after 40s
tween(rooster, {
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
if (rooster && rooster.parent) {
rooster.destroy();
}
roosterTimeout = LK.setTimeout(spawnRooster, 40000); // 40 seconds
}
});
}
// Update lastX for next frame
rooster.lastX = rooster.x;
};
}
// Add rooster update to main game loop
var oldGameUpdate = game.update;
game.update = function () {
if (typeof oldGameUpdate === "function") {
oldGameUpdate();
}
if (rooster && rooster.parent && typeof rooster.updateRoosterMovement === "function") {
rooster.updateRoosterMovement();
}
// Update zombie
if (zombie && zombie.parent) {
zombie.update();
// Collision detection with player (only triggers on state change)
var isIntersecting = zombie.intersects(farmer);
// Check if we just started intersecting
if (!zombie.lastWasIntersecting && isIntersecting && zombieDamageTimer <= 0) {
// Zombie just touched the player, deduct gold
money = Math.max(0, money - zombieDamageAmount);
updateMoneyDisplay();
// Flash both zombie and farmer red
LK.effects.flashObject(zombie, 0xff0000, 500);
LK.effects.flashObject(farmer, 0xff0000, 500);
// Set cooldown timer to prevent continuous damage (3 second cooldown)
zombieDamageTimer = 180;
}
// Update intersection state
zombie.lastWasIntersecting = isIntersecting;
// Update damage cooldown timer
if (zombieDamageTimer > 0) {
zombieDamageTimer--;
}
}
};
// Create the zombie
function createZombie() {
// Remove existing zombie if it exists
if (zombie && zombie.parent) {
zombie.destroy();
}
// Create new zombie
zombie = new Zombie();
// Position zombie off-screen to the left
zombie.x = -100;
zombie.y = 2732 / 2;
// Initialize tracking variables
zombie.lastX = zombie.x;
zombie.lastY = zombie.y;
zombie.lastWasIntersecting = false;
game.addChild(zombie);
// Increase zombie damage each time it spawns
zombieAppearCount++;
if (zombieAppearCount === 1) {
zombieDamageAmount = 500;
} else {
zombieDamageAmount = zombieDamageAmount * 2;
}
}
// Start the first rooster and create zombie
spawnRooster();
// Delay the first zombie spawn by 40 seconds after game start
LK.setTimeout(createZombie, 40000); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Removed plugin import to fix 'Unable to load plugins' error
var Animal = Container.expand(function () {
var self = Container.call(this);
self.animalAsset = null;
self.setAnimalImage = function (imageId) {
if (self.animalAsset) {
self.animalAsset.destroy();
}
self.animalAsset = self.attachAsset(imageId, {
anchorX: 0.5,
anchorY: 0.5
});
};
return self;
});
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
// Create the bird asset
var birdAsset = self.attachAsset('Bird', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1,
scaleX: 0.8,
scaleY: 0.8
});
// Variables for movement
self.speed = 1.0; // Faster than clouds
self.lifeTime = 3000; // 50 seconds at 60fps
self.lifeCounter = 0; // Track how long bird has been visible
self.flyHeight = 0; // Vertical position offset for flying pattern
// Initialize bird
self.init = function () {
self.lifeCounter = 0;
self.alpha = 1;
// Start movement animation using tween
self.startMoving();
};
// Start the left to right movement with slight up/down wave pattern
self.startMoving = function () {
// Move bird to the right side of screen
var targetX = 2048 + birdAsset.width / 2; // Move past right edge
// Create the movement tween
tween(self, {
x: targetX
}, {
duration: 20000,
// Faster than clouds - 20 seconds to cross screen
easing: tween.linear
});
};
// Update function called every frame
self.update = function () {
// Increment life counter
self.lifeCounter++;
// Create a small wavy flight pattern
self.y = self.y + Math.sin(self.lifeCounter * 0.03) * 1.5;
// If bird has reached the right edge of the screen
if (self.x >= 2048 + birdAsset.width / 2) {
// Stop any existing tweens on this bird
tween.stop(self);
// Fade out animation
tween(self, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove bird from game
self.destroy();
}
});
}
};
return self;
});
// CarrotSlot class for area 2
var CarrotSlot = Container.expand(function () {
var self = Container.call(this);
self.slotAsset = self.attachAsset('carrot', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 1; // Area 2
self.regrowing = false;
// Show/hide carrot and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide carrot with animation
tween(self.slotAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
// Show sprout with animation
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show carrot with animation
tween(self.slotAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Hide sprout with animation
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to carrot size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to carrot and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
// Cloud class
var Cloud = Container.expand(function () {
var self = Container.call(this);
// Create the cloud asset
var cloudAsset = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8 // Semi-transparent clouds
});
// Variables for movement
self.speed = 0.2; // Very slow speed for smooth movement
self.lifeTime = 6000; // 100 seconds at 60fps - longer lifetime
self.lifeCounter = 0; // Track how long cloud has been visible
self.layer = 0; // Layer for visual depth (0 = front, 1 = back)
// Initialize cloud
self.init = function () {
self.lifeCounter = 0;
self.alpha = 1;
// Apply layer-specific settings
if (self.layer === 1) {
// Back layer cloud (slightly smaller and more transparent)
self.scale.set(0.8, 0.8);
self.alpha = 0.7;
}
// Start movement animation using tween
self.startMoving();
};
// Start the left to right movement only
self.startMoving = function () {
// Move cloud to the right side of screen
var targetX = 2048 + cloudAsset.width / 2; // Move past right edge
// Create the movement tween
tween(self, {
x: targetX
}, {
duration: 60000,
// Slower movement - 60 seconds to cross screen
easing: tween.linear
});
};
// Update function called every frame
self.update = function () {
// Increment life counter
self.lifeCounter++;
// Track lastX for edge detection
if (typeof self.lastX === "undefined") {
self.lastX = self.x;
}
// If cloud has just reached the right edge of the screen (crossed this frame)
if (self.lastX < 2048 + cloudAsset.width / 2 && self.x >= 2048 + cloudAsset.width / 2) {
// Stop any existing tweens on this cloud
tween.stop(self);
// Fade out animation
tween(self, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove cloud from game
self.destroy();
}
});
}
// Update lastX for next frame
self.lastX = self.x;
};
return self;
});
// EggplantSlot class for area 4
var EggplantSlot = Container.expand(function () {
var self = Container.call(this);
self.slotAsset = self.attachAsset('eggplant', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 3; // Area 4
self.regrowing = false;
// Show/hide eggplant and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide eggplant with animation
tween(self.slotAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
// Show sprout with animation
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show eggplant with animation
tween(self.slotAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Hide sprout with animation
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to eggplant size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to eggplant and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
// Farmer class
var Farmer = Container.expand(function () {
var self = Container.call(this);
// Create animation frames
var idleFrame = self.attachAsset('farmer', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
// Frame 2 (running)
var runningFrame = self.attachAsset('farmer_walk', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Frame 3 (right step)
var rightStepFrame = self.attachAsset('farmer_walk', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
rotation: 0.1
});
self.speed = 18; // px per move
self.targetX = self.x;
self.targetY = self.y;
self.moving = false;
self.lastMoving = false;
self.animationTimer = 0;
self.animationFrame = 0;
self.frameTime = 18; // 0.3 seconds at 60fps
// Animation frame switching
self.switchToFrame = function (frameNum) {
idleFrame.alpha = 0;
runningFrame.alpha = 0;
rightStepFrame.alpha = 0;
if (frameNum === 0) {
// Idle
idleFrame.alpha = 1;
} else if (frameNum === 1) {
// Running
runningFrame.alpha = 1;
} else if (frameNum === 2) {
// Right step
rightStepFrame.alpha = 1;
}
};
// Move farmer towards target
self.update = function () {
// Track movement direction and update image
if (self.moving) {
var dx = self.targetX - self.x;
// Check if moving right or left
if (dx > 0) {
// Moving right - use player_right asset
idleFrame.scaleX = 1;
runningFrame.scaleX = 1;
rightStepFrame.scaleX = 1;
// Switch to player_right image
if (self.currentAsset !== idleFrame || idleFrame.texture !== LK.getAsset('player_right', {}).texture) {
if (self.currentAsset) {
self.currentAsset.alpha = 0;
}
var rightAsset = LK.getAsset('player_right', {
anchorX: 0.5,
anchorY: 0.5
});
rightAsset.alpha = 1;
self.addChild(rightAsset);
self.currentAsset = rightAsset;
}
} else if (dx < 0) {
// Moving left - use player_left asset
idleFrame.scaleX = -1;
runningFrame.scaleX = -1;
rightStepFrame.scaleX = -1;
// Switch to player_left image
if (self.currentAsset !== idleFrame || idleFrame.texture !== LK.getAsset('player_left', {}).texture) {
if (self.currentAsset) {
self.currentAsset.alpha = 0;
}
var leftAsset = LK.getAsset('player_left', {
anchorX: 0.5,
anchorY: 0.5
});
leftAsset.alpha = 1;
self.addChild(leftAsset);
self.currentAsset = leftAsset;
}
}
// Animation handling
self.animationTimer++;
if (self.animationTimer >= self.frameTime) {
self.animationTimer = 0;
self.animationFrame = self.animationFrame === 1 ? 2 : 1; // Toggle between frames 1 and 2
self.switchToFrame(self.animationFrame);
}
} else if (!self.moving && self.lastMoving) {
// Just stopped moving - switch to idle
self.switchToFrame(0);
}
self.lastMoving = self.moving;
if (!self.moving) {
return;
}
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.speed) {
self.x = self.targetX;
self.y = self.targetY;
self.moving = false;
// Switch to idle frame when stopping
self.switchToFrame(0);
} else {
self.x += self.speed * dx / dist;
self.y += self.speed * dy / dist;
}
};
// Set movement target
self.moveTo = function (x, y) {
self.targetX = x;
self.targetY = y;
// Start movement
if (!self.moving) {
self.moving = true;
self.animationFrame = 1;
self.animationTimer = 0;
self.switchToFrame(self.animationFrame);
}
};
// Attach sickle to farmer's hand
var sickle = self.attachAsset('sickle', {
anchorX: 0.2,
// hand position, left side of ellipse
anchorY: 0.7,
// slightly below center
x: 0,
y: 30
});
sickle.alpha = 1;
// Add attack animation for sickle
self.attack = function () {
tween(sickle, {
rotation: Math.PI * 2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
sickle.rotation = 0;
}
});
};
return self;
});
// Field class
var Field = Container.expand(function () {
var self = Container.call(this);
self.index = 0; // 0-3
self.locked = false;
self.lockCost = 0;
self.lockNode = null;
self.fenceNodes = [];
self.wheats = [];
self.unlockBtn = null;
// Draw fences - Empty implementation to eliminate fences
self.drawFences = function (x, y, w, h) {
self.fenceNodes = [];
// No fences or gates are created
};
// Place wheat
self.placeWheats = function (x, y, w, h, count) {
self.wheats = [];
// Define grid size
var rows = 5;
var cols = 10;
// Choose vegetable asset per area
var vegAssetId = 'wheat';
if (self.index === 1) {
vegAssetId = 'carrot';
}
if (self.index === 2) {
vegAssetId = 'tomato';
}
if (self.index === 3) {
vegAssetId = 'eggplant';
}
// Fallback if asset not found, use wheat
if (!LK.assets || !LK.assets[vegAssetId]) {
vegAssetId = 'wheat';
}
// Calculate asset size for spacing (use wheat size as reference for all)
var vegAsset = LK.getAsset('wheat', {
anchorX: 0.5,
anchorY: 1
});
var wheatW = vegAsset.width;
var wheatH = vegAsset.height;
// Padding from fences
var padX = 60;
var padY = 60;
// Compute available area for wheat grid
var gridW = w - 2 * padX;
var gridH = h - 2 * padY;
// Compute spacing between wheat plants
var spacingX = (gridW - wheatW) / (cols - 1);
var spacingY = (gridH - wheatH) / (rows - 1);
// Place appropriate vegetable in grid based on field index
for (var row = 0; row < rows; ++row) {
for (var col = 0; col < cols; ++col) {
var wx = x + padX + col * spacingX + wheatW / 2;
var wy = y + padY + row * spacingY + wheatH;
var veg;
// Create appropriate vegetable based on area/field index
if (self.index === 1) {
veg = new CarrotSlot();
} else if (self.index === 2) {
veg = new TomatoSlot();
} else if (self.index === 3) {
veg = new EggplantSlot();
} else {
veg = new Wheat();
veg.fieldIndex = self.index;
veg.vegAssetId = vegAssetId;
veg.setVegAsset && veg.setVegAsset(vegAssetId);
}
veg.x = wx;
veg.y = wy;
self.addChild(veg);
self.wheats.push(veg);
}
}
};
// Lock overlay
self.showLock = function (centerX, centerY) {
if (self.lockNode) {
return;
}
self.lockNode = LK.getAsset('lock', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX,
y: centerY
});
self.addChild(self.lockNode);
// Unlock text
var unlockTxt = new Text2('Unlock\n$' + self.lockCost, {
size: 60,
fill: "#fff"
});
unlockTxt.anchor.set(0.5, 0.5);
unlockTxt.x = centerX;
unlockTxt.y = centerY + 70;
self.unlockBtn = unlockTxt;
self.addChild(unlockTxt);
};
self.hideLock = function () {
if (self.lockNode) {
self.lockNode.destroy();
self.lockNode = null;
}
if (self.unlockBtn) {
self.unlockBtn.destroy();
self.unlockBtn = null;
}
};
return self;
});
// Zombie respawn is now handled after being killed by the player;
// IntroScreen class for game intro animation with improved loading
var IntroScreen = Container.expand(function () {
var self = Container.call(this);
// Track loading state
self.loadingPhase = 0; // 0=Loading core, 1=Loading intro, 2=Loading game assets, 3=Complete
self.animationStarted = false;
self.introAssetsLoaded = false;
self.gameAssetsLoaded = false;
// Create a dark overlay as background
var overlay = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0,
scaleX: 30,
scaleY: 40,
alpha: 1,
tint: 0x000000
});
self.addChild(overlay);
// Loading text
var loadingText = new Text2('Loading Core Assets...', {
size: 120,
fill: 0xFFFFFF
});
loadingText.anchor.set(0.5, 0.5);
loadingText.x = 2048 / 2;
loadingText.y = 2732 / 2;
self.addChild(loadingText);
// Animation references
var sunriseBackground = null;
var introClouds = [];
var maleFarmer = null;
var femaleFarmer = null;
var sproutAsset = null;
var wheatAsset = null;
var carrotAsset = null;
var tomatoAsset = null;
var titleText = null;
var subtitleText = null;
var introZombie = null;
var introSickle = null;
var startButtonBg = null;
var startText = null;
// Loading dots animation
self.updateLoadingText = function () {
if (self.loadingPhase >= 3) {
return;
}
var dots = '';
if (loadingText && loadingText.text) {
var baseTxt = '';
if (self.loadingPhase === 0) {
baseTxt = 'Loading Core Assets';
} else if (self.loadingPhase === 1) {
baseTxt = 'Loading Intro Assets';
} else if (self.loadingPhase === 2) {
baseTxt = 'Loading Game Assets';
}
if (loadingText.text.indexOf(baseTxt) === 0) {
var parts = loadingText.text.split(baseTxt);
dots = parts.length > 1 ? parts[1] : '';
}
}
// Cycle through dot patterns
if (dots === '...') {
dots = '';
} else if (dots === '') {
dots = '.';
} else if (dots === '.') {
dots = '..';
} else if (dots === '..') {
dots = '...';
}
// Update text based on current loading phase
var baseTxt = '';
if (self.loadingPhase === 0) {
baseTxt = 'Loading Core Assets';
} else if (self.loadingPhase === 1) {
baseTxt = 'Loading Intro Assets';
} else if (self.loadingPhase === 2) {
baseTxt = 'Loading Game Assets';
}
loadingText.setText(baseTxt + dots);
// Continue animation until all assets are loaded
LK.setTimeout(self.updateLoadingText, 500);
};
// Check if intro assets are loaded
self.checkIntroAssetsLoaded = function () {
if (!self.introAssetsLoaded) {
var allAssetsLoaded = true;
var testAssets = ['centerCircle', 'cloud'];
for (var i = 0; i < testAssets.length; i++) {
var testAsset = LK.getAsset(testAssets[i], {
anchorX: 0.5,
anchorY: 0.5
});
if (!testAsset || !testAsset.width) {
allAssetsLoaded = false;
break;
}
}
if (allAssetsLoaded) {
self.introAssetsLoaded = true;
self.loadingPhase = 1;
// Now that intro assets are loaded, create the intro elements
self.createIntroElements();
// Start loading game assets
LK.setTimeout(self.checkGameAssetsLoaded, 100);
} else {
// Check again in a moment
LK.setTimeout(self.checkIntroAssetsLoaded, 100);
}
}
};
// Check if game assets are loaded
self.checkGameAssetsLoaded = function () {
if (!self.gameAssetsLoaded) {
var allAssetsLoaded = true;
var testAssets = ['farmer', 'wheat', 'zombie_1', 'tomato', 'carrot', 'eggplant', 'sickle'];
for (var i = 0; i < testAssets.length; i++) {
var testAsset = LK.getAsset(testAssets[i], {
anchorX: 0.5,
anchorY: 0.5
});
if (!testAsset || !testAsset.width) {
allAssetsLoaded = false;
break;
}
}
if (allAssetsLoaded) {
self.gameAssetsLoaded = true;
self.loadingPhase = 3;
// Fade out the loading text
tween(loadingText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
loadingText.destroy();
// Start the intro animation once all loading is complete
if (!self.animationStarted) {
self.animationStarted = true;
self.startAnimation();
}
}
});
} else {
// Update loading phase
self.loadingPhase = 2;
// Check again in a moment
LK.setTimeout(self.checkGameAssetsLoaded, 100);
}
}
};
// Create intro elements once basic assets are loaded
self.createIntroElements = function () {
// Add a sunrise effect background
sunriseBackground = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 30,
scaleY: 40,
alpha: 0,
tint: 0xf5cb6c // Sunrise yellow color
});
self.addChild(sunriseBackground);
// Create animated clouds for intro
introClouds = [];
for (var i = 0; i < 3; i++) {
var cloudAsset = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
x: -300 + i * 500,
y: 400 + i * 150,
alpha: 0,
scaleX: 0.8 + i * 0.3,
scaleY: 0.8 + i * 0.3
});
self.addChild(cloudAsset);
introClouds.push(cloudAsset);
}
// Create title text
titleText = new Text2('FARM HARVESTER', {
size: 180,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 2732 / 4;
titleText.alpha = 0;
self.addChild(titleText);
// Create subtitle text
subtitleText = new Text2('Grow crops, earn money, expand your farm!', {
size: 90,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = titleText.y + 200;
subtitleText.alpha = 0;
self.addChild(subtitleText);
// Create start text only, no background
startText = new Text2('TAP TO START', {
size: 100,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startText.x = 2048 / 2;
startText.y = 2732 / 2 + 600;
startText.alpha = 0;
self.addChild(startText);
};
// Start the loading process
self.updateLoadingText();
self.checkIntroAssetsLoaded();
// Lazy creation of game assets for intro only when needed
self.createGameIntroAssets = function () {
// Create male and female farmer for intro animation only when needed
if (!maleFarmer) {
maleFarmer = LK.getAsset('farmer', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 300,
y: 2732 / 2 + 200,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
});
self.addChild(maleFarmer);
}
if (!femaleFarmer) {
femaleFarmer = LK.getAsset('farmer_walk', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 300,
y: 2732 / 2 + 200,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
});
self.addChild(femaleFarmer);
}
// Create growing plant animation elements only when needed
if (!sproutAsset) {
sproutAsset = LK.getAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(sproutAsset);
}
if (!wheatAsset) {
wheatAsset = LK.getAsset('wheat', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(wheatAsset);
}
// Create vegetables that will grow from sprout
if (!carrotAsset) {
carrotAsset = LK.getAsset('carrot', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 - 200,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(carrotAsset);
}
if (!tomatoAsset) {
tomatoAsset = LK.getAsset('tomato', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 + 200,
y: 2732 / 2 + 400,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
self.addChild(tomatoAsset);
}
// Add zombie for intro animation
if (!introZombie) {
introZombie = LK.getAsset('zombie_1', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 + 300,
y: 2732 / 2 + 300,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0
});
self.addChild(introZombie);
}
// Add sickle for intro animation
if (!introSickle) {
introSickle = LK.getAsset('sickle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 200,
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: -Math.PI / 4
});
self.addChild(introSickle);
}
};
// Start animation sequence
self.startAnimation = function () {
// Make sure assets are loaded before starting animation
if (self.loadingPhase < 3) {
LK.setTimeout(self.checkGameAssetsLoaded, 100);
return;
}
// Create game assets needed for intro animation
self.createGameIntroAssets();
// Fade in sunrise effect
tween(sunriseBackground, {
alpha: 0.5
}, {
duration: 2000,
easing: tween.easeOut
});
// Animate clouds drifting in
for (var i = 0; i < introClouds.length; i++) {
(function (index) {
var cloud = introClouds[index];
LK.setTimeout(function () {
tween(cloud, {
alpha: 0.7,
x: cloud.x + 400
}, {
duration: 4000,
easing: tween.easeOut
});
}, 500 * index);
})(i);
}
// Fade in and animate farmers running in from sides
LK.setTimeout(function () {
// Animate male farmer running in from left
tween(maleFarmer, {
alpha: 1,
x: 2048 / 2 - 150
}, {
duration: 1500,
easing: tween.easeOut
});
// Animate female farmer running in from right
tween(femaleFarmer, {
alpha: 1,
x: 2048 / 2 + 150
}, {
duration: 1500,
easing: tween.easeOut
});
}, 1000);
// Animate farmers meeting in middle and "planting" sprout
LK.setTimeout(function () {
// Move farmers to center
tween(maleFarmer, {
x: 2048 / 2 - 50
}, {
duration: 800,
easing: tween.easeInOut
});
tween(femaleFarmer, {
x: 2048 / 2 + 50
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Show sprout growing
sproutAsset.alpha = 1;
tween(sproutAsset, {
scaleX: 1,
scaleY: 1
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Show wheat growing from sprout
wheatAsset.alpha = 1;
tween(wheatAsset, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
easing: tween.easeOut
});
// Show carrot and tomato growing
carrotAsset.alpha = 1;
tween(carrotAsset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut
});
tomatoAsset.alpha = 1;
tween(tomatoAsset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut
});
}
});
}
});
}, 3000);
// Animate zombie coming in from right
LK.setTimeout(function () {
introZombie.alpha = 1;
tween(introZombie, {
x: 2048 / 2 + 450
}, {
duration: 1500,
easing: tween.easeIn
});
}, 5000);
// Animate sickle appearing and swinging
LK.setTimeout(function () {
introSickle.alpha = 1;
tween(introSickle, {
rotation: Math.PI
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(introZombie, {
alpha: 0,
y: introZombie.y + 100
}, {
duration: 500,
easing: tween.easeIn
});
}
});
}, 6000);
// Fade in title with a fancy effect
LK.setTimeout(function () {
titleText.alpha = 0.1;
tween(titleText, {
alpha: 1,
y: titleText.y + 50
}, {
duration: 1200,
easing: tween.easeOut
});
// Flash effect for title
var _flashTitle = function flashTitle(count) {
if (count <= 0) {
return;
}
tween(titleText, {
alpha: 0.7
}, {
duration: 100,
onFinish: function onFinish() {
tween(titleText, {
alpha: 1
}, {
duration: 100,
onFinish: function onFinish() {
_flashTitle(count - 1);
}
});
}
});
};
LK.setTimeout(function () {
_flashTitle(3);
}, 1200);
}, 7000);
// Fade in subtitle with delay
LK.setTimeout(function () {
tween(subtitleText, {
alpha: 1,
y: subtitleText.y + 30
}, {
duration: 800,
easing: tween.easeOut
});
}, 8000);
// Fade out animation elements and transition to game UI
LK.setTimeout(function () {
// Fade out animation elements
if (maleFarmer) {
tween(maleFarmer, {
alpha: 0
}, {
duration: 800
});
}
if (femaleFarmer) {
tween(femaleFarmer, {
alpha: 0
}, {
duration: 800
});
}
if (sproutAsset) {
tween(sproutAsset, {
alpha: 0
}, {
duration: 800
});
}
if (wheatAsset) {
tween(wheatAsset, {
alpha: 0
}, {
duration: 800
});
}
if (carrotAsset) {
tween(carrotAsset, {
alpha: 0
}, {
duration: 800
});
}
if (tomatoAsset) {
tween(tomatoAsset, {
alpha: 0
}, {
duration: 800
});
}
if (introSickle) {
tween(introSickle, {
alpha: 0
}, {
duration: 800
});
}
// Fade in start text only - startButtonBg is removed
tween(startText, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// No need to pulse since startButtonBg is removed
}
});
}, 9500);
};
// Pulse animation for start button (modified to check if element exists)
self.startPulse = function () {
// Just pulse the start text since background is removed
tween(startText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startText, {
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: self.startPulse
});
}
});
};
// Handle intro screen tap to start the game
self.down = function (x, y, obj) {
// Prevent multiple taps
if (self._startingGame) {
return;
}
self._startingGame = true;
// Play tap animation for text instead
tween(startText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Transition to yellow background
tween(sunriseBackground, {
alpha: 1,
tint: 0xf8e9c0
}, {
duration: 800,
easing: tween.easeOut
});
// Fade out all elements
if (titleText) {
tween(titleText, {
alpha: 0
}, {
duration: 600
});
}
if (subtitleText) {
tween(subtitleText, {
alpha: 0
}, {
duration: 600
});
}
tween(startText, {
alpha: 0
}, {
duration: 600
});
for (var i = 0; i < introClouds.length; i++) {
tween(introClouds[i], {
alpha: 0
}, {
duration: 600
});
}
// Fade out entire intro screen with delay
LK.setTimeout(function () {
tween(self, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
// Start/enable actual game
startActualGame();
}
});
}, 800);
}
});
return true; // Prevent event bubbling
};
return self;
});
// Rooster class with 4-frame animation cycling smoothly
var Rooster = Container.expand(function () {
var self = Container.call(this);
// Animation frame asset ids
var frameIds = ['rooster_1', 'rooster_2', 'rooster_3', 'rooster_4'];
self.roosterFrames = [];
self.currentFrame = 0;
self.frameTimer = 0;
self.frameInterval = 10; // ~0.16s per frame at 60fps (smooth)
// Attach all frames, only show the first
for (var i = 0; i < frameIds.length; ++i) {
var frame = self.attachAsset(frameIds[i], {
anchorX: 0.5,
anchorY: 0.5,
alpha: i === 0 ? 1 : 0
});
self.roosterFrames.push(frame);
}
// Animation update
self.update = function () {
self.frameTimer++;
if (self.frameTimer >= self.frameInterval) {
// Hide current frame
self.roosterFrames[self.currentFrame].alpha = 0;
// Advance to next frame
self.currentFrame = (self.currentFrame + 1) % self.roosterFrames.length;
// Show new frame
self.roosterFrames[self.currentFrame].alpha = 1;
self.frameTimer = 0;
}
};
return self;
});
// TomatoSlot class for area 3
var TomatoSlot = Container.expand(function () {
var self = Container.call(this);
self.slotAsset = self.attachAsset('tomato', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 2; // Area 3
self.regrowing = false;
// Show/hide tomato and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide tomato with animation
tween(self.slotAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
// Show sprout with animation
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show tomato with animation
tween(self.slotAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
// Hide sprout with animation
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to tomato size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to tomato and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
// Wheat class
var Wheat = Container.expand(function () {
var self = Container.call(this);
self.vegAssetId = 'wheat';
self.wheatAsset = self.attachAsset('wheat', {
anchorX: 0.5,
anchorY: 1
});
var sproutAsset = self.attachAsset('sprout', {
anchorX: 0.5,
anchorY: 1,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.harvested = false;
self.regrowTime = 1800; // 30 seconds at 60fps
self.regrowCounter = 0;
self.fieldIndex = 0; // which field this wheat belongs to
self.regrowing = false;
self.removeAfter = 0;
// Change vegetable asset if needed
self.setVegAsset = function (assetId) {
if (self.wheatAsset) {
self.wheatAsset.destroy();
}
self.vegAssetId = assetId || 'wheat';
// Only allow wheat, carrot, tomato, eggplant
var validAssets = {
wheat: 1,
carrot: 1,
tomato: 1,
eggplant: 1
};
if (!validAssets[self.vegAssetId]) {
self.vegAssetId = 'wheat';
}
self.wheatAsset = self.attachAsset(self.vegAssetId, {
anchorX: 0.5,
anchorY: 1
});
// Make sure sprout is on top
self.removeChild(sproutAsset);
self.addChild(sproutAsset);
};
// Show/hide wheat and handle regrow animation
self.setHarvested = function (harvested) {
self.harvested = harvested;
if (harvested) {
// Hide wheat, show sprout
if (self.wheatAsset) {
// Animate wheat harvesting with tween
tween(self.wheatAsset, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
}
// Show and animate sprout growing from nothing
sproutAsset.alpha = 1;
sproutAsset.scaleX = 0.1;
sproutAsset.scaleY = 0.1;
// Animate sprout appearing
tween(sproutAsset, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
self.regrowCounter = self.regrowTime;
self.regrowing = true;
} else {
// Show wheat/veg, hide sprout with animation
if (self.wheatAsset) {
tween(self.wheatAsset, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
// Fade out sprout
tween(sproutAsset, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
self.regrowing = false;
}
};
// Regrow logic and removal after 5 seconds
self.update = function () {
if (self.harvested && self.regrowing) {
if (self.regrowCounter > 0) {
// Animate sprout growing to wheat/veg size
var t = 1 - self.regrowCounter / self.regrowTime;
sproutAsset.scaleX = 0.5 + 0.5 * t;
sproutAsset.scaleY = 0.5 + 0.5 * t;
self.regrowCounter--;
}
if (self.regrowCounter <= 0) {
// Sprout is now full size, switch back to wheat/veg and allow harvest again
sproutAsset.scaleX = 1;
sproutAsset.scaleY = 1;
self.setHarvested(false);
}
}
};
// For hit detection
self.isHarvestable = function () {
return !self.harvested;
};
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
// Create the zombie frames (two different assets)
var zombieFrame1 = self.attachAsset('zombie_1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
var zombieFrame2 = self.attachAsset('zombie_2', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Animation variables
self.currentFrame = 0;
self.frameTimer = 0;
self.frameInterval = 15; // Frame switch interval
self.speed = 2; // Movement speed
self.lastX = 0; // Track previous X for collision detection
self.lastY = 0; // Track previous Y for collision detection
self.lastWasIntersecting = false; // Track previous intersection state
self.isDead = false; // Track if zombie is dead
// Handle click/tap on zombie
self.down = function (x, y, obj) {
// Mark zombie as clicked and initiate death sequence
if (!self.isDead) {
self.isDead = true;
// Flash zombie yellow to indicate hit
LK.effects.flashObject(self, 0xFFFF00, 300);
// Death animation - fade out and scale down
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove zombie from game
self.destroy();
// Create new zombie after a 40s delay
LK.setTimeout(createZombie, 40000);
}
});
// Prevent event from bubbling to game (stop farmer movement)
return true;
}
};
// Zombie animation and movement
self.update = function () {
// Don't update if dead
if (self.isDead) {
return;
}
// Save previous position for collision detection
self.lastX = self.x;
self.lastY = self.y;
// Frame animation
self.frameTimer++;
if (self.frameTimer >= self.frameInterval) {
// Toggle between frames
self.currentFrame = self.currentFrame === 0 ? 1 : 0;
// Show current frame
zombieFrame1.alpha = self.currentFrame === 0 ? 1 : 0;
zombieFrame2.alpha = self.currentFrame === 1 ? 1 : 0;
self.frameTimer = 0;
}
// Move zombie toward the farmer
if (farmer) {
var dx = farmer.x - self.x;
var dy = farmer.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > self.speed) {
self.x += self.speed * dx / dist;
self.y += self.speed * dy / dist;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4caf50 // Grass green
});
/****
* Game Code
****/
// Area 4
// Area 3
// Area 2
// Lock icon (ellipse, gray)
// Sickle (ellipse, yellow)
// House (box)
// Farmer (box)
// Wheat (ellipse)
// Field fence (rectangle)
// --- Game constants ---
// Rooster animation frames (replace id values with your own image ids)
var FIELD_W = 900;
var FIELD_H = 900;
var FIELD_GAP = 120; // Increased gap to move fences further from center
var FIELD_COUNT = 4;
var WHEAT_PER_FIELD = 10;
// Area unlock prices and reward multipliers
var FIELD_LOCK_COSTS = [0, 20000, 40000, 60000]; // Area 1 open, others locked
var FIELD_REWARD_MULT = [1, 2, 3, 4]; // Area 1=1x, 2=2x, 3=3x, 4=4x
// --- Area constants ---
// Define the distance from center for all areas (equal distance)
var AREA_DISTANCE = 600;
// Create an array to hold the areas
var areas = [];
var animals = [];
// --- Game state ---
var fields = [];
var farmer = null;
var money = 0;
var moneyTxt = null;
var sickle = null;
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var unlockFieldIndex = -1;
var playerMovementBlockedByUIClick = false; // Flag to indicate UI handled the click
// --- Layout calculation ---
// Fields: 2x2 grid, with house in center
// [0][1]
// [2][3]
var fieldPositions = [{
x: 0,
y: 0
},
// top-left
{
x: FIELD_W + FIELD_GAP,
y: 0
},
// top-right
{
x: 0,
y: FIELD_H + FIELD_GAP
},
// bottom-left
{
x: FIELD_W + FIELD_GAP,
y: FIELD_H + FIELD_GAP
} // bottom-right
];
// Center everything in game area
var totalW = FIELD_W * 2 + FIELD_GAP;
var totalH = FIELD_H * 2 + FIELD_GAP;
var offsetX = Math.floor((2048 - totalW) / 2);
var offsetY = Math.floor((2732 - totalH) / 2);
// --- Setup actual game start function ---
var gameInitialized = false;
var introScreen = null;
function initializeGameElements() {
if (gameInitialized) {
return;
}
// --- Create fields ---
for (var i = 0; i < FIELD_COUNT; ++i) {
var f = new Field();
f.index = i;
f.locked = FIELD_LOCK_COSTS[i] > 0;
f.lockCost = FIELD_LOCK_COSTS[i];
var pos = fieldPositions[i];
var fx = offsetX + pos.x;
var fy = offsetY + pos.y;
// Skip drawing fences
f.placeWheats(fx, fy, FIELD_W, FIELD_H, WHEAT_PER_FIELD);
if (f.locked) {
// Center of field
f.showLock(fx + FIELD_W / 2, fy + FIELD_H / 2);
}
game.addChild(f);
fields.push(f);
}
gameInitialized = true;
}
function startActualGame() {
// The assets should already be loaded due to the optimized intro loading process
// Initialize game elements if not already done
initializeGameElements();
// Set game elements active
game.gameActive = true;
// Play background music
LK.playMusic('backgroundMusic', {
loop: true
});
// Start game timers and events
createClouds();
LK.setTimeout(createBird, 60000);
spawnRooster();
LK.setTimeout(createZombie, 40000);
}
// Create intro screen with enhanced animations
introScreen = new IntroScreen();
game.addChild(introScreen);
// Set game to inactive until intro completes
game.gameActive = false;
// Start intro animation sequence
introScreen.startAnimation();
// Don't initialize game elements yet - wait for intro to complete
// They will be created when the player taps the start button
// Center reference point for positions
var centerX = offsetX + FIELD_W;
var centerY = offsetY + FIELD_H - 250;
// --- Create farmer ---
farmer = new Farmer();
farmer.x = centerX;
farmer.y = centerY - 120; // Start at center area
game.addChild(farmer);
// --- Create sickle (attached to farmer's hand) ---
sickle = LK.getAsset('sickle', {
anchorX: 0.2,
// hand position, left side of ellipse
anchorY: 0.7,
// slightly below center
x: 0,
y: 30
});
sickle.alpha = 1;
// --- Money display ---
moneyTxt = new Text2('$0', {
size: 100,
fill: "#fff"
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
// Buttons removed to simplify the game interface
// --- Missions UI ---
// "Missions" title
var missionsTitle = new Text2('Missions', {
size: 90,
fill: "#fff"
});
missionsTitle.anchor.set(0, 0); // Left align, top
// Place on the left side of the center part of the screen
var missionAreaX = 180; // 180px from left edge, safe from menu
var missionAreaY = 120; // Below top menu area
missionsTitle.x = missionAreaX;
missionsTitle.y = missionAreaY;
game.addChild(missionsTitle);
// Mission bar background (smaller, left side)
var missionBarBg = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0,
x: missionAreaX,
y: missionsTitle.y + missionsTitle.height + 18,
scaleX: 2.2,
scaleY: 0.5,
alpha: 0.25
});
game.addChild(missionBarBg);
// Mission bar fill (progress)
var missionBarFill = LK.getAsset('centerCircle', {
anchorX: 0,
anchorY: 0,
x: missionAreaX,
y: missionsTitle.y + missionsTitle.height + 18,
scaleX: 0,
// Will be set dynamically
scaleY: 0.5,
tint: 0xFFD700,
// Gold color
alpha: 0.85
});
game.addChild(missionBarFill);
// Mission text
var missionText = new Text2('Reach $100,000', {
size: 60,
fill: "#fff"
});
missionText.anchor.set(0, 0);
missionText.x = missionAreaX + 10;
missionText.y = missionBarBg.y + missionBarBg.height + 8;
game.addChild(missionText);
// Store for update
var missionBarMaxWidth = 200; // px, visually (not used, but kept for reference)
var missionBarFillMaxScale = 2.2;
// --- Helper: update money display ---
function updateMoneyDisplay() {
moneyTxt.setText('$' + money);
// --- Missions progress update ---
if (typeof missionBarFill !== "undefined") {
// Clamp progress between 0 and 1
var progress = Math.max(0, Math.min(1, money / 100000));
missionBarFill.scaleX = missionBarFillMaxScale * progress;
}
// --- Mission complete: You Win! ---
if (money >= 100000 && !game._missionWinShown) {
game._missionWinShown = true;
LK.showYouWin();
}
}
// --- Helper: unlock field if enough money ---
function tryUnlockField(fieldIdx) {
var f = fields[fieldIdx];
if (!f.locked) {
return;
}
if (money >= f.lockCost) {
money -= f.lockCost;
updateMoneyDisplay();
f.locked = false;
f.hideLock();
// Flash field green
for (var i = 0; i < f.fenceNodes.length; ++i) {
LK.effects.flashObject(f.fenceNodes[i], 0x00ff00, 600);
}
} else {
// Not enough money, flash red
LK.effects.flashScreen(0xff0000, 400);
}
}
// --- Touch/mouse handling ---
var lastDownX = 0,
lastDownY = 0;
var harvestMode = false;
var harvestWheat = null;
// Helper: find harvestable vegetable under (x, y) in unlocked fields
function findHarvestableWheat(x, y) {
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
if (f.locked) {
continue;
}
for (var j = 0; j < f.wheats.length; ++j) {
var w = f.wheats[j];
if (w.isHarvestable()) {
// Use bounding box for hit
var wx = w.x,
wy = w.y;
var ww = 60,
wh = 80;
if (x >= wx - ww / 2 && x <= wx + ww / 2 && y >= wy - wh && y <= wy) {
return w;
}
}
}
}
return null;
}
// Helper: find locked field under (x, y)
function findLockedField(x, y) {
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
if (!f.locked) {
continue;
}
// Use field area
var pos = fieldPositions[i];
var fx = offsetX + pos.x;
var fy = offsetY + pos.y;
if (x >= fx && x <= fx + FIELD_W && y >= fy && y <= fy + FIELD_H) {
return i;
}
}
return -1;
}
// --- Game event handlers ---
// Move farmer or harvest wheat
game.down = function (x, y, obj) {
// Don't process game inputs if game is not active yet
if (!game.gameActive) {
return;
}
// Shop system completely removed
// No shopButton references needed anymore
// Continue with normal game control flow
// No shop button checks needed
//
lastDownX = x;
lastDownY = y;
// Check if tapping on locked field unlock button
var lockedIdx = findLockedField(x, y);
if (lockedIdx >= 0) {
var f = fields[lockedIdx];
// If tap is near lock icon or unlock text
var centerX = offsetX + fieldPositions[lockedIdx].x + FIELD_W / 2;
var centerY = offsetY + fieldPositions[lockedIdx].y + FIELD_H / 2;
var dist = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
if (dist < 120) {
tryUnlockField(lockedIdx);
return;
}
}
// Check for wheat
var w = findHarvestableWheat(x, y);
if (w) {
harvestMode = true;
harvestWheat = w;
// Change player to face forward during harvest
// Switch to player_down for harvesting
if (farmer.currentAsset) {
farmer.currentAsset.alpha = 0;
}
var playerDown = LK.getAsset('player_down', {
anchorX: 0.5,
anchorY: 0.5
});
playerDown.alpha = 1;
farmer.addChild(playerDown);
farmer.currentAsset = playerDown;
// Trigger sickle attack animation
farmer.attack();
// Show harvest animation effect
var harvestEffect = LK.getAsset('sprout', {
anchorX: 0.5,
anchorY: 0.5,
x: w.x,
y: w.y - 50,
alpha: 0.8,
scaleX: 2,
scaleY: 2
});
game.addChild(harvestEffect);
// Animate the harvest effect
tween(harvestEffect, {
alpha: 0,
y: harvestEffect.y - 100
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
harvestEffect.destroy();
}
});
// Harvest
w.setHarvested(true);
var reward = 100 * (FIELD_REWARD_MULT[w.fieldIndex] || 1);
money += reward;
updateMoneyDisplay();
// Flash wheat
LK.effects.flashObject(w, 0xffff00, 300);
// No setHarvested(false) here; regrow/removal handled in Wheat.update
harvestMode = false;
harvestWheat = null;
return;
}
// Move farmer with animation
farmer.moveTo(x, y);
dragging = true;
dragOffsetX = x - farmer.x;
dragOffsetY = y - farmer.y;
};
// Drag farmer
game.move = function (x, y, obj) {
// Don't process game inputs if game is not active yet
if (!game.gameActive) {
return;
}
// Shop system completely removed
//
if (dragging) {
farmer.moveTo(x - dragOffsetX, y - dragOffsetY);
}
if (harvestMode && harvestWheat) {
sickle.x = x;
sickle.y = y;
}
};
// End drag/harvest
game.up = function (x, y, obj) {
// Don't process game inputs if game is not active yet
if (!game.gameActive) {
return;
}
// Shop system completely removed
//
//
dragging = false;
harvestMode = false;
harvestWheat = null;
};
// --- Main update loop ---
// Defensive: If game is reset, clear win timer
game.update = function () {
// Only update game elements if game is active (after intro)
if (!game.gameActive) {
// If there's an intro screen, allow it to animate even while game is inactive
if (introScreen && introScreen.parent) {
// Still allow intro screen animations to update
if (introScreen.updateLoadingText && !introScreen.assetsLoaded) {
// Loading animation is handled by setTimeout
}
}
return;
}
// Update farmer if initialized
if (farmer) {
farmer.update();
}
// Update wheat regrow
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
f.wheats.forEach(function (wheat) {
wheat.update();
});
}
// Update clouds
for (var i = 0; i < clouds.length; i++) {
clouds[i].update();
}
// Update birds
for (var i = 0; i < birds.length; i++) {
birds[i].update();
}
};
// --- Create areas and place animals ---
// Calculate center of game screen
var gameWidth = 2048;
var gameHeight = 2732;
var gameCenterX = gameWidth / 2;
var gameCenterY = gameHeight / 2;
// Create the four areas at equal distances from center
// Area_Left
var areaLeft = new Container();
areaLeft.x = gameCenterX - AREA_DISTANCE;
areaLeft.y = gameCenterY;
areaLeft.name = "Area_Left";
game.addChild(areaLeft);
areas.push(areaLeft);
// Area_Right
var areaRight = new Container();
areaRight.x = gameCenterX + AREA_DISTANCE;
areaRight.y = gameCenterY;
areaRight.name = "Area_Right";
game.addChild(areaRight);
areas.push(areaRight);
// Area_Top
var areaTop = new Container();
areaTop.x = gameCenterX;
areaTop.y = gameCenterY - AREA_DISTANCE;
areaTop.name = "Area_Top";
game.addChild(areaTop);
areas.push(areaTop);
// Area_Bottom
var areaBottom = new Container();
areaBottom.x = gameCenterX;
areaBottom.y = gameCenterY + AREA_DISTANCE;
areaBottom.name = "Area_Bottom";
game.addChild(areaBottom);
areas.push(areaBottom);
// Place animals in the areas
// Animal_Right at bottom right of screen
var animalRight = new Animal();
animalRight.setAnimalImage('animal_right');
animalRight.name = "Animal_Right";
// Place at bottom right, accounting for anchor (0.5, 0.5) and asset size
var animalRightAsset = LK.getAsset('animal_right', {
anchorX: 0.5,
anchorY: 0.5
});
animalRight.x = gameWidth - animalRightAsset.width / 2 - 10; // 10px padding from right
animalRight.y = gameHeight - animalRightAsset.height / 2 - 10; // 10px padding from bottom
game.addChild(animalRight);
animals.push(animalRight);
// Area_Bottom has no animal
// --- Create clouds ---
var clouds = [];
// Create two clouds at different positions
function createClouds() {
// Remove any existing clouds
for (var i = 0; i < clouds.length; i++) {
clouds[i].destroy();
}
clouds = [];
// Cloud width for calculations
var cloudWidth = 500;
// Create first cloud (front layer)
var cloud1 = new Cloud();
cloud1.x = -cloudWidth / 2; // Start from off-screen left
cloud1.y = 180; // Higher position near the top
cloud1.layer = 0; // Front layer - this will be in front
cloud1.init(); // Initialize movement and timing
game.addChild(cloud1);
clouds.push(cloud1);
// Create second cloud (back layer)
var cloud2 = new Cloud();
cloud2.x = -cloudWidth / 2 - 200; // Start more separated from first cloud
cloud2.y = 280; // Position below first cloud with more separation
cloud2.layer = 1; // Back layer - this will be behind
cloud2.init(); // Initialize movement and timing
game.addChild(cloud2);
clouds.push(cloud2);
// Schedule creation of new clouds after these disappear
LK.setTimeout(createClouds, 61000); // 61 seconds to ensure smooth transition
}
// Start creating clouds
createClouds();
// Shop system completely removed
// --- Create zombie ---
var zombie = null;
var zombieDamageTimer = 0; // Timer to prevent continuous damage
var zombieDamageAmount = 500; // Initial zombie damage/cost
var zombieAppearCount = 0; // How many times zombie has appeared
// --- Create birds ---
var birds = [];
// Create a bird that starts at the top, flies across, disappears, and restarts in a loop
function createBird() {
// Remove any existing birds that might be stuck
for (var i = 0; i < birds.length; i++) {
birds[i].destroy();
}
birds = [];
// Bird asset for size
var tempBirdAsset = LK.getAsset('Bird', {
anchorX: 0.5,
anchorY: 0.5
});
var birdWidth = tempBirdAsset.width;
var birdHeight = tempBirdAsset.height;
// Start at the top of the screen, just off the left edge
var bird = new Bird();
bird.x = -birdWidth / 2;
bird.y = birdHeight / 2 + 20; // 20px padding from the very top
bird.init();
game.addChild(bird);
birds.push(bird);
// Set up a watcher to restart the bird after 60 seconds (3600 ticks at 60fps)
bird._birdLoopCheck = function () {
// Only restart if bird is gone (destroyed)
if (!bird.parent) {
LK.setTimeout(createBird, 60000); // 60 seconds delay before next bird
} else {
LK.setTimeout(bird._birdLoopCheck, 200); // Check again in 200ms
}
};
LK.setTimeout(bird._birdLoopCheck, 200);
}
// Start creating birds after 1 minute (60000 ms)
LK.setTimeout(createBird, 60000);
// Background music will be played when the game starts after the intro sequence completes
// Music playback is now handled in startActualGame()
// --- Initial money display ---
updateMoneyDisplay();
// --- Place trees at corners ---
// Tree size
var treeWidth = 400;
var treeHeight = 532;
// Top left corner tree
var topLeftTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: offsetX / 2,
y: offsetY / 2
});
game.addChild(topLeftTree);
// Top right corner tree
var topRightTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - offsetX / 2,
y: offsetY / 2
});
game.addChild(topRightTree);
// Bottom left corner tree
var bottomLeftTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: offsetX / 2,
y: 2732 - offsetY / 2
});
game.addChild(bottomLeftTree);
// Bottom right corner tree
var bottomRightTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - offsetX / 2,
y: 2732 - offsetY / 2
});
game.addChild(bottomRightTree);
// --- Place trees at middle sides aligned with corner trees ---
// Tree to the left of center
var leftCenterTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: offsetX / 2,
y: topRightTree.y
});
game.addChild(leftCenterTree);
// Tree to the right of center
var rightCenterTree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - offsetX / 2,
y: topRightTree.y
});
game.addChild(rightCenterTree);
// --- Add Rooster that moves left-to-right, disappears at right edge, reappears after 40s and repeats ---
var rooster = null;
var roosterTimeout = null;
function spawnRooster() {
// Remove any existing rooster
if (rooster && rooster.parent) {
rooster.destroy();
}
rooster = new Rooster();
// Start at the left center of the screen
rooster.y = 2732 / 2;
rooster.x = rooster.roosterFrames[0].width / 2 + 10;
game.addChild(rooster);
// Rooster path: left-to-right, horizontally centered
var roosterStartX = rooster.roosterFrames[0].width / 2 + 10;
var roosterEndX = 2048 - rooster.roosterFrames[0].width / 2 - 10;
var roosterSpeed = 1; // px per frame, very slow movement
rooster.targetX = roosterEndX;
rooster.direction = 1; // 1: moving right
rooster.updateRoosterMovement = function () {
// Track lastX for edge detection
if (typeof rooster.lastX === "undefined") {
rooster.lastX = rooster.x;
}
// Move only horizontally in the center
var dx = rooster.targetX - rooster.x;
var dist = Math.abs(dx);
if (dist < roosterSpeed) {
rooster.x = rooster.targetX;
} else {
rooster.x += roosterSpeed * (dx > 0 ? 1 : -1);
}
// Call animation update
if (typeof rooster.update === "function") {
rooster.update();
}
// Check if rooster just reached the right edge (disappear trigger)
if (rooster.lastX < roosterEndX && rooster.x >= roosterEndX) {
// Fade out and destroy, then respawn after 40s
tween(rooster, {
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
if (rooster && rooster.parent) {
rooster.destroy();
}
roosterTimeout = LK.setTimeout(spawnRooster, 40000); // 40 seconds
}
});
}
// Update lastX for next frame
rooster.lastX = rooster.x;
};
}
// Add rooster update to main game loop
var oldGameUpdate = game.update;
game.update = function () {
if (typeof oldGameUpdate === "function") {
oldGameUpdate();
}
if (rooster && rooster.parent && typeof rooster.updateRoosterMovement === "function") {
rooster.updateRoosterMovement();
}
// Update zombie
if (zombie && zombie.parent) {
zombie.update();
// Collision detection with player (only triggers on state change)
var isIntersecting = zombie.intersects(farmer);
// Check if we just started intersecting
if (!zombie.lastWasIntersecting && isIntersecting && zombieDamageTimer <= 0) {
// Zombie just touched the player, deduct gold
money = Math.max(0, money - zombieDamageAmount);
updateMoneyDisplay();
// Flash both zombie and farmer red
LK.effects.flashObject(zombie, 0xff0000, 500);
LK.effects.flashObject(farmer, 0xff0000, 500);
// Set cooldown timer to prevent continuous damage (3 second cooldown)
zombieDamageTimer = 180;
}
// Update intersection state
zombie.lastWasIntersecting = isIntersecting;
// Update damage cooldown timer
if (zombieDamageTimer > 0) {
zombieDamageTimer--;
}
}
};
// Create the zombie
function createZombie() {
// Remove existing zombie if it exists
if (zombie && zombie.parent) {
zombie.destroy();
}
// Create new zombie
zombie = new Zombie();
// Position zombie off-screen to the left
zombie.x = -100;
zombie.y = 2732 / 2;
// Initialize tracking variables
zombie.lastX = zombie.x;
zombie.lastY = zombie.y;
zombie.lastWasIntersecting = false;
game.addChild(zombie);
// Increase zombie damage each time it spawns
zombieAppearCount++;
if (zombieAppearCount === 1) {
zombieDamageAmount = 500;
} else {
zombieDamageAmount = zombieDamageAmount * 2;
}
}
// Start the first rooster and create zombie
spawnRooster();
// Delay the first zombie spawn by 40 seconds after game start
LK.setTimeout(createZombie, 40000);