User prompt
To optimize the Automatic Collect feature, make sure it runs only when necessary and doesn’t check or process data every frame unnecessarily. Use events or timers to trigger collection actions at set intervals instead of constant updates. Avoid heavy calculations during automatic collection and update the UI only when the collected amount changes. This reduces CPU usage and prevents the game from lagging, keeping the gameplay smooth and responsive.
User prompt
To optimize all your game mechanics and features, first organize your code so each part (like harvesting, automatic collect, UI updates, and money handling) runs efficiently without unnecessary calculations every frame. Use event-driven programming where possible—trigger actions only when the player interacts or when specific conditions change, instead of constantly checking in update loops. Manage resources carefully by loading and unloading assets as needed and avoid creating too many objects at once. For timers and delays, use lightweight functions that don’t block the main thread. Also, minimize UI updates by only changing text or visuals when there is a real change, not every frame. Finally, profile your game regularly to identify and fix any performance bottlenecks. This approach ensures your game runs smoothly even as you add more features.
User prompt
The message "You need 30,000 money to unlock Automatic Collect." should appear centered exactly in the middle of the screen with a medium font size that is easy to read but not too large. This message should show up 1 minute (60 seconds) after the game starts and remain visible for 30 seconds before disappearing automatically. Make sure the text color contrasts well with the background so the player can clearly see it. Also, control the timing with a timer or delay function in your game’s code to handle when the message appears and disappears smoothly. This ensures the player gets the information at the right time in a clear and non-intrusive way. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Show Instruction Message Centered, Small, and Visible for 30 Seconds After 30 seconds from game start, display the message: "To use Automatic Collect, move your mouse over the wheat." Show the message centered on the screen with a small font size that’s easy to read. Make sure the text color contrasts with the background for clear visibility. Keep the message visible for 30 seconds before hiding or removing it automatically. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Display Small Instruction Message Centered and Clearly Visible Show the message in the center of the screen (both horizontally and vertically). Use a smaller font size than normal, so it’s not too big but still easy to read. Make sure the text color contrasts well with the background to keep it clearly visible. Position the message so it does not block important UI elements but is noticeable. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Show Instruction Message After 30 Seconds for 10 Seconds Start a timer when the game begins counting 30 seconds. After 30 seconds, display the message: "To use Automatic Collect, move your mouse over the wheat." Keep this message visible for 10 seconds. After 10 seconds, automatically hide or remove the message from the screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Temporary Unlock That Resets on Game Exit When the player pays 30,000, the Automatic Collect feature unlocks temporarily during that game session. The button changes to show "Automatic Collect" without the price or lock while playing. However, once the player leaves or restarts the game, the unlock resets. Next time the player starts, the button shows "Unlock - 30,000" again, requiring the player to pay 30,000 once more to unlock. This means the player must pay every time they start a new game session to use the feature.
User prompt
Automatic Collect Unlock and Lock System with Price Initially, the button shows: "Unlock - 30,000" and looks locked (with a lock icon or style). When the player pays 30,000, the button changes to: "Automatic Collect" with the lock removed (unlocked look). After unlocking, the "Unlock" text and price (30,000) completely disappear. The unlocked state is saved permanently, so if the player leaves and returns, the button still shows "Automatic Collect" without the price or lock. If the player hasn’t paid yet, the button remains locked and shows the price to unlock. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
After Buying, Show Only “Automatic Collect” When the player buys/unlocks the feature, the button should show only “Automatic Collect.” The price or any other text should disappear completely. This change stays even if the player leaves and comes back to the game. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Keep the Button Text as “Automatic Collect” Permanently After First Unlock When the player unlocks Automatic Collect for the first time by paying 30,000, immediately change the button text from "Unlock - 30,000" to "Automatic Collect". This change should be saved permanently in the player’s data (using persistent storage like a database, local save, cloud save, or any system your game uses to remember player progress). Every time the player starts or re-enters the game, the system should check if the player has already unlocked Automatic Collect by reading that saved data. If the player has unlocked it, the button text should remain as "Automatic Collect" — never go back to showing the price or "Unlock" text. The player can then toggle the feature ON or OFF, but the button text stays the same. This means, once unlocked, the button text will always show "Automatic Collect" and never show the price again, even after leaving and returning to the game. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
How to Hide the "30,000" Price Permanently After Unlocking Automatic Collect To ensure the player never sees the "30,000" price again after unlocking Automatic Collect, follow these steps: Save the Unlock Status Permanently: When the player pays 30,000 to unlock Automatic Collect, save a boolean flag like hasAutomaticCollect = true in a persistent storage system (such as a database, cloud save, local storage, or player data system) that keeps data even after the player leaves the game. Check Unlock Status on Game Start: Each time the player starts or loads the game, check this saved flag. If hasAutomaticCollect is true, it means the player has already unlocked the feature. Update the UI Accordingly: When the player has unlocked Automatic Collect, remove or hide the "30,000" price text from the button so it no longer appears. The button should only show the label "Automatic Collect" without any price. Ensure No Additional Payments Are Required: Since the unlock status is saved, prevent deducting money again or showing the price after the first purchase. By following these steps, the price text will permanently disappear for the player after the initial unlock, even if they leave and return to the game. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Permanent Unlock and Price Removal The player only needs to unlock Automatic Collect once by paying 30,000 money. After unlocking, the price ("30,000") on the button is permanently removed—it never shows again for that player. This unlock status is saved permanently, so even if the player exits and returns to the game, the Automatic Collect feature remains unlocked and the price stays hidden. There is no need to pay again or see the price after the first unlock. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Remove the Price Text on the Automatic Collect Button After Unlock When the player unlocks Automatic Collect, the "30,000" price text on the button should be removed completely. The button then only shows "Automatic Collect" without any price next to it.
User prompt
Hide the Money Display When Automatic Collect Is Unlocked When the player unlocks Automatic Collect, the money amount display should be hidden or removed from the screen. This shows clearly that the feature is active and the price no longer matters.
User prompt
Hide the 30,000 Price for Players Who Have Bought Automatic Collect Players who have already bought/unlocked the Automatic Collect feature should not see the "30,000" price anymore. For these players, only the "Automatic Collect" label remains visible on the button. This way, the price disappears only for those who have paid, making the UI cleaner.
User prompt
After Unlock, Hide the Price for That Player Once the player unlocks the feature by paying 30,000, they won’t see the “30,000” price again. They will only see the feature name (like "Automatic Collect") on the button. This keeps the UI clean and clear for players who already paid.
User prompt
Show Price Only to Players Who Haven’t Bought It The "Unlock - 30,000" text should be visible only to players who haven’t bought the feature yet. After the player buys it, the price text disappears. This way, only players who still need to pay see the price, and those who bought it just see the feature name.
User prompt
Persistent Unlock After Purchase Once the player buys/unlocks the Automatic Collect feature by paying 30,000 money, the unlock status is saved permanently. Even if the player exits the game and returns later, they will still have the Automatic Collect feature unlocked. This means the player does not need to pay again after the first purchase. Make sure to save this unlock state using persistent storage (like a database, save file, or cloud save) depending on your platform. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Button Placement, Label, and Unlock Price Info Place the button centered at the bottom of the screen (horizontally centered). Next to the button (inside or as part of the button’s text), display the label: "Automatic Collect" (using "Collect" instead of "Collection"). Also, clearly show that the feature can only be unlocked with 30,000 money, for example: "Unlock - 30,000" when locked, or just "Automatic Collect" when unlocked. Make sure the button is large and visible enough for easy clicking.
User prompt
Button Placement, Label, and Unlock Price Info Place the button centered at the bottom of the screen (horizontally centered). Next to the button (inside or as part of the button’s text), display the label: "Automatic Collect" (using "Collect" instead of "Collection"). Also, clearly show that the feature can only be unlocked with 10,000 money, for example: "Unlock - 10,000" when locked, or just "Automatic Collect" when unlocked. Make sure the button is large and visible enough for easy clicking.
User prompt
Button Placement and Label Place the button centered at the bottom of the screen (horizontally centered). Next to the button (either inside or as part of the button’s text), display the label: "Automatic Collect" (use "Collect" instead of "Collection"). Make sure the button is large enough to be easily visible and clickable.
User prompt
One-Time Payment for Unlocking The player only needs to pay once to unlock the Automatic Collection feature. After the initial payment of 10,000 money, the player can toggle the feature ON and OFF freely without any additional cost. No more money will be deducted from the player after the first unlock. The button should remember the unlocked state and allow toggling without further payments.
User prompt
Additional Feature: Toggleable Lock with Price Display The player can toggle the Automatic Collection mode ON and OFF by clicking the button again after unlocking. When locked again, the feature becomes inactive, but the player does not get their money back. They need to unlock again by paying if desired. Next to the "Unlock" text on the button, always display the price (10,000 money) clearly so the player knows the cost. The button’s main label should clearly show the feature name as "Automatic Collection" (or the equivalent in your game). This way, the player sees both the price and feature name on the button, and can control the feature’s status by toggling it ON or OFF.
User prompt
Detailed Description for Automatic Collection Unlock System Display Player's Current Money Show the player’s current money clearly on the screen so they always know how much they have. Unlock Button with Label "Unlock" The automatic collection feature starts locked. The button should display the text: "Unlock" Unlock Condition: 10,000 Money When the player’s money reaches 10,000 or more, the button becomes clickable/enabled. It should be obvious to the player that they now have enough money to unlock the feature. When Player Clicks "Unlock" Button Deduct 10,000 money from the player’s total immediately (subtract 10,000 from their current money). Activate the Automatic Collection mode. Change the button text from "Unlock" to "Automatic Collection" or a similar active mode label to indicate the feature is now active. Visual Feedback Make sure the money display updates instantly when 10,000 is deducted. The button’s appearance should clearly indicate whether the feature is locked or unlocked.
User prompt
Please fix the bug: 'Uncaught TypeError: swipeModeText.getText is not a function' in or related to this line: 'if (money >= 10000 && swipeModeText.getText() === 'Unlock') {' Line Number: 1939
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.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 - optimized self.update = function () { // Early return if invisible or not visible - prevents unnecessary calculations if (self.alpha <= 0 || !self.visible) return; // Increment life counter first for potential early returns self.lifeCounter++; // Only check edge crossing if we're near the edge - optimization var edgeX = 2048 + birdAsset.width / 2; if (self.x >= edgeX) { // 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.visible = false; // Hide instead of destroy birds.push(self); // Return to pool } }); return; // Early return after starting fade out animation } // Create a small wavy flight pattern - only for visible, active birds self.y = self.y + Math.sin(self.lifeCounter * 0.03) * 1.5; }; 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--; } else { // Sprout is now full size, switch back to carrot and allow harvest again sproutAsset.scaleX = 1; sproutAsset.scaleY = 1; self.setHarvested(false); self.regrowing = false; // Stop regrowing process } } }; // 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 - optimized self.update = function () { // Early return if invisible or not visible - saves processing if (self.alpha <= 0 || !self.visible) return; // Track lastX for edge detection - initialize once if undefined if (typeof self.lastX === "undefined") self.lastX = self.x; // Only check edge crossing if we're near the edge - optimization var edgeX = 2048 + cloudAsset.width / 2; if (self.x >= edgeX && self.lastX < edgeX) { // Stop any existing tweens on this cloud to prevent conflicts tween.stop(self); // Fade out animation tween(self, { alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Remove cloud from game self.visible = false; // Hide instead of destroy clouds.push(self); // Return to pool } }); } // 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--; } else { // Sprout is now full size, switch back to eggplant and allow harvest again sproutAsset.scaleX = 1; sproutAsset.scaleY = 1; self.setHarvested(false); self.regrowing = false; // Stop regrowing process } } }; // 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; }); // 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--; } else { // Sprout is now full size, switch back to tomato and allow harvest again sproutAsset.scaleX = 1; sproutAsset.scaleY = 1; self.setHarvested(false); self.regrowing = false; // Stop regrowing process } } }; // 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 - highly optimized self.update = function () { // Early return if not harvested or not regrowing - prevents unnecessary checks if (!self.harvested || !self.regrowing) return; if (self.regrowCounter > 0) { // Optimize calculations by using cached values and only calculating once var t = 1 - self.regrowCounter / self.regrowTime; var newScale = 0.5 + 0.5 * t; sproutAsset.scaleX = newScale; sproutAsset.scaleY = newScale; self.regrowCounter--; } else { // Sprout is now full size, switch back to wheat/veg and allow harvest again sproutAsset.scaleX = 1; sproutAsset.scaleY = 1; self.setHarvested(false); self.regrowing = false; // Stop regrowing process } }; // 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 or not visible if (self.isDead || !self.visible) 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; } } // Check if zombie is off-screen and return to pool if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) { self.visible = false; // Hide instead of destroy zombies.push(self); // Return to pool } }; 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 = storage.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); // --- Create fields --- // Load unlocked fields from storage, default to [true, false, false, false] (only first field unlocked) // Defensive: ensure unlockedFields is an array of length 4 var unlockedFields = storage.unlockedFields; if (!Array.isArray(unlockedFields) || unlockedFields.length !== 4) { unlockedFields = [true, false, false, false]; storage.unlockedFields = unlockedFields; } for (var i = 0; i < FIELD_COUNT; ++i) { var f = new Field(); f.index = i; // Use unlockedFields to determine locked state f.locked = !unlockedFields[i]; 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); } // Center reference point for positions var centerX = offsetX + FIELD_W; var centerY = offsetY + FIELD_H - 250; // --- Create farmer --- farmer = new Farmer(); farmer.x = storage.farmerX || centerX; farmer.y = storage.farmerY || 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('$' + money, { size: 100, fill: "#fff" }); moneyTxt.anchor.set(0.5, 0); LK.gui.top.addChild(moneyTxt); // --- Information message on right side --- // Create the info message text var infoMsgTxt = new Text2('Game controls: Use mouse to move.\nFor mobile, tap to move.', { size: 80, fill: "#fff" }); infoMsgTxt.anchor.set(1, 0.5); // Right align, vertically centered // Position at right side, vertically centered (avoid top 100px for menu) infoMsgTxt.x = 2048 - 40; // 40px padding from right edge infoMsgTxt.y = 2732 / 2; game.addChild(infoMsgTxt); // Hide after 30 seconds (1800 frames at 60fps) LK.setTimeout(function () { if (infoMsgTxt && infoMsgTxt.parent) { infoMsgTxt.destroy(); } }, 30000); // --- Instruction message for Automatic Collect --- // Create the instruction message text var instructionMsgTxt = new Text2('To use Automatic Collect, move your mouse over the wheat.', { size: 50, // Smaller font size for better visibility fill: 0xFFCC00 // Bright yellow for contrast }); instructionMsgTxt.anchor.set(0.5, 0.5); // Center align instructionMsgTxt.x = 2048 / 2; // Center horizontally instructionMsgTxt.y = 2732 / 2; // Center vertically instructionMsgTxt.visible = false; // Initially hidden game.addChild(instructionMsgTxt); // Show instruction message after 30 seconds LK.setTimeout(function () { instructionMsgTxt.visible = true; // Hide instruction message after 30 seconds LK.setTimeout(function () { if (instructionMsgTxt && instructionMsgTxt.parent) { instructionMsgTxt.destroy(); } }, 30000); }, 30000); // --- Message for unlocking Automatic Collect --- // Create the unlock message text var unlockMsgTxt = new Text2('You need 30,000 money to unlock Automatic Collect.', { size: 70, // Medium font size fill: 0xFFFFFF // White color for contrast }); unlockMsgTxt.anchor.set(0.5, 0.5); // Center align unlockMsgTxt.x = 2048 / 2; // Center horizontally unlockMsgTxt.y = 2732 / 2; // Center vertically unlockMsgTxt.visible = false; // Initially hidden game.addChild(unlockMsgTxt); // Show unlock message after 60 seconds LK.setTimeout(function () { unlockMsgTxt.visible = true; // Hide unlock message after 30 seconds LK.setTimeout(function () { if (unlockMsgTxt && unlockMsgTxt.parent) { unlockMsgTxt.destroy(); } }, 30000); }, 60000); // --- 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(); // Reset player position and money farmer.x = centerX; farmer.y = centerY - 120; money = 0; _updateMoneyDisplay(); } } // --- 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(); // Update unlockedFields in storage only if changed var unlockedFields = storage.unlockedFields || [true, false, false, false]; if (!unlockedFields[fieldIdx]) { unlockedFields[fieldIdx] = true; storage.unlockedFields = unlockedFields; } // 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; var harvestedCrops = []; // Track harvested crops during swipe // 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) { // If UI handled this click, do nothing for game movement. if (playerMovementBlockedByUIClick) { playerMovementBlockedByUIClick = false; // Reset flag for next input 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) { // If UI interaction blocked the start of a drag, this helps. if (playerMovementBlockedByUIClick) { // Flag will be reset by the next 'down' event, or could be reset here if necessary, // but typically 'move' follows a 'down' that wasn't blocked. return; } // Shop system completely removed // if (dragging) { farmer.moveTo(x - dragOffsetX, y - dragOffsetY); } if (swipeModeActive) { sickle.x = x; sickle.y = y; // Check for new harvestable crops under the swipe var newHarvestWheat = findHarvestableWheat(x, y); if (newHarvestWheat && !harvestedCrops.includes(newHarvestWheat)) { harvestedCrops.push(newHarvestWheat); newHarvestWheat.setHarvested(true); var reward = 100 * (FIELD_REWARD_MULT[newHarvestWheat.fieldIndex] || 1); money += reward; _updateMoneyDisplay(); LK.effects.flashObject(newHarvestWheat, 0xffff00, 300); } } }; // End drag/harvest game.up = function (x, y, obj) { // If UI interaction blocked the 'down' event, 'up' should also be controlled. if (playerMovementBlockedByUIClick) { playerMovementBlockedByUIClick = false; // Reset flag here as well return; } // Shop system completely removed // // dragging = false; harvestMode = false; harvestWheat = null; harvestedCrops = []; // Reset harvested crops tracking // swipeModeActive = false; // Optional: Deactivate swipe mode on release }; // --- Main update loop --- // Defensive: If game is reset, clear win timer game.update = function () { // Update 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(); } // Update zombies for (var i = 0; i < zombies.length; i++) { zombies[i].update(); } }; // Automatic Collect Timer var autoCollectInterval = 5000; // 5 seconds interval for automatic collection var autoCollectTimer = LK.setInterval(function () { if (swipeModeActive) { for (var i = 0; i < fields.length; ++i) { var f = fields[i]; if (f.locked) continue; f.wheats.forEach(function (wheat) { if (wheat.isHarvestable()) { wheat.setHarvested(true); var reward = 100 * (FIELD_REWARD_MULT[wheat.fieldIndex] || 1); money += reward; _updateMoneyDisplay(); LK.effects.flashObject(wheat, 0xffff00, 300); } }); } } }, autoCollectInterval); // --- 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 clouds at different positions with increased delay function createClouds() { // Reuse existing clouds or create new ones if pool is empty var cloud; if (clouds.length > 0) { cloud = clouds.pop(); cloud.alpha = 1; // Reset alpha for visibility cloud.visible = true; // Ensure cloud is visible cloud.init(); // Reinitialize cloud properties } else { cloud = new Cloud(); game.addChild(cloud); cloud.init(); // Initialize cloud properties } // Cloud width for calculations - cached outside for performance var cloudWidth = 500; cloud.x = -cloudWidth / 2; // Start from off-screen left cloud.y = 180; // Higher position near the top cloud.layer = 0; // Front layer - this will be in front cloud.init(); // Initialize movement and timing clouds.push(cloud); // Schedule creation of new clouds after these disappear - extended time LK.setTimeout(createClouds, 180000); // 180 seconds to spread out cloud creation more } // 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 zombies = []; var birds = []; // Create a bird that starts at the top, flies across, disappears, and restarts in a loop function createBird() { // Avoid overlapping timers - clear any existing if (window._birdCreationTimer) { LK.clearTimeout(window._birdCreationTimer); window._birdCreationTimer = null; } // Reuse existing birds or create new ones if pool is empty var bird; if (birds.length > 0) { bird = birds.pop(); bird.alpha = 1; // Reset alpha for visibility bird.visible = true; // Ensure bird is visible bird.init(); // Reinitialize bird properties } else { bird = new Bird(); game.addChild(bird); bird.init(); // Initialize bird properties } // Cache bird dimensions for better performance var birdWidth = 350; // Use known width instead of creating temporary asset var birdHeight = 350; // Use known height bird.x = -birdWidth / 2; bird.y = birdHeight / 2 + 20; // 20px padding from the very top bird.init(); birds.push(bird); // Simple flag to prevent duplicate scheduling bird._nextBirdScheduled = false; // Optimized check function that runs less frequently bird._birdLoopCheck = function () { // Only schedule new bird once if this one is gone if ((!bird.parent || bird.alpha <= 0) && !bird._nextBirdScheduled) { bird._nextBirdScheduled = true; // Create new bird after a longer delay to reduce processing frequency window._birdCreationTimer = LK.setTimeout(createBird, 240000); // 240 seconds (4 min) delay for less frequent processing } else if (bird.parent && bird.alpha > 0) { // Check much less frequently to reduce timer overhead LK.setTimeout(bird._birdLoopCheck, 30000); // Check every 30 seconds instead of 15 } }; // Start the check after a longer delay LK.setTimeout(bird._birdLoopCheck, 30000); } // Start creating birds after 1 minute (60000 ms) LK.setTimeout(createBird, 60000); // Play background music in a loop LK.playMusic('backgroundMusic', { loop: true }); // --- 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 - with robust null check if (rooster) { // Only try to destroy if rooster exists and has a parent if (rooster && rooster.parent) { try { rooster.destroy(); } catch (e) { console.log("Error destroying rooster:", e); } } rooster = null; } 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--; } } storage.farmerX = farmer.x; storage.farmerY = farmer.y; storage.money = money; }; // Create the zombie function createZombie() { // Reuse existing zombie or create new one if pool is empty var zombie; if (zombies.length > 0) { zombie = zombies.pop(); zombie.alpha = 1; // Reset alpha for visibility zombie.visible = true; // Ensure zombie is visible zombie.isDead = false; // Reset dead state zombie.init(); // Reinitialize zombie properties } else { zombie = new Zombie(); game.addChild(zombie); } // Reset zombie properties for reuse zombie.alpha = 1; zombie.isDead = false; // 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; // Increase zombie damage each time it spawns zombieAppearCount++; if (zombieAppearCount === 1) { zombieDamageAmount = 500; } else { zombieDamageAmount = zombieDamageAmount * 2; } // Schedule next zombie creation with increased delay LK.setTimeout(createZombie, 120000); // 120 seconds delay for next zombie } // Start the first rooster and create zombie spawnRooster(); // Delay the first zombie spawn by 40 seconds after game start LK.setTimeout(createZombie, 40000); // Zombie respawn is now handled after being killed by the player; // --- Time and Season System --- // --- Day and Season Variables --- var currentDay = storage.currentDay || 1; var currentSeason = storage.currentSeason || "Summer"; var SEASONS = ["Summer", "Autumn"]; var seasonIndex = SEASONS.indexOf(currentSeason); if (seasonIndex === -1) seasonIndex = 0; var autumnColors = [0xC97A3A, 0xB94E2A, 0xA65C1B, 0xE07B39, 0xD2691E, 0xB22222, 0x8B4513]; var autumnLeafAssets = []; // Will hold leaf particles var autumnLeavesActive = false; var autumnCropSlowdown = 2; // Crops grow 2x slower in autumn var autumnNightStartHour = 18; // Night starts earlier (not implemented, placeholder) var autumnGrassColor = 0xB97A56; // Dry grass color // --- UI Elements for Day and Season --- var dayTxt = new Text2('Day ' + currentDay, { size: 80, fill: "#fff" }); dayTxt.anchor.set(1, 0); dayTxt.x = 2048 - 40; // Right side, 40px padding dayTxt.y = 40; // Top, 40px padding game.addChild(dayTxt); var seasonTxt = new Text2(SEASONS[seasonIndex], { size: 80, fill: "#fff" }); seasonTxt.anchor.set(1, 0); seasonTxt.x = 2048 - 40; // Right side, 40px padding seasonTxt.y = 120; // Below day text game.addChild(seasonTxt); // --- Autumn Effects: Falling Leaves --- function spawnAutumnLeaves() { if (autumnLeavesActive) return; autumnLeavesActive = true; // Remove any old leaves for (var i = 0; i < autumnLeafAssets.length; ++i) { if (autumnLeafAssets[i] && autumnLeafAssets[i].parent) { try { autumnLeafAssets[i].destroy(); } catch (e) {} } } autumnLeafAssets = []; // Spawn 20 leaves at random positions at the top for (var i = 0; i < 20; ++i) { var color = autumnColors[Math.floor(Math.random() * autumnColors.length)]; var leaf = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.25 + Math.random() * 0.2, scaleY: 0.12 + Math.random() * 0.1, tint: color, alpha: 0.7 + Math.random() * 0.3, x: Math.random() * 2048, y: -30 - Math.random() * 100 }); leaf._fallSpeed = 1.5 + Math.random() * 1.5; leaf._drift = (Math.random() - 0.5) * 2; leaf._spin = (Math.random() - 0.5) * 0.1; game.addChild(leaf); autumnLeafAssets.push(leaf); } } // --- Remove Autumn Leaves --- function removeAutumnLeaves() { autumnLeavesActive = false; for (var i = 0; i < autumnLeafAssets.length; ++i) { if (autumnLeafAssets[i] && autumnLeafAssets[i].parent) { try { autumnLeafAssets[i].destroy(); } catch (e) {} } } autumnLeafAssets = []; } // --- Update Autumn Leaves --- function updateAutumnLeaves() { if (!autumnLeavesActive) return; for (var i = 0; i < autumnLeafAssets.length; ++i) { var leaf = autumnLeafAssets[i]; if (!leaf) continue; leaf.y += leaf._fallSpeed; leaf.x += leaf._drift; leaf.rotation += leaf._spin; // Respawn leaf at top if it falls below screen if (leaf.y > 2732 + 30) { leaf.y = -30 - Math.random() * 100; leaf.x = Math.random() * 2048; leaf._fallSpeed = 1.5 + Math.random() * 1.5; leaf._drift = (Math.random() - 0.5) * 2; leaf._spin = (Math.random() - 0.5) * 0.1; } } } // --- Crop Growth Slowdown Helper --- function getCropGrowthModifier() { return SEASONS[seasonIndex] === "Autumn" ? autumnCropSlowdown : 1; } // --- Update Day and Season --- function updateDayAndSeason() { currentDay++; // Change season every 3 days if (currentDay > 3) { currentDay = 1; seasonIndex = (seasonIndex + 1) % SEASONS.length; currentSeason = SEASONS[seasonIndex]; // Visual changes for each season if (currentSeason === "Autumn") { game.setBackgroundColor(autumnGrassColor); spawnAutumnLeaves(); } else { // Summer: restore green grass, remove leaves game.setBackgroundColor(0x4caf50); removeAutumnLeaves(); } } dayTxt.setText('Day ' + currentDay); seasonTxt.setText(currentSeason); storage.currentDay = currentDay; storage.currentSeason = currentSeason; } // --- Apply Crop Growth Slowdown in Autumn --- // Patch all crop regrowTime on season change function applySeasonalCropGrowth() { for (var i = 0; i < fields.length; ++i) { var f = fields[i]; for (var j = 0; j < f.wheats.length; ++j) { var crop = f.wheats[j]; if (typeof crop._baseRegrowTime === "undefined") { crop._baseRegrowTime = crop.regrowTime; } crop.regrowTime = crop._baseRegrowTime * getCropGrowthModifier(); } } } // --- Patch updateDayAndSeason to also update crop growth --- var _oldUpdateDayAndSeason = updateDayAndSeason; updateDayAndSeason = function updateDayAndSeason() { _oldUpdateDayAndSeason(); applySeasonalCropGrowth(); }; // --- Initial Season Visuals and Crop Growth --- if (currentSeason === "Autumn") { game.setBackgroundColor(autumnGrassColor); spawnAutumnLeaves(); } else { game.setBackgroundColor(0x4caf50); removeAutumnLeaves(); } applySeasonalCropGrowth(); // --- Set interval to update day and season every minute (for testing) --- LK.setInterval(updateDayAndSeason, 60000); // --- Patch main game update to animate autumn leaves --- var _oldGameUpdateForSeason = game.update; game.update = function () { if (typeof _oldGameUpdateForSeason === "function") _oldGameUpdateForSeason(); updateAutumnLeaves(); }; // Add Swipe Mode Button to the game UI var swipeModeButton = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, // Centered horizontally y: 2732 - 150, // 150 pixels above the bottom edge for better visibility // 100 pixels above the bottom edge scaleX: 4.5, // Width: 450 px for better visibility scaleY: 2.0, // Height: 200 px for better visibility // Height: 150 px tint: 0xFFD700, // Gold color alpha: 0.85, visible: money >= 10000 // Initially hidden if money is less than 10,000 }); game.addChild(swipeModeButton); var swipeModeText = new Text2('Automatic Collect\n$30,000', { size: 80, fill: 0x32CD32 // Bright green color }); swipeModeText.anchor.set(0.5, 0.5); swipeModeText.x = swipeModeButton.x; swipeModeText.y = swipeModeButton.y; swipeModeText.visible = money >= 10000; // Initially hidden if money is less than 10,000 game.addChild(swipeModeText); var swipeModeActive = false; var swipeModeUnlocked = false; // Track if the feature has been unlocked // Toggle Automatic Harvest Mode on button click swipeModeButton.down = function (x, y, obj) { if (!swipeModeUnlocked && money >= 30000) { money -= 30000; _updateMoneyDisplay(); swipeModeUnlocked = true; swipeModeActive = true; // Removed persistent storage update for swipeModeUnlocked swipeModeButton.tint = 0x00FF00; // Change to green when active swipeModeText.setText('Automatic Collect'); console.log("Automatic Collection Mode Activated"); } else if (swipeModeUnlocked) { swipeModeActive = !swipeModeActive; swipeModeButton.tint = swipeModeActive ? 0x00FF00 : 0xFFD700; // Toggle color swipeModeText.setText('Automatic Collect'); console.log(swipeModeActive ? "Automatic Collection Mode Activated" : "Automatic Collection Mode Deactivated"); } else { console.log("Not enough money to unlock Automatic Collection"); } }; // Update visibility of the button based on money function updateButtonVisibility() { if (swipeModeUnlocked) { swipeModeButton.visible = true; swipeModeText.visible = true; swipeModeText.setText('Automatic Collect'); } else if (money >= 30000) { swipeModeButton.visible = true; swipeModeText.visible = true; swipeModeText.setText('Unlock - $30,000'); } else { swipeModeButton.visible = false; swipeModeText.visible = false; } } // Call updateButtonVisibility whenever money changes _updateMoneyDisplay = function updateMoneyDisplay() { var previousMoney = moneyTxt.text; moneyTxt.setText('$' + money); if (moneyTxt.text !== previousMoney) { if (typeof missionBarFill !== "undefined") { var progress = Math.max(0, Math.min(1, money / 100000)); missionBarFill.scaleX = missionBarFillMaxScale * progress; } if (money >= 100000 && !game._missionWinShown) { game._missionWinShown = true; LK.showYouWin(); farmer.x = centerX; farmer.y = centerY - 120; money = 0; _updateMoneyDisplay(); } updateButtonVisibility(); // Check button visibility } };
===================================================================
--- original.js
+++ change.js
@@ -1397,8 +1397,27 @@
for (var i = 0; i < zombies.length; i++) {
zombies[i].update();
}
};
+// Automatic Collect Timer
+var autoCollectInterval = 5000; // 5 seconds interval for automatic collection
+var autoCollectTimer = LK.setInterval(function () {
+ if (swipeModeActive) {
+ for (var i = 0; i < fields.length; ++i) {
+ var f = fields[i];
+ if (f.locked) continue;
+ f.wheats.forEach(function (wheat) {
+ if (wheat.isHarvestable()) {
+ wheat.setHarvested(true);
+ var reward = 100 * (FIELD_REWARD_MULT[wheat.fieldIndex] || 1);
+ money += reward;
+ _updateMoneyDisplay();
+ LK.effects.flashObject(wheat, 0xffff00, 300);
+ }
+ });
+ }
+ }
+}, autoCollectInterval);
// --- Create areas and place animals ---
// Calculate center of game screen
var gameWidth = 2048;
var gameHeight = 2732;
@@ -1949,19 +1968,22 @@
}
}
// Call updateButtonVisibility whenever money changes
_updateMoneyDisplay = function updateMoneyDisplay() {
+ var previousMoney = moneyTxt.text;
moneyTxt.setText('$' + money);
- if (typeof missionBarFill !== "undefined") {
- var progress = Math.max(0, Math.min(1, money / 100000));
- missionBarFill.scaleX = missionBarFillMaxScale * progress;
+ if (moneyTxt.text !== previousMoney) {
+ if (typeof missionBarFill !== "undefined") {
+ var progress = Math.max(0, Math.min(1, money / 100000));
+ missionBarFill.scaleX = missionBarFillMaxScale * progress;
+ }
+ if (money >= 100000 && !game._missionWinShown) {
+ game._missionWinShown = true;
+ LK.showYouWin();
+ farmer.x = centerX;
+ farmer.y = centerY - 120;
+ money = 0;
+ _updateMoneyDisplay();
+ }
+ updateButtonVisibility(); // Check button visibility
}
- if (money >= 100000 && !game._missionWinShown) {
- game._missionWinShown = true;
- LK.showYouWin();
- farmer.x = centerX;
- farmer.y = centerY - 120;
- money = 0;
- _updateMoneyDisplay();
- }
- updateButtonVisibility(); // Check button visibility
};
\ No newline at end of file