User prompt
Please fix the bug: 'TypeError: animals[i].update is not a function' in or related to this line: 'animals[i].update();' Line Number: 1120
User prompt
Create a new tab named "Animal Left". Make it able to move as I described before.
User prompt
Create a new animation named "Rooster Animation" and add it into the game.
User prompt
I want to add a rooster to my game. It will move slowly with animation. It should start from the normal position. It will go right, then left, then down. This will repeat in a loop. I will add 4 animation images. The rooster will switch between these 4 images in a loop while walking. The old image will not be removed, just changed to the next one.
User prompt
I will add the animation images myself. When the rooster moves, it should remove the old image and show the new one. There will be 4 images for the walking animation. I will add these images. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I will add the images myself. The rooster should start from the left side. It should move slowly with animation. The movement should look smooth. While walking, it should change between 4 images (walking animation). It should move around the screen in a loop.
User prompt
I want the rooster to move around the whole screen. It should start at the top middle of the screen. Then go to the right side. After that, go to the far left side. Then move down. It should do this in a loop, slowly. I will add walking animation using images. There will be 4 images, and the rooster should change its image while walking.
User prompt
I will add the rooster's images myself. When the character walks, it will switch to another image. The rooster should be able to walk around the whole game map.
User prompt
I want to add a rooster to my game. It will be moving, but I will add the animation myself. The rooster will have 4 images. As it walks forward, the image will change.
User prompt
Please fix the bug: 'TypeError: sun.update is not a function' in or related to this line: 'sun.update();' Line Number: 1213
User prompt
Please fix the bug: 'TypeError: sun.update is not a function' in or related to this line: 'sun.update();' Line Number: 1213
User prompt
Hey Upit, I will add the sun and moon as images myself. Please do this: Show the sun image at the top center when the game starts. After 2 minutes, slowly fade out the sun image, and show the moon image in the same place. When the moon appears, make the environment a bit darker, but still visible. After another 2 minutes, fade out the moon and bring back the sun. Repeat this in a loop (sun > moon > sun...). Thanks!
User prompt
Hey Upit, Please add a simple sun and moon system: When the game starts, the sun should appear at the top center of the screen. After 2 minutes, the sun should slowly fade out, and the moon should appear in the same top center position. When the moon appears, make the environment slightly darker, but not too dark — players should still see clearly. After another 2 minutes, the moon should fade out and the sun should come back, making the game bright again. This should repeat in a loop (sun > moon > sun...). Thanks!
User prompt
delete rain
User prompt
Hey Upit, Please add rain to the game that starts 2 minutes after the game begins. The rain should last for a while, then stop and disappear automatically. Thanks!
User prompt
Hey Upit, Please add rain to the game that starts 2 minutes after the game begins. The rain should last for some time and look natural. Thanks!
User prompt
Hey Upit, Please make 2 clouds start from the left side of the screen and move slowly all the way to the far right edge of the screen. They should appear near the top and disappear after reaching the right edge. Make them a little more separated from each other — not too close, but still near. Also, one cloud should be slightly in front, and the other slightly behind (like layers). Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hey Upit, Please make 2 clouds that start from the left side of the screen and move slowly to the right side, finishing at the right edge. They should be close to each other, but one cloud should be slightly in front and the other a bit behind (like layers). Make them appear near the top of the screen. Thanks!
User prompt
Hey Upit, Please make the 2 clouds move only from left to right (no going back). Make them appear a bit higher on the screen (more at the top). They should move slowly and stay longer before disappearing. Also, keep some space between the two clouds. Thanks!
User prompt
Hey Upit, Please make the 2 clouds move slower from left to right and back. Increase their visible time so they stay longer before disappearing. Also, make sure the clouds are a bit more separated, not right next to each other. Thanks!
User prompt
Hey Upit, Please create 2 clouds that start from the left side of the screen and move slowly to the right side. They should move back and forth smoothly between left and right edges. Make sure there is a small space between the two clouds, but they shouldn’t be too far apart. The clouds should move like this for 10 seconds, then disappear. Thanks!
User prompt
Hey Upit, Please create 2 clouds that move slowly left and right across the entire screen width. Each cloud should appear, move back and forth for 10 seconds, then disappear. Make it simple and smooth. Thanks!
User prompt
Hey Upit, Please create a simple cloud system with 2 clouds on the screen. Each cloud should stay visible for 5 seconds, then disappear. The clouds should move slowly left and right (back and forth) while visible. Make it very simple, just basic movement animation. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hey Upit, Please remove the shop completely from the game. Do not open or show the shop anymore. The shop system should be totally disabled or deleted. Thanks!
User prompt
Hey Upit, Please fix the shop step by step: Add a big “Close” button that closes the shop when clicked or tapped. While the shop is open, disable player movement so clicking works properly. After closing, allow the player to move again. Also, check if our system has any errors causing the issue. Thank you!
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ 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; }); // 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; }); // 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); } }; 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; }); // ShopButton class for shop functionality var ShopButton = Container.expand(function () { var self = Container.call(this); // Create shop button with larger text for better visibility var shopBtn = new Text2('Shop', { size: 120, // Increased text size for mobile fill: 0xFFFFFF }); shopBtn.anchor.set(0.5, 0.5); self.addChild(shopBtn); // Create larger background for shop button (better touch target) var btnBg = LK.getAsset('rect', { anchorX: 0.5, anchorY: 0.5, width: 280, // Wider button for easier mobile tapping height: 140, // Taller button for easier mobile tapping tint: 0x3e8a2e }); self.addChildAt(btnBg, 0); // Panel elements self.panel = new Container(); self.panel.visible = false; self.panel.x = 1024; // Center horizontally on screen self.panel.y = 1366; // Center vertically on screen // Track shop open state for blocking player movement self.isShopOpen = false; game.addChild(self.panel); // Panel background - made larger for mobile var panelBg = LK.getAsset('rect', { anchorX: 0.5, anchorY: 0.5, width: 1600, // Wider panel for mobile height: 1800, // Taller panel for better mobile spacing tint: 0x3e8a2e }); self.panel.addChild(panelBg); // Panel title - larger text var title = new Text2('Sickle Shop', { size: 100, // Larger title text for mobile fill: 0xFFFFFF }); title.anchor.set(0.5, 0); title.y = -800; // Moved up to accommodate larger panel self.panel.addChild(title); // Close button - larger and more prominent var closeBtn = new Text2('CLOSE', { size: 100, // Larger text for mobile visibility fill: 0xFFFFFF }); closeBtn.anchor.set(0.5, 0.5); closeBtn.x = 0; // Centered at bottom of panel closeBtn.y = 750; // At bottom of panel self.panel.addChild(closeBtn); // Close button background - large red box for better visibility and touch target var closeBtnBg = LK.getAsset('rect', { anchorX: 0.5, anchorY: 0.5, width: 500, // Very wide background for easy mobile tapping height: 150, // Tall background for easy mobile tapping tint: 0xff0000, // Bright red color to stand out as close button x: 0, // Centered horizontally y: 750 // At bottom of panel }); self.panel.addChildAt(closeBtnBg, self.panel.children.indexOf(closeBtn)); // Also keep X button at top for multiple close options var xBtn = new Text2('X', { size: 120, // Larger text for mobile visibility fill: 0xFFFFFF }); xBtn.anchor.set(0.5, 0.5); xBtn.x = 700; // Positioned further to the right xBtn.y = -800; // Aligned with title self.panel.addChild(xBtn); // X button background - larger for better touch target var xBtnBg = LK.getAsset('rect', { anchorX: 0.5, anchorY: 0.5, width: 140, // Larger background for mobile height: 140, // Larger background for mobile tint: 0xff5555, // Red color to stand out as close button x: 700, // Match X position y: -800 // Match Y position }); self.panel.addChildAt(xBtnBg, self.panel.children.indexOf(xBtn)); // Sickle items var sickleTypes = [{ name: "Basic Sickle", price: 0, imageId: 'sickle', tint: 0xB8A677 }, { name: "Stone Sickle", price: 1000, imageId: 'sickle', tint: 0x777777 }, { name: "Iron Sickle", price: 5000, imageId: 'sickle', tint: 0xCCCCCC }, { name: "Gold Sickle", price: 20000, imageId: 'sickle', tint: 0xFFD700 }, { name: "Diamond Sickle", price: 50000, imageId: 'sickle', tint: 0x89CFF0 }]; // Create sickle items with more spacing and larger UI elements for mobile for (var i = 0; i < sickleTypes.length; i++) { var item = sickleTypes[i]; var y = -500 + i * 220; // Much more vertical spacing for better mobile touch targets // Sickle image with tint - larger image var sickleImg = LK.getAsset('sickle', { anchorX: 0.5, anchorY: 0.5, x: -400, // Moved further left for wider panel y: y, scaleX: 2.0, // Much larger for mobile visibility scaleY: 2.0, // Much larger for mobile visibility tint: item.tint || 0xFFFFFF }); self.panel.addChild(sickleImg); // Sickle name - larger text var nameText = new Text2(item.name, { size: 70, // Larger text size for mobile fill: 0xFFFFFF }); nameText.anchor.set(0, 0.5); nameText.x = -280; // Adjusted position nameText.y = y; self.panel.addChild(nameText); // Buy button - larger text var buyText = item.price === 0 ? "Owned" : "Buy $" + item.price; var buyBtn = new Text2(buyText, { size: 70, // Larger text size for mobile fill: 0xFFFFFF }); buyBtn.anchor.set(0.5, 0.5); buyBtn.x = 450; // Moved further right for wider panel buyBtn.y = y; buyBtn.interactive = true; buyBtn.sickleIndex = i; buyBtn.price = item.price; self.panel.addChild(buyBtn); // Buy button background - larger for better touch target on mobile var buyBtnBg = LK.getAsset('rect', { anchorX: 0.5, anchorY: 0.5, width: 300, // Much wider button for mobile height: 120, // Much taller button for mobile tint: item.price === 0 ? 0x888888 : 0x326b23, x: 450, // Match position with text y: y }); self.panel.addChildAt(buyBtnBg, self.panel.children.indexOf(buyBtn)); } // Toggle panel visibility self.togglePanel = function () { self.panel.visible = !self.panel.visible; self.isShopOpen = self.panel.visible; // Signal that a UI interaction occurred, to prevent game movement for this click. playerMovementBlockedByUIClick = true; }; // Event handlers self.down = function (x, y, obj) { // x, y are global click coordinates. // If panel is not visible, this click is on the ShopButton itself to open/toggle the panel. if (!self.panel.visible) { // A more precise hit-test for the actual shop button graphics could be added here // if the ShopButton container itself is much larger than its visual. // For now, assume any click on the ShopButton object when panel is closed, opens it. self.togglePanel(); // This handles visibility, state, and sets playerMovementBlockedByUIClick return; } // Panel is visible. Check for clicks on panel elements. // Panel's origin (self.panel.x, self.panel.y) is its center due to panelBg's anchor. var panelCenterX = self.panel.x; var panelCenterY = self.panel.y; // Hit test for X button (top right of panel) // xBtn and xBtnBg are defined in ShopButton's scope. xBtn local pos: (700, -800) var xBtnGlobalX = panelCenterX + xBtn.x; var xBtnGlobalY = panelCenterY + xBtn.y; if (Math.abs(x - xBtnGlobalX) < xBtnBg.width / 2 && Math.abs(y - xBtnGlobalY) < xBtnBg.height / 2) { self.togglePanel(); // Handles visibility, state, and sets playerMovementBlockedByUIClick return; } // Hit test for big red "CLOSE" button (bottom of panel) // closeBtn and closeBtnBg are defined in ShopButton's scope. closeBtn local pos: (0, 750) var closeBtnGlobalX = panelCenterX + closeBtn.x; var closeBtnGlobalY = panelCenterY + closeBtn.y; if (Math.abs(x - closeBtnGlobalX) < closeBtnBg.width / 2 && Math.abs(y - closeBtnGlobalY) < closeBtnBg.height / 2) { self.togglePanel(); // Handles visibility, state, and sets playerMovementBlockedByUIClick return; } // Hit test for sickle items (buy buttons or select owned) // panelPos referenced in original code for itemY is effectively panelCenterY for (var i = 0; i < sickleTypes.length; i++) { var itemRelY = -500 + i * 220; // Relative Y of item row in panel from panel center var itemRowGlobalY = panelCenterY + itemRelY; var rowHitHeight = 110; // Half-height for hit testing the row // Check if click is vertically within this item's row if (y >= itemRowGlobalY - rowHitHeight && y <= itemRowGlobalY + rowHitHeight) { // Click is in the row, now check if it's on an interactive part. if (sickleTypes[i].price === 0) { // Item is owned - click anywhere in row selects it self.displaySickle(i); LK.effects.flashScreen(0x00ff00, 200); // Flash for selection self.panel.visible = false; // Close panel self.isShopOpen = false; playerMovementBlockedByUIClick = true; // Signal UI handled click return; } else { // Item is not owned - check if click is on Buy button // Buy button relative X is 450 from panel center. Hit width assumed 150 (half of 300) var buyBtnGlobalX = panelCenterX + 450; var buyBtnHitRadiusX = 150; // Half of buyBtnBg width (300) if (Math.abs(x - buyBtnGlobalX) < buyBtnHitRadiusX) { self.onBuy(i, sickleTypes[i].price); // onBuy will handle panel closing and flag setting return; } } } } // If the click was on the panel's background (but not on an interactive element) // panelBg is centered at panel's origin, dimensions 1600x1800 if (Math.abs(x - panelCenterX) < panelBg.width / 2 && Math.abs(y - panelCenterY) < panelBg.height / 2) { playerMovementBlockedByUIClick = true; // Consume click on panel background return; } // If click was not on any recognized part of the shop button or panel, // it will fall through, and playerMovementBlockedByUIClick remains false (unless set elsewhere). }; // Display current sickle self.displaySickle = function (index) { if (index >= 0 && index < sickleTypes.length) { // Apply sickle customization to player's sickle if (sickle) { // Remove old sickle farmer.removeChild(sickle); // Create new sickle with custom tint sickle = LK.getAsset(sickleTypes[index].imageId, { anchorX: 0.2, anchorY: 0.7, x: 0, y: 30, tint: sickleTypes[index].tint }); farmer.addChild(sickle); } } }; // Buy sickle handler self.onBuy = function (index, price) { // Skip if already owned (price 0) if (price === 0) return; // Check if player has enough money if (money >= price) { // Subtract money money -= price; updateMoneyDisplay(); // Update button to "Owned" var btnCount = 0; for (var c = 0; c < self.panel.children.length; c++) { var child = self.panel.children[c]; if (child && child.setText && child.text && (child.text.indexOf("Buy") === 0 || child.text === "Owned")) { if (btnCount === index) { child.setText("Owned"); // Update button background // The background is always just before the button in children if (c > 0 && self.panel.children[c - 1] && self.panel.children[c - 1].tint !== undefined) { self.panel.children[c - 1].tint = 0x888888; } break; } btnCount++; } } // Set price to 0 (owned) sickleTypes[index].price = 0; // Apply sickle customization to player's sickle if (sickle) { // Remove old sickle farmer.removeChild(sickle); // Create new sickle with custom tint sickle = LK.getAsset(sickleTypes[index].imageId, { anchorX: 0.2, anchorY: 0.7, x: 0, y: 30, tint: sickleTypes[index].tint }); farmer.addChild(sickle); } // Flash screen green for successful purchase LK.effects.flashScreen(0x00ff00, 300); // Close shop panel immediately after purchase self.panel.visible = false; self.isShopOpen = false; playerMovementBlockedByUIClick = true; // Signal UI handled click } else { // Not enough money, flash red LK.effects.flashScreen(0xff0000, 300); playerMovementBlockedByUIClick = true; // Signal UI handled click (even if purchase failed) } }; 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; }); /**** * 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 --- 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); // --- 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); } // 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; farmer.addChild(sickle); // --- Money display --- moneyTxt = new Text2('$0', { size: 100, fill: "#fff" }); moneyTxt.anchor.set(0.5, 0); LK.gui.top.addChild(moneyTxt); // --- Helper: update money display --- function updateMoneyDisplay() { moneyTxt.setText('$' + money); } // --- 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) { // If UI handled this click (e.g., shop interaction), do nothing for game movement. if (playerMovementBlockedByUIClick) { playerMovementBlockedByUIClick = false; // Reset flag for next input return; } // If shop is open (and click wasn't consumed by panel interaction above), block game actions. // This handles cases like clicking outside the panel while it's open. if (shopButton && shopButton.isShopOpen) { return; } // If shop is closed, but the click is on the ShopButton itself (to open it), // ShopButton.down will handle it and set playerMovementBlockedByUIClick. // This check here ensures game.down doesn't proceed if the click was on the shop button. // shopButton (the button instance) global pos: shopButton.x, shopButton.y // shopButton's background (btnBg) is 280x140, centered on shopButton.x,y if (shopButton && Math.abs(x - shopButton.x) < shopButton.getChildAt(0).width / 2 && // Assuming btnBg is child 0 and has width Math.abs(y - shopButton.y) < shopButton.getChildAt(0).height / 2) { // Assuming btnBg is child 0 and has height // Click was on the main shop button. ShopButton.down will handle it. // playerMovementBlockedByUIClick will be set by ShopButton's togglePanel. // We can return here as well, as ShopButton.down will be invoked for this click. return; } 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; // Animate sickle (in farmer's hand) tween(sickle, { rotation: Math.PI * 2 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { sickle.rotation = 0; // 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; } // Block movement if shop is open if (shopButton && shopButton.isShopOpen) { return; // Don't process movement when shop is open } 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) { // If UI interaction blocked the 'down' event, 'up' should also be controlled. if (playerMovementBlockedByUIClick) { playerMovementBlockedByUIClick = false; // Reset flag here as well return; } // Block up events if shop is open if (shopButton && shopButton.isShopOpen) { // It's possible playerMovementBlockedByUIClick was already true if shop was just closed. // This ensures if shop is still open (e.g. click missed UI elements), up is blocked. return; } dragging = false; harvestMode = false; harvestWheat = null; }; // --- Main update loop --- game.update = function () { // Update farmer farmer.update(); // Update wheat regrow for (var i = 0; i < fields.length; ++i) { var f = fields[i]; for (var j = 0; j < f.wheats.length; ++j) { f.wheats[j].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 right edge of screen, centered vertically var animalRight = new Animal(); animalRight.setAnimalImage('animal_right'); animalRight.name = "Animal_Right"; animalRight.x = gameWidth; // Position at right edge animalRight.y = gameCenterY; // Center vertically game.addChild(animalRight); // Add directly to game instead of areaRight animals.push(animalRight); // Area_Bottom has no animal // --- Create shop button --- var shopButton = new ShopButton(); shopButton.x = 2048 - 150; // Position on right side of screen with spacing from edge shopButton.y = gameCenterY; // Position at vertical center game.addChild(shopButton); // --- 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);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
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;
});
// 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;
});
// 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);
}
};
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;
});
// ShopButton class for shop functionality
var ShopButton = Container.expand(function () {
var self = Container.call(this);
// Create shop button with larger text for better visibility
var shopBtn = new Text2('Shop', {
size: 120,
// Increased text size for mobile
fill: 0xFFFFFF
});
shopBtn.anchor.set(0.5, 0.5);
self.addChild(shopBtn);
// Create larger background for shop button (better touch target)
var btnBg = LK.getAsset('rect', {
anchorX: 0.5,
anchorY: 0.5,
width: 280,
// Wider button for easier mobile tapping
height: 140,
// Taller button for easier mobile tapping
tint: 0x3e8a2e
});
self.addChildAt(btnBg, 0);
// Panel elements
self.panel = new Container();
self.panel.visible = false;
self.panel.x = 1024; // Center horizontally on screen
self.panel.y = 1366; // Center vertically on screen
// Track shop open state for blocking player movement
self.isShopOpen = false;
game.addChild(self.panel);
// Panel background - made larger for mobile
var panelBg = LK.getAsset('rect', {
anchorX: 0.5,
anchorY: 0.5,
width: 1600,
// Wider panel for mobile
height: 1800,
// Taller panel for better mobile spacing
tint: 0x3e8a2e
});
self.panel.addChild(panelBg);
// Panel title - larger text
var title = new Text2('Sickle Shop', {
size: 100,
// Larger title text for mobile
fill: 0xFFFFFF
});
title.anchor.set(0.5, 0);
title.y = -800; // Moved up to accommodate larger panel
self.panel.addChild(title);
// Close button - larger and more prominent
var closeBtn = new Text2('CLOSE', {
size: 100,
// Larger text for mobile visibility
fill: 0xFFFFFF
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = 0; // Centered at bottom of panel
closeBtn.y = 750; // At bottom of panel
self.panel.addChild(closeBtn);
// Close button background - large red box for better visibility and touch target
var closeBtnBg = LK.getAsset('rect', {
anchorX: 0.5,
anchorY: 0.5,
width: 500,
// Very wide background for easy mobile tapping
height: 150,
// Tall background for easy mobile tapping
tint: 0xff0000,
// Bright red color to stand out as close button
x: 0,
// Centered horizontally
y: 750 // At bottom of panel
});
self.panel.addChildAt(closeBtnBg, self.panel.children.indexOf(closeBtn));
// Also keep X button at top for multiple close options
var xBtn = new Text2('X', {
size: 120,
// Larger text for mobile visibility
fill: 0xFFFFFF
});
xBtn.anchor.set(0.5, 0.5);
xBtn.x = 700; // Positioned further to the right
xBtn.y = -800; // Aligned with title
self.panel.addChild(xBtn);
// X button background - larger for better touch target
var xBtnBg = LK.getAsset('rect', {
anchorX: 0.5,
anchorY: 0.5,
width: 140,
// Larger background for mobile
height: 140,
// Larger background for mobile
tint: 0xff5555,
// Red color to stand out as close button
x: 700,
// Match X position
y: -800 // Match Y position
});
self.panel.addChildAt(xBtnBg, self.panel.children.indexOf(xBtn));
// Sickle items
var sickleTypes = [{
name: "Basic Sickle",
price: 0,
imageId: 'sickle',
tint: 0xB8A677
}, {
name: "Stone Sickle",
price: 1000,
imageId: 'sickle',
tint: 0x777777
}, {
name: "Iron Sickle",
price: 5000,
imageId: 'sickle',
tint: 0xCCCCCC
}, {
name: "Gold Sickle",
price: 20000,
imageId: 'sickle',
tint: 0xFFD700
}, {
name: "Diamond Sickle",
price: 50000,
imageId: 'sickle',
tint: 0x89CFF0
}];
// Create sickle items with more spacing and larger UI elements for mobile
for (var i = 0; i < sickleTypes.length; i++) {
var item = sickleTypes[i];
var y = -500 + i * 220; // Much more vertical spacing for better mobile touch targets
// Sickle image with tint - larger image
var sickleImg = LK.getAsset('sickle', {
anchorX: 0.5,
anchorY: 0.5,
x: -400,
// Moved further left for wider panel
y: y,
scaleX: 2.0,
// Much larger for mobile visibility
scaleY: 2.0,
// Much larger for mobile visibility
tint: item.tint || 0xFFFFFF
});
self.panel.addChild(sickleImg);
// Sickle name - larger text
var nameText = new Text2(item.name, {
size: 70,
// Larger text size for mobile
fill: 0xFFFFFF
});
nameText.anchor.set(0, 0.5);
nameText.x = -280; // Adjusted position
nameText.y = y;
self.panel.addChild(nameText);
// Buy button - larger text
var buyText = item.price === 0 ? "Owned" : "Buy $" + item.price;
var buyBtn = new Text2(buyText, {
size: 70,
// Larger text size for mobile
fill: 0xFFFFFF
});
buyBtn.anchor.set(0.5, 0.5);
buyBtn.x = 450; // Moved further right for wider panel
buyBtn.y = y;
buyBtn.interactive = true;
buyBtn.sickleIndex = i;
buyBtn.price = item.price;
self.panel.addChild(buyBtn);
// Buy button background - larger for better touch target on mobile
var buyBtnBg = LK.getAsset('rect', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
// Much wider button for mobile
height: 120,
// Much taller button for mobile
tint: item.price === 0 ? 0x888888 : 0x326b23,
x: 450,
// Match position with text
y: y
});
self.panel.addChildAt(buyBtnBg, self.panel.children.indexOf(buyBtn));
}
// Toggle panel visibility
self.togglePanel = function () {
self.panel.visible = !self.panel.visible;
self.isShopOpen = self.panel.visible;
// Signal that a UI interaction occurred, to prevent game movement for this click.
playerMovementBlockedByUIClick = true;
};
// Event handlers
self.down = function (x, y, obj) {
// x, y are global click coordinates.
// If panel is not visible, this click is on the ShopButton itself to open/toggle the panel.
if (!self.panel.visible) {
// A more precise hit-test for the actual shop button graphics could be added here
// if the ShopButton container itself is much larger than its visual.
// For now, assume any click on the ShopButton object when panel is closed, opens it.
self.togglePanel(); // This handles visibility, state, and sets playerMovementBlockedByUIClick
return;
}
// Panel is visible. Check for clicks on panel elements.
// Panel's origin (self.panel.x, self.panel.y) is its center due to panelBg's anchor.
var panelCenterX = self.panel.x;
var panelCenterY = self.panel.y;
// Hit test for X button (top right of panel)
// xBtn and xBtnBg are defined in ShopButton's scope. xBtn local pos: (700, -800)
var xBtnGlobalX = panelCenterX + xBtn.x;
var xBtnGlobalY = panelCenterY + xBtn.y;
if (Math.abs(x - xBtnGlobalX) < xBtnBg.width / 2 && Math.abs(y - xBtnGlobalY) < xBtnBg.height / 2) {
self.togglePanel(); // Handles visibility, state, and sets playerMovementBlockedByUIClick
return;
}
// Hit test for big red "CLOSE" button (bottom of panel)
// closeBtn and closeBtnBg are defined in ShopButton's scope. closeBtn local pos: (0, 750)
var closeBtnGlobalX = panelCenterX + closeBtn.x;
var closeBtnGlobalY = panelCenterY + closeBtn.y;
if (Math.abs(x - closeBtnGlobalX) < closeBtnBg.width / 2 && Math.abs(y - closeBtnGlobalY) < closeBtnBg.height / 2) {
self.togglePanel(); // Handles visibility, state, and sets playerMovementBlockedByUIClick
return;
}
// Hit test for sickle items (buy buttons or select owned)
// panelPos referenced in original code for itemY is effectively panelCenterY
for (var i = 0; i < sickleTypes.length; i++) {
var itemRelY = -500 + i * 220; // Relative Y of item row in panel from panel center
var itemRowGlobalY = panelCenterY + itemRelY;
var rowHitHeight = 110; // Half-height for hit testing the row
// Check if click is vertically within this item's row
if (y >= itemRowGlobalY - rowHitHeight && y <= itemRowGlobalY + rowHitHeight) {
// Click is in the row, now check if it's on an interactive part.
if (sickleTypes[i].price === 0) {
// Item is owned - click anywhere in row selects it
self.displaySickle(i);
LK.effects.flashScreen(0x00ff00, 200); // Flash for selection
self.panel.visible = false; // Close panel
self.isShopOpen = false;
playerMovementBlockedByUIClick = true; // Signal UI handled click
return;
} else {
// Item is not owned - check if click is on Buy button
// Buy button relative X is 450 from panel center. Hit width assumed 150 (half of 300)
var buyBtnGlobalX = panelCenterX + 450;
var buyBtnHitRadiusX = 150; // Half of buyBtnBg width (300)
if (Math.abs(x - buyBtnGlobalX) < buyBtnHitRadiusX) {
self.onBuy(i, sickleTypes[i].price); // onBuy will handle panel closing and flag setting
return;
}
}
}
}
// If the click was on the panel's background (but not on an interactive element)
// panelBg is centered at panel's origin, dimensions 1600x1800
if (Math.abs(x - panelCenterX) < panelBg.width / 2 && Math.abs(y - panelCenterY) < panelBg.height / 2) {
playerMovementBlockedByUIClick = true; // Consume click on panel background
return;
}
// If click was not on any recognized part of the shop button or panel,
// it will fall through, and playerMovementBlockedByUIClick remains false (unless set elsewhere).
};
// Display current sickle
self.displaySickle = function (index) {
if (index >= 0 && index < sickleTypes.length) {
// Apply sickle customization to player's sickle
if (sickle) {
// Remove old sickle
farmer.removeChild(sickle);
// Create new sickle with custom tint
sickle = LK.getAsset(sickleTypes[index].imageId, {
anchorX: 0.2,
anchorY: 0.7,
x: 0,
y: 30,
tint: sickleTypes[index].tint
});
farmer.addChild(sickle);
}
}
};
// Buy sickle handler
self.onBuy = function (index, price) {
// Skip if already owned (price 0)
if (price === 0) return;
// Check if player has enough money
if (money >= price) {
// Subtract money
money -= price;
updateMoneyDisplay();
// Update button to "Owned"
var btnCount = 0;
for (var c = 0; c < self.panel.children.length; c++) {
var child = self.panel.children[c];
if (child && child.setText && child.text && (child.text.indexOf("Buy") === 0 || child.text === "Owned")) {
if (btnCount === index) {
child.setText("Owned");
// Update button background
// The background is always just before the button in children
if (c > 0 && self.panel.children[c - 1] && self.panel.children[c - 1].tint !== undefined) {
self.panel.children[c - 1].tint = 0x888888;
}
break;
}
btnCount++;
}
}
// Set price to 0 (owned)
sickleTypes[index].price = 0;
// Apply sickle customization to player's sickle
if (sickle) {
// Remove old sickle
farmer.removeChild(sickle);
// Create new sickle with custom tint
sickle = LK.getAsset(sickleTypes[index].imageId, {
anchorX: 0.2,
anchorY: 0.7,
x: 0,
y: 30,
tint: sickleTypes[index].tint
});
farmer.addChild(sickle);
}
// Flash screen green for successful purchase
LK.effects.flashScreen(0x00ff00, 300);
// Close shop panel immediately after purchase
self.panel.visible = false;
self.isShopOpen = false;
playerMovementBlockedByUIClick = true; // Signal UI handled click
} else {
// Not enough money, flash red
LK.effects.flashScreen(0xff0000, 300);
playerMovementBlockedByUIClick = true; // Signal UI handled click (even if purchase failed)
}
};
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;
});
/****
* 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 ---
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);
// --- 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);
}
// 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;
farmer.addChild(sickle);
// --- Money display ---
moneyTxt = new Text2('$0', {
size: 100,
fill: "#fff"
});
moneyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moneyTxt);
// --- Helper: update money display ---
function updateMoneyDisplay() {
moneyTxt.setText('$' + money);
}
// --- 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) {
// If UI handled this click (e.g., shop interaction), do nothing for game movement.
if (playerMovementBlockedByUIClick) {
playerMovementBlockedByUIClick = false; // Reset flag for next input
return;
}
// If shop is open (and click wasn't consumed by panel interaction above), block game actions.
// This handles cases like clicking outside the panel while it's open.
if (shopButton && shopButton.isShopOpen) {
return;
}
// If shop is closed, but the click is on the ShopButton itself (to open it),
// ShopButton.down will handle it and set playerMovementBlockedByUIClick.
// This check here ensures game.down doesn't proceed if the click was on the shop button.
// shopButton (the button instance) global pos: shopButton.x, shopButton.y
// shopButton's background (btnBg) is 280x140, centered on shopButton.x,y
if (shopButton && Math.abs(x - shopButton.x) < shopButton.getChildAt(0).width / 2 &&
// Assuming btnBg is child 0 and has width
Math.abs(y - shopButton.y) < shopButton.getChildAt(0).height / 2) {
// Assuming btnBg is child 0 and has height
// Click was on the main shop button. ShopButton.down will handle it.
// playerMovementBlockedByUIClick will be set by ShopButton's togglePanel.
// We can return here as well, as ShopButton.down will be invoked for this click.
return;
}
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;
// Animate sickle (in farmer's hand)
tween(sickle, {
rotation: Math.PI * 2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
sickle.rotation = 0;
// 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;
}
// Block movement if shop is open
if (shopButton && shopButton.isShopOpen) {
return; // Don't process movement when shop is open
}
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) {
// If UI interaction blocked the 'down' event, 'up' should also be controlled.
if (playerMovementBlockedByUIClick) {
playerMovementBlockedByUIClick = false; // Reset flag here as well
return;
}
// Block up events if shop is open
if (shopButton && shopButton.isShopOpen) {
// It's possible playerMovementBlockedByUIClick was already true if shop was just closed.
// This ensures if shop is still open (e.g. click missed UI elements), up is blocked.
return;
}
dragging = false;
harvestMode = false;
harvestWheat = null;
};
// --- Main update loop ---
game.update = function () {
// Update farmer
farmer.update();
// Update wheat regrow
for (var i = 0; i < fields.length; ++i) {
var f = fields[i];
for (var j = 0; j < f.wheats.length; ++j) {
f.wheats[j].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 right edge of screen, centered vertically
var animalRight = new Animal();
animalRight.setAnimalImage('animal_right');
animalRight.name = "Animal_Right";
animalRight.x = gameWidth; // Position at right edge
animalRight.y = gameCenterY; // Center vertically
game.addChild(animalRight); // Add directly to game instead of areaRight
animals.push(animalRight);
// Area_Bottom has no animal
// --- Create shop button ---
var shopButton = new ShopButton();
shopButton.x = 2048 - 150; // Position on right side of screen with spacing from edge
shopButton.y = gameCenterY; // Position at vertical center
game.addChild(shopButton);
// --- 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);