User prompt
Make the grocery text big bold and black as well with button text
User prompt
Make th button it's own asset
User prompt
Make a button asset
User prompt
Make the buttons a square sprite
User prompt
Make a friend who if you crash into them you have to decide which phrase is nicer to say to them and there's multiple scenarios ex: "Hi, how are you?" or "Hello amigo how are you on this wonderful day?" correct answer: 1
User prompt
Make the background white
User prompt
Add. Lives count for touching obstacles and walls, but demons and shoppers still auto kill
User prompt
Please fix the bug: 'TypeError: obstacles[j].update is not a function. (In 'obstacles[j].update()', 'obstacles[j].update' is undefined)' in or related to this line: 'obstacles[j].update();' Line Number: 1426
User prompt
Please fix the bug: 'TypeError: obstacles[j].update is not a function. (In 'obstacles[j].update()', 'obstacles[j].update' is undefined)' in or related to this line: 'obstacles[j].update();' Line Number: 1426
User prompt
Add walls for extra difficulty on Karen mode an prevent item from spawning in them
User prompt
Please fix the bug: 'Can't find variable: menuBg' in or related to this line: 'logo.x = menuBg.width / 2;' Line Number: 257
User prompt
There is a giant obstacle in the background of the main menu, please remove it
User prompt
Make it smaller by width and a little taller by height
User prompt
Make the play bottom smaller by a ton
User prompt
Please fix the bug: 'undefined is not an object (evaluating 'self.buttonText.style.fontSize = self.fontSize')' in or related to this line: 'self.buttonText.style.fontSize = self.fontSize;' Line Number: 94
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'fontSize')' in or related to this line: 'self.buttonText.style.fontSize = self.fontSize;' Line Number: 94
User prompt
Make a button asset to replace the buttons we use now
User prompt
Make a button sprite
User prompt
Make Karen mode button bigger
User prompt
Take the obstacle out from the back
User prompt
Fix the text from supermarket dash to Walmart dash and make the background blank
User prompt
Fix title screen
User prompt
Add a Karen mode where demons spawn and customers spawn very fast
User prompt
Add a Karen mode where demons and customers spawn at a very fast rate
User prompt
Add a main menu with a logo asset
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Cashier = Container.expand(function () { var self = Container.call(this); // Create cashier visuals - using shopper asset with different tint var cashierGraphics = self.attachAsset('shopper', { anchorX: 0.5, anchorY: 0.5 }); // Make cashier visually distinct cashierGraphics.tint = 0x00AAFF; // Add cashier label var cashierLabel = new Text2("CASHIER", { size: 30, fill: 0x000000 }); cashierLabel.anchor.set(0.5, 0); cashierLabel.y = -120; self.addChild(cashierLabel); // Add visual indicator when all items collected self.showCheckoutReady = function () { var readyText = new Text2("CHECKOUT\nREADY!", { size: 35, fill: 0x00FF00 }); readyText.anchor.set(0.5, 0); readyText.y = -90; self.addChild(readyText); }; return self; }); var Item = Container.expand(function () { var self = Container.call(this); var itemGraphics = self.attachAsset('item', { anchorX: 0.5, anchorY: 0.5 }); self.name = ''; self.price = 0; self.onList = false; self.isSpecial = false; self.collected = false; self.setValue = function (name, price, onList) { self.name = name; self.price = price; self.onList = onList; var nameText = new Text2(name, { size: 22, fill: 0x000000 }); nameText.anchor.set(0.5, 0.5); nameText.y = -40; self.addChild(nameText); var priceText = new Text2('$' + price.toFixed(2), { size: 20, fill: 0x008000 }); priceText.anchor.set(0.5, 0.5); priceText.y = 40; self.addChild(priceText); if (onList) { itemGraphics.tint = 0xFFFF00; // Highlight items on the list } }; self.makeSpecialDeal = function () { if (self.isSpecial) { return; } self.isSpecial = true; // Replace with special deal graphics if (self.children.indexOf(itemGraphics) !== -1) { self.removeChild(itemGraphics); } var dealGraphics = self.attachAsset('specialDeal', { anchorX: 0.5, anchorY: 0.5 }); // Apply discount self.price = Math.round(self.price * 0.5 * 100) / 100; // Update price text for (var i = 0; i < self.children.length; i++) { if (self.children[i] instanceof Text2 && self.children[i].y === 40) { self.children[i].setText('$' + self.price.toFixed(2) + ' 50% OFF!'); self.children[i].tint = 0xFF0000; break; } } }; self.collect = function () { self.collected = true; self.visible = false; }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Create menu background var menuBg = LK.getAsset('obstacle', { anchorX: 0, anchorY: 0 }); menuBg.width = 1500; menuBg.height = 1800; menuBg.tint = 0xFFFFFF; menuBg.alpha = 0.9; self.addChild(menuBg); // Center the menu self.x = 2048 / 2 - menuBg.width / 2; self.y = 2732 / 2 - menuBg.height / 2; // Add logo var logo = self.attachAsset('logo', { anchorX: 0.5, anchorY: 0.5 }); logo.x = menuBg.width / 2; logo.y = 300; // Add title var titleText = new Text2("SUPERMARKET DASH", { size: 80, fill: 0x008000 }); titleText.anchor.set(0.5, 0.5); titleText.x = menuBg.width / 2; titleText.y = 550; self.addChild(titleText); // Add subtitle var subtitleText = new Text2("Race against the clock and avoid other shoppers!", { size: 40, fill: 0x000000 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = menuBg.width / 2; subtitleText.y = 650; self.addChild(subtitleText); // Add play button var playButton = new Container(); var playBg = LK.getAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); playBg.width = 400; playBg.height = 120; playBg.tint = 0x00AA00; playButton.addChild(playBg); var playText = new Text2("PLAY", { size: 60, fill: 0xFFFFFF }); playText.anchor.set(0.5, 0.5); playButton.addChild(playText); playButton.x = menuBg.width / 2; playButton.y = 900; playButton.interactive = true; self.addChild(playButton); // Add instructions var instructionsText = new Text2("How to play:\n\n• Collect all items on your shopping list\n• Avoid other shoppers and obstacles\n• Get to the cashier before time runs out\n• Defeat shopping demons before they reach the cashier", { size: 35, fill: 0x000000 }); instructionsText.anchor.set(0.5, 0); instructionsText.x = menuBg.width / 2; instructionsText.y = 1100; self.addChild(instructionsText); // Add event listeners playButton.down = function (x, y, obj) { LK.getSound('button').play(); self.onPlayClicked(); }; self.onPlayClicked = function () { // This will be set from outside }; return self; }); var MiniMap = Container.expand(function () { var self = Container.call(this); // Create minimap background var mapBg = LK.getAsset('obstacle', { anchorX: 0, anchorY: 0 }); mapBg.width = 300; mapBg.height = 225; mapBg.tint = 0xDDDDDD; mapBg.alpha = 0.7; self.addChild(mapBg); // Container for map items self.mapItems = new Container(); self.addChild(self.mapItems); // Factor to scale actual positions to minimap size self.scaleX = 300 / 2048; self.scaleY = 225 / 2732; // Update minimap with current game state self.update = function (cart, shoppers, items, obstacles, aisles) { // Clear previous map items while (self.mapItems.children.length > 0) { self.mapItems.removeChild(self.mapItems.children[0]); } // Draw aisles for (var i = 0; i < aisles.length; i++) { var aisleIcon = LK.getAsset('aisle', { anchorX: 0.5, anchorY: 0.5 }); aisleIcon.x = aisles[i].x * self.scaleX; aisleIcon.y = aisles[i].y * self.scaleY; aisleIcon.width = 12; aisleIcon.height = 225; aisleIcon.alpha = 0.6; self.mapItems.addChild(aisleIcon); } // Draw items on list that haven't been collected for (var j = 0; j < items.length; j++) { if (items[j].onList && !items[j].collected) { var itemIcon = LK.getAsset('item', { anchorX: 0.5, anchorY: 0.5 }); itemIcon.x = items[j].x * self.scaleX; itemIcon.y = items[j].y * self.scaleY; itemIcon.width = 8; itemIcon.height = 8; itemIcon.tint = 0xFFFF00; self.mapItems.addChild(itemIcon); } } // Draw obstacles for (var k = 0; k < obstacles.length; k++) { var obstacleIcon = LK.getAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); obstacleIcon.x = obstacles[k].x * self.scaleX; obstacleIcon.y = obstacles[k].y * self.scaleY; obstacleIcon.width = 10; obstacleIcon.height = 10; obstacleIcon.tint = 0xFF0000; self.mapItems.addChild(obstacleIcon); } // Draw shoppers for (var m = 0; m < shoppers.length; m++) { var shopperIcon = LK.getAsset('shopper', { anchorX: 0.5, anchorY: 0.5 }); shopperIcon.x = shoppers[m].x * self.scaleX; shopperIcon.y = shoppers[m].y * self.scaleY; shopperIcon.width = 6; shopperIcon.height = 12; shopperIcon.tint = 0xFF0000; self.mapItems.addChild(shopperIcon); } // Draw cart (player) last so it's on top if (cart) { var cartIcon = LK.getAsset('cart', { anchorX: 0.5, anchorY: 0.5 }); cartIcon.x = cart.x * self.scaleX; cartIcon.y = cart.y * self.scaleY; cartIcon.width = 15; cartIcon.height = 15; cartIcon.tint = 0x0000FF; self.mapItems.addChild(cartIcon); } }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); var warningText = new Text2('⚠️', { size: 32, fill: 0x000000 }); warningText.anchor.set(0.5, 0.5); self.addChild(warningText); self.duration = 5000; // 5 seconds self.createTime = Date.now(); self.update = function () { // Check if obstacle should be removed if (Date.now() - self.createTime > self.duration) { self.readyToRemove = true; } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); // Create power-up visual var powerUpGraphics = self.attachAsset('item', { anchorX: 0.5, anchorY: 0.5 }); // Make it visually distinct powerUpGraphics.tint = 0x00FFFF; self.type = 'speed'; // Default type self.duration = 5000; // Default duration: 5 seconds self.active = false; self.collected = false; // Set power-up type and properties self.setType = function (type) { self.type = type; var typeText = new Text2(type.toUpperCase(), { size: 20, fill: 0xFFFFFF }); typeText.anchor.set(0.5, 0.5); self.addChild(typeText); // Set appearance based on type switch (type) { case 'speed': powerUpGraphics.tint = 0x00FFFF; // Cyan self.duration = 5000; break; case 'magnet': powerUpGraphics.tint = 0xFF00FF; // Magenta self.duration = 7000; break; case 'shield': powerUpGraphics.tint = 0x0000FF; // Blue self.duration = 10000; break; } }; self.collect = function () { self.collected = true; self.visible = false; }; return self; }); var Shopper = Container.expand(function () { var self = Container.call(this); var shopperGraphics = self.attachAsset('shopper', { anchorX: 0.5, anchorY: 0.5 }); self.isMoving = false; self.startX = 0; self.startY = 0; self.targetX = 0; self.targetY = 0; self.lastX = 0; self.lastY = 0; // Initialize shopper movement self.startMoving = function () { // Stop any existing movement tween.stop(self); // Remember starting position self.startX = self.x; self.startY = self.y; self.lastX = self.x; self.lastY = self.y; // Choose a random destination within the aisle area var randomDistance = 100 + Math.random() * 300; var randomAngle = Math.random() * Math.PI * 2; self.targetX = self.x + Math.cos(randomAngle) * randomDistance; self.targetY = self.y + Math.sin(randomAngle) * randomDistance; // Constrain to game boundaries self.targetX = Math.max(100, Math.min(2048 - 100, self.targetX)); self.targetY = Math.max(100, Math.min(2732 - 100, self.targetY)); // Randomize movement duration (2-5 seconds) var duration = 2000 + Math.random() * 3000; // Use tween to smoothly move to the destination tween(self, { x: self.targetX, y: self.targetY }, { duration: duration, easing: tween.easeInOut, onFinish: function onFinish() { // Wait for a moment before moving again LK.setTimeout(function () { self.startMoving(); }, 500 + Math.random() * 1000); } }); self.isMoving = true; }; self.update = function () { // Keep track of last position for intersection detection self.lastX = self.x; self.lastY = self.y; // Start moving if not already moving if (!self.isMoving) { self.startMoving(); } }; return self; }); var ShoppingCart = Container.expand(function () { var self = Container.call(this); var cartGraphics = self.attachAsset('cart', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.budget = 100; self.collectedItems = []; self.isColliding = false; self.powerUps = {}; self.magnetRange = 0; // Visually indicate active power-ups self.powerUpIndicator = new Container(); self.addChild(self.powerUpIndicator); self.powerUpIndicator.y = -100; self.setBudget = function (amount) { self.budget = amount; }; self.addItem = function (item) { if (self.budget >= item.price) { self.budget -= item.price; self.collectedItems.push(item.name); return true; } return false; }; // Apply a power-up effect self.applyPowerUp = function (type, duration) { // Clear previous power-up of this type if active if (self.powerUps[type] && self.powerUps[type].timer) { LK.clearTimeout(self.powerUps[type].timer); } // Set up power-up self.powerUps[type] = { active: true, startTime: Date.now(), duration: duration }; // Apply immediate effects switch (type) { case 'speed': self.originalSpeed = self.speed; self.speed = 10; // Double speed break; case 'magnet': self.magnetRange = 200; // Set item attraction range break; case 'shield': // Visual indicator if (!self.shieldGraphics) { self.shieldGraphics = LK.getAsset('item', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 200 }); self.shieldGraphics.tint = 0x0000FF; self.shieldGraphics.alpha = 0.3; self.addChildAt(self.shieldGraphics, 0); } else { self.shieldGraphics.visible = true; } break; } // Update indicator self.updatePowerUpIndicator(); // Set timer to remove power-up self.powerUps[type].timer = LK.setTimeout(function () { self.removePowerUp(type); }, duration); }; // Remove power-up effect self.removePowerUp = function (type) { if (!self.powerUps[type] || !self.powerUps[type].active) { return; } // Remove effects switch (type) { case 'speed': self.speed = self.originalSpeed; break; case 'magnet': self.magnetRange = 0; break; case 'shield': if (self.shieldGraphics) { self.shieldGraphics.visible = false; } break; } // Update status self.powerUps[type].active = false; self.updatePowerUpIndicator(); }; // Update the visual indicator of active power-ups self.updatePowerUpIndicator = function () { // Clear current indicators while (self.powerUpIndicator.children.length > 0) { self.powerUpIndicator.removeChild(self.powerUpIndicator.children[0]); } // Add indicators for active power-ups var xPos = 0; var types = Object.keys(self.powerUps); for (var i = 0; i < types.length; i++) { if (self.powerUps[types[i]] && self.powerUps[types[i]].active) { // Calculate remaining time var elapsed = Date.now() - self.powerUps[types[i]].startTime; var remaining = Math.max(0, self.powerUps[types[i]].duration - elapsed); var seconds = Math.ceil(remaining / 1000); var indicator = new Text2(types[i] + ": " + seconds + "s", { size: 20, fill: 0xFFFFFF }); indicator.anchor.set(0.5, 0); indicator.x = xPos; self.powerUpIndicator.addChild(indicator); xPos += 100; } } }; return self; }); var ShoppingDemon = Container.expand(function () { var self = Container.call(this); // Create demon visuals - using shopper asset with demonic tint var demonGraphics = self.attachAsset('shopper', { anchorX: 0.5, anchorY: 0.5 }); // Make demon visually distinct with red tint demonGraphics.tint = 0xFF0000; // Scale up the demon slightly to make it more threatening demonGraphics.scaleX = 1.2; demonGraphics.scaleY = 1.2; // Add demon label var demonLabel = new Text2("DEMON", { size: 30, fill: 0xFF0000 }); demonLabel.anchor.set(0.5, 0); demonLabel.y = -120; self.addChild(demonLabel); // Movement properties self.speed = 2; self.target = null; self.cashier = null; self.lastX = 0; self.lastY = 0; self.active = true; // Set cashier target self.setTarget = function (cashier) { self.cashier = cashier; }; // Update demon movement self.update = function () { // Keep track of last position self.lastX = self.x; self.lastY = self.y; // If we have a cashier target, move toward it if (self.cashier && self.active) { // Calculate direction to cashier var dx = self.cashier.x - self.x; var dy = self.cashier.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move toward cashier if not already there if (distance > 10) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Rotate demon to face direction of movement demonGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2; } } }; // Flash demon when hit self.hit = function () { LK.effects.flashObject(self, 0xFFFFFF, 300); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xFFFFFF // White background }); /**** * Game Code ****/ // Game state variables var gameStarted = false; var timeRemaining = 60; // seconds var level = 1; var shoppingList = []; var aisles = []; var shoppers = []; var items = []; var powerUps = []; var obstacles = []; var specialDealTimer = null; var cleanupTimer = null; var powerUpUpdateTimer = null; var demonTimer = null; var demons = []; var cart; var gameArea; var demon; var mainMenu; var showingMainMenu = true; // UI elements var budgetText, timerText, shoppingListText, levelText, messageText, miniMap; // Create game area (container for all game elements) gameArea = new Container(); game.addChild(gameArea); // Create main menu function createMainMenu() { mainMenu = new MainMenu(); game.addChild(mainMenu); // Set event handler for play button mainMenu.onPlayClicked = function () { // Hide menu and start game showingMainMenu = false; mainMenu.visible = false; // Initialize game level initLevel(); }; } // Create the main menu createMainMenu(); // Initialize level function initLevel() { // Hide main menu if visible if (mainMenu && mainMenu.visible) { mainMenu.visible = false; showingMainMenu = false; } // Clear previous level elements clearLevel(); // Set level properties timeRemaining = 60 + level * 10; // Create aisles (4 aisles) for (var i = 0; i < 5; i++) { var aisle = LK.getAsset('aisle', { anchorX: 0.5, anchorY: 0.5 }); aisle.x = 100 + i * 450; aisle.y = 2732 / 2; gameArea.addChild(aisle); aisles.push(aisle); } // Generate shopping list (3-7 items depending on level) var numItems = 3 + Math.min(level, 4); generateShoppingList(numItems); // Create items in store createStoreItems(); // Create shoppers (obstacles) var numShoppers = 3 + level; createShoppers(numShoppers); // Create player's cart cart = new ShoppingCart(); cart.x = 2048 / 2; cart.y = 2732 - 200; cart.setBudget(100 + level * 20); gameArea.addChild(cart); // Create power-ups createPowerUps(); // Set up timers for special events setupEventTimers(); // Update UI updateUI(); // Create cashier at the bottom of store var cashier = new Cashier(); cashier.x = 2048 / 2; cashier.y = 2732 - 100; gameArea.addChild(cashier); // Create shopping demon var demon = new ShoppingDemon(); demon.x = 100; demon.y = 200; demon.setTarget(cashier); gameArea.addChild(demon); // Store reference to shopping demon game.demon = demon; // Start the game gameStarted = true; LK.playMusic('bgmusic'); } function clearLevel() { // Clear all arrays aisles = []; shoppers = []; items = []; obstacles = []; shoppingList = []; demons = []; demon = null; game.demon = null; // Clear all timers if (specialDealTimer) { LK.clearInterval(specialDealTimer); specialDealTimer = null; } if (cleanupTimer) { LK.clearInterval(cleanupTimer); cleanupTimer = null; } if (demonTimer) { LK.clearInterval(demonTimer); demonTimer = null; } // Remove all children from game area while (gameArea.children.length > 0) { gameArea.removeChild(gameArea.children[0]); } } function generateShoppingList(numItems) { var possibleItems = [{ name: "Milk", price: 3.49 }, { name: "Bread", price: 2.99 }, { name: "Eggs", price: 4.29 }, { name: "Cereal", price: 4.99 }, { name: "Bananas", price: 1.99 }, { name: "Chips", price: 3.79 }, { name: "Soda", price: 5.49 }, { name: "Pizza", price: 7.99 }, { name: "Ice Cream", price: 6.49 }, { name: "Chicken", price: 8.99 }]; // Shuffle array for (var i = possibleItems.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = possibleItems[i]; possibleItems[i] = possibleItems[j]; possibleItems[j] = temp; } // Take first numItems shoppingList = possibleItems.slice(0, numItems); // Update shopping list display updateShoppingListText(); } function createStoreItems() { // Create items from shopping list for (var i = 0; i < shoppingList.length; i++) { var item = new Item(); var aisleIndex = Math.floor(Math.random() * aisles.length); var aisle = aisles[aisleIndex]; item.x = aisle.x + (Math.random() * 200 - 100); item.y = 200 + Math.random() * (2732 - 400); item.setValue(shoppingList[i].name, shoppingList[i].price, true); gameArea.addChild(item); items.push(item); } // Create additional random items not on list var numExtraItems = 10 + level * 2; var possibleItems = [{ name: "Apples", price: 3.99 }, { name: "Soup", price: 2.49 }, { name: "Yogurt", price: 4.79 }, { name: "Coffee", price: 7.99 }, { name: "Pasta", price: 1.99 }, { name: "Candy", price: 3.29 }, { name: "Juice", price: 4.49 }, { name: "Paper", price: 5.99 }, { name: "Soap", price: 3.59 }, { name: "Cookies", price: 4.29 }, { name: "Cheese", price: 5.49 }, { name: "Water", price: 3.99 }, { name: "Tissues", price: 2.79 }, { name: "Detergent", price: 8.99 }, { name: "Toothpaste", price: 3.99 }]; for (var j = 0; j < numExtraItems; j++) { var extraItem = new Item(); var extraAisleIndex = Math.floor(Math.random() * aisles.length); var extraAisle = aisles[extraAisleIndex]; var itemData = possibleItems[Math.floor(Math.random() * possibleItems.length)]; extraItem.x = extraAisle.x + (Math.random() * 200 - 100); extraItem.y = 200 + Math.random() * (2732 - 400); extraItem.setValue(itemData.name, itemData.price, false); gameArea.addChild(extraItem); items.push(extraItem); } } function createShoppers(numShoppers) { for (var i = 0; i < numShoppers; i++) { var shopper = new Shopper(); var aisleIndex = Math.floor(Math.random() * aisles.length); var aisle = aisles[aisleIndex]; shopper.x = aisle.x + (Math.random() * 200 - 100); shopper.y = 200 + Math.random() * (2732 - 400); shopperGraphics = shopper.children[0]; // Randomly rotate the shopper shopperGraphics.rotation = Math.random() * Math.PI * 2; gameArea.addChild(shopper); shoppers.push(shopper); // Stagger the movement starts LK.setTimeout(function (s) { return function () { s.startMoving(); }; }(shopper), i * 300); } } function setupEventTimers() { // Special deals event (every 10-15 seconds) specialDealTimer = LK.setInterval(function () { createSpecialDeal(); }, 10000 + Math.random() * 5000); // Cleanup event (every 15-20 seconds) cleanupTimer = LK.setInterval(function () { createCleanupObstacle(); }, 15000 + Math.random() * 5000); // Demon spawner event (every 20-30 seconds) demonTimer = LK.setInterval(function () { spawnDemon(); }, 20000 + Math.random() * 10000); } function createSpecialDeal() { // Pick a random item to make a special deal if (items.length > 0) { var randomIndex = Math.floor(Math.random() * items.length); var item = items[randomIndex]; if (!item.isSpecial && !item.collected) { item.makeSpecialDeal(); // Show flash sale message showMessage("FLASH SALE!", 2000); } } } function createCleanupObstacle() { // Create cleanup on a random aisle var randomAisleIndex = Math.floor(Math.random() * aisles.length); var aisle = aisles[randomAisleIndex]; var obstacle = new Obstacle(); obstacle.x = aisle.x; obstacle.y = 500 + Math.random() * 1500; gameArea.addChild(obstacle); obstacles.push(obstacle); // Show cleanup message showMessage("CLEANUP ON AISLE " + (randomAisleIndex + 1), 2000); } function updateShoppingListText() { var listText = "Shopping List:\n"; var remainingItems = 0; for (var i = 0; i < shoppingList.length; i++) { var collected = false; // Check if item has been collected if (cart && cart.collectedItems) { collected = cart.collectedItems.indexOf(shoppingList[i].name) !== -1; } if (!collected) { remainingItems++; listText += "• " + shoppingList[i].name + " - $" + shoppingList[i].price.toFixed(2) + "\n"; } else { listText += "✓ " + shoppingList[i].name + " - $" + shoppingList[i].price.toFixed(2) + "\n"; } } if (shoppingListText) { shoppingListText.setText(listText); } return remainingItems; } function showMessage(text, duration) { if (messageText) { messageText.setText(text); messageText.visible = true; LK.setTimeout(function () { messageText.visible = false; }, duration); } } function createUI() { // Create budget display budgetText = new Text2("Budget: $0.00", { size: 40, fill: 0x008000 }); budgetText.anchor.set(0, 0); LK.gui.topRight.addChild(budgetText); // Create timer display timerText = new Text2("Time: 0:00", { size: 40, fill: 0xDE2027 }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); // Create level display levelText = new Text2("Level: 1", { size: 40, fill: 0x0071CE }); levelText.anchor.set(1, 0); LK.gui.topLeft.addChild(levelText); // Move it a bit to the right to avoid the platform menu levelText.x += 120; // Create shopping list display shoppingListText = new Text2("Shopping List:", { size: 30, fill: 0x000000 }); shoppingListText.anchor.set(1, 0); shoppingListText.x = -20; // Move it a bit to the left to ensure visibility LK.gui.right.addChild(shoppingListText); // Create message text for events messageText = new Text2("", { size: 60, fill: 0xFF0000 }); messageText.anchor.set(0.5, 0.5); messageText.visible = false; LK.gui.center.addChild(messageText); // Create minimap in bottom left corner miniMap = new MiniMap(); miniMap.x = 20; miniMap.y = -250; // Position from bottom LK.gui.bottomLeft.addChild(miniMap); } function updateUI() { if (!cart) { return; } // Update budget display budgetText.setText("Budget: $" + cart.budget.toFixed(2)); // Update timer display var minutes = Math.floor(timeRemaining / 60); var seconds = timeRemaining % 60; timerText.setText("Time: " + minutes + ":" + (seconds < 10 ? "0" : "") + seconds); // Update level display levelText.setText("Level: " + level); // Update shopping list var remainingItems = updateShoppingListText(); // If no items remaining, highlight cashier to indicate checkout if (remainingItems === 0) { // Find cashier and set indicator for (var c = 0; c < gameArea.children.length; c++) { if (gameArea.children[c] instanceof Cashier) { gameArea.children[c].showCheckoutReady(); break; } } // No longer win automatically - need to go to cashier } } // Handle touch/drag controls var dragging = false; function handleMove(x, y, obj) { if (dragging && cart) { // Move the cart to the touch position cart.x = x; cart.y = y; // Keep within game boundaries cart.x = Math.max(cart.width / 2, Math.min(2048 - cart.width / 2, cart.x)); cart.y = Math.max(cart.height / 2, Math.min(2732 - cart.height / 2, cart.y)); } } game.move = handleMove; game.down = function (x, y, obj) { if (showingMainMenu) { // Let the menu handle its own click events return; } if (!gameStarted) { initLevel(); return; } if (cart && Math.abs(x - cart.x) < cart.width / 2 && Math.abs(y - cart.y) < cart.height / 2) { dragging = true; } handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragging = false; }; // Main game loop var lastSecondTick = 0; game.update = function () { if (showingMainMenu) { // Don't update game while showing menu return; } if (!gameStarted) { return; } // Update timer once per second if (LK.ticks % 60 === 0) { timeRemaining--; updateUI(); // Check if time is up if (timeRemaining <= 0) { gameStarted = false; showMessage("TIME'S UP!", 2000); LK.setTimeout(function () { LK.showGameOver(); }, 2000); } } // Update power-up indicators every 16 frames (roughly 4 times per second) if (cart && LK.ticks % 15 === 0) { cart.updatePowerUpIndicator(); // Update minimap if (miniMap) { miniMap.update(cart, shoppers, items, obstacles, aisles); } } // Apply magnet effect if active if (cart && cart.powerUps.magnet && cart.powerUps.magnet.active && cart.magnetRange > 0) { for (var i = 0; i < items.length; i++) { var item = items[i]; if (!item.collected && !(item instanceof PowerUp)) { var dx = cart.x - item.x; var dy = cart.y - item.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < cart.magnetRange) { // Move item toward cart var speed = 5 + (1 - distance / cart.magnetRange) * 10; item.x += dx / distance * speed; item.y += dy / distance * speed; } } } } // Update all shoppers for (var i = 0; i < shoppers.length; i++) { shoppers[i].update(); } // Update all obstacles for (var j = obstacles.length - 1; j >= 0; j--) { obstacles[j].update(); if (obstacles[j].readyToRemove) { gameArea.removeChild(obstacles[j]); obstacles.splice(j, 1); } } // Check for collisions with cart if (cart) { // Check for collisions with items for (var k = 0; k < items.length; k++) { var item = items[k]; if (!item.collected && cart.intersects(item)) { // Check if item is a power-up if (item instanceof PowerUp) { // Collect power-up item.collect(); LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 15); // Apply the power-up effect cart.applyPowerUp(item.type, item.duration); showMessage(item.type.toUpperCase() + " POWER-UP!", 1000); continue; } if (item.onList) { // Collect item on shopping list if (cart.addItem(item)) { item.collect(); LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 10); updateUI(); } else { // Not enough budget if (!cart.isColliding) { showMessage("Not enough budget!", 1000); cart.isColliding = true; LK.setTimeout(function () { cart.isColliding = false; }, 1000); } } } else if (item.isSpecial) { // Collect special item if (cart.addItem(item)) { item.collect(); LK.getSound('deal').play(); LK.setScore(LK.getScore() + 5); updateUI(); } else { // Not enough budget if (!cart.isColliding) { showMessage("Not enough budget!", 1000); cart.isColliding = true; LK.setTimeout(function () { cart.isColliding = false; }, 1000); } } } } } // Check for collisions with shoppers for (var m = 0; m < shoppers.length; m++) { if (cart.intersects(shoppers[m]) && !cart.isColliding) { // Check if shield power-up is active if (cart.powerUps.shield && cart.powerUps.shield.active) { // Shield protects from collision LK.getSound('collision').play(); LK.effects.flashObject(cart, 0x0000FF, 500); // Blue flash for shield cart.isColliding = true; showMessage("SHIELD PROTECTED YOU!", 1000); // Move shopper away var dx = shoppers[m].x - cart.x; var dy = shoppers[m].y - cart.y; var distance = Math.sqrt(dx * dx + dy * dy); shoppers[m].x += dx / distance * 150; shoppers[m].y += dy / distance * 150; LK.setTimeout(function () { cart.isColliding = false; }, 1000); } else { // Collision with shopper - Game Over! LK.getSound('collision').play(); LK.effects.flashObject(cart, 0xFF0000, 500); cart.isColliding = true; // Show death message and end game showMessage("GAME OVER! Other shopper crashed into you!", 2000); gameStarted = false; updateUI(); LK.setTimeout(function () { LK.showGameOver(); // Show main menu after game over LK.setTimeout(function () { mainMenu.visible = true; showingMainMenu = true; }, 1000); }, 2000); } } } // Check for collisions with obstacles for (var n = 0; n < obstacles.length; n++) { if (cart.intersects(obstacles[n]) && !cart.isColliding) { // Collision with obstacle LK.getSound('collision').play(); LK.effects.flashObject(cart, 0xFF0000, 500); cart.isColliding = true; // Penalty timeRemaining = Math.max(0, timeRemaining - 3); updateUI(); LK.setTimeout(function () { cart.isColliding = false; }, 1000); } } // Update and check collision with demon from initial level if (game.demon && game.demon.active) { // Update demon game.demon.update(); // Check if demon collided with cashier for (var c = 0; c < gameArea.children.length; c++) { if (gameArea.children[c] instanceof Cashier && game.demon.intersects(gameArea.children[c]) && game.demon.active) { // Demon reached cashier - Game Over! LK.getSound('collision').play(); LK.effects.flashScreen(0xFF0000, 1000); showMessage("GAME OVER! Demon reached the cashier!", 2000); gameStarted = false; LK.setTimeout(function () { LK.showGameOver(); }, 2000); return; } } // Check if player touched the demon if (cart && cart.intersects(game.demon) && !cart.isColliding) { // Player touched demon - defeat it! game.demon.hit(); game.demon.active = false; LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 50); showMessage("DEMON DEFEATED! +50 POINTS", 2000); // Make demon disappear slowly tween(game.demon, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { gameArea.removeChild(game.demon); } }); } } // Update and check collision with spawned demons for (var d = demons.length - 1; d >= 0; d--) { var currentDemon = demons[d]; // Update demon if (currentDemon.active) { currentDemon.update(); // Check if demon collided with cashier for (var c = 0; c < gameArea.children.length; c++) { if (gameArea.children[c] instanceof Cashier && currentDemon.intersects(gameArea.children[c]) && currentDemon.active) { // Demon reached cashier - Game Over! LK.getSound('collision').play(); LK.effects.flashScreen(0xFF0000, 1000); showMessage("GAME OVER! Demon reached the cashier!", 2000); gameStarted = false; LK.setTimeout(function () { LK.showGameOver(); }, 2000); return; } } // Check if player touched the demon if (cart && cart.intersects(currentDemon) && !cart.isColliding) { // Player touched demon - defeat it! currentDemon.hit(); currentDemon.active = false; LK.getSound('pickup').play(); LK.setScore(LK.getScore() + 50); showMessage("DEMON DEFEATED! +50 POINTS", 2000); // Make demon disappear slowly tween(currentDemon, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, easing: tween.easeOut, onFinish: function (demonIndex) { return function () { if (demons[demonIndex]) { gameArea.removeChild(demons[demonIndex]); demons.splice(demonIndex, 1); } }; }(d) }); // Set cart as colliding briefly to prevent multiple demon hits cart.isColliding = true; LK.setTimeout(function () { cart.isColliding = false; }, 500); } } } // Check for collision with cashier for level completion for (var c = 0; c < gameArea.children.length; c++) { if (gameArea.children[c] instanceof Cashier && cart.intersects(gameArea.children[c])) { // Check if all items have been collected var remainingItems = updateShoppingListText(); if (remainingItems === 0 && !cart.isColliding) { // Level complete! level++; showMessage("CHECKOUT COMPLETE! LEVEL UP!", 3000); LK.setTimeout(initLevel, 3000); gameStarted = false; // Award bonus points for remaining time var timeBonus = timeRemaining * 2; LK.setScore(LK.getScore() + timeBonus); break; } else if (remainingItems > 0 && !cart.isColliding) { // Still have items to collect showMessage("Finish your shopping first!", 1000); cart.isColliding = true; LK.setTimeout(function () { cart.isColliding = false; }, 1000); } } } } }; // Initialize UI createUI(); // Don't show start instructions since we now have a menu function createPowerUps() { // Create 3 power-ups of different types, randomly placed in aisles var powerUpTypes = ['speed', 'magnet', 'shield']; for (var i = 0; i < powerUpTypes.length; i++) { var powerUp = new PowerUp(); var aisleIndex = Math.floor(Math.random() * aisles.length); var aisle = aisles[aisleIndex]; powerUp.x = aisle.x + (Math.random() * 200 - 100); powerUp.y = 200 + Math.random() * (2732 - 400); powerUp.setType(powerUpTypes[i]); gameArea.addChild(powerUp); items.push(powerUp); // Add to items array for collision detection } } function spawnDemon() { if (!gameStarted) { return; } // Create a new demon var newDemon = new ShoppingDemon(); // Place demon at a random edge of the screen var side = Math.floor(Math.random() * 4); switch (side) { case 0: // Top newDemon.x = Math.random() * 2048; newDemon.y = 50; break; case 1: // Right newDemon.x = 2048 - 50; newDemon.y = Math.random() * 2732; break; case 2: // Bottom newDemon.x = Math.random() * 2048; newDemon.y = 2732 - 50; break; case 3: // Left newDemon.x = 50; newDemon.y = Math.random() * 2732; break; } // Find the cashier to target for (var c = 0; c < gameArea.children.length; c++) { if (gameArea.children[c] instanceof Cashier) { newDemon.setTarget(gameArea.children[c]); break; } } // Initialize tracking properties newDemon.lastX = newDemon.x; newDemon.lastY = newDemon.y; // Add to game gameArea.addChild(newDemon); demons.push(newDemon); // Show warning message showMessage("SHOPPING DEMON APPROACHING!", 2000); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Cashier = Container.expand(function () {
var self = Container.call(this);
// Create cashier visuals - using shopper asset with different tint
var cashierGraphics = self.attachAsset('shopper', {
anchorX: 0.5,
anchorY: 0.5
});
// Make cashier visually distinct
cashierGraphics.tint = 0x00AAFF;
// Add cashier label
var cashierLabel = new Text2("CASHIER", {
size: 30,
fill: 0x000000
});
cashierLabel.anchor.set(0.5, 0);
cashierLabel.y = -120;
self.addChild(cashierLabel);
// Add visual indicator when all items collected
self.showCheckoutReady = function () {
var readyText = new Text2("CHECKOUT\nREADY!", {
size: 35,
fill: 0x00FF00
});
readyText.anchor.set(0.5, 0);
readyText.y = -90;
self.addChild(readyText);
};
return self;
});
var Item = Container.expand(function () {
var self = Container.call(this);
var itemGraphics = self.attachAsset('item', {
anchorX: 0.5,
anchorY: 0.5
});
self.name = '';
self.price = 0;
self.onList = false;
self.isSpecial = false;
self.collected = false;
self.setValue = function (name, price, onList) {
self.name = name;
self.price = price;
self.onList = onList;
var nameText = new Text2(name, {
size: 22,
fill: 0x000000
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -40;
self.addChild(nameText);
var priceText = new Text2('$' + price.toFixed(2), {
size: 20,
fill: 0x008000
});
priceText.anchor.set(0.5, 0.5);
priceText.y = 40;
self.addChild(priceText);
if (onList) {
itemGraphics.tint = 0xFFFF00; // Highlight items on the list
}
};
self.makeSpecialDeal = function () {
if (self.isSpecial) {
return;
}
self.isSpecial = true;
// Replace with special deal graphics
if (self.children.indexOf(itemGraphics) !== -1) {
self.removeChild(itemGraphics);
}
var dealGraphics = self.attachAsset('specialDeal', {
anchorX: 0.5,
anchorY: 0.5
});
// Apply discount
self.price = Math.round(self.price * 0.5 * 100) / 100;
// Update price text
for (var i = 0; i < self.children.length; i++) {
if (self.children[i] instanceof Text2 && self.children[i].y === 40) {
self.children[i].setText('$' + self.price.toFixed(2) + ' 50% OFF!');
self.children[i].tint = 0xFF0000;
break;
}
}
};
self.collect = function () {
self.collected = true;
self.visible = false;
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Create menu background
var menuBg = LK.getAsset('obstacle', {
anchorX: 0,
anchorY: 0
});
menuBg.width = 1500;
menuBg.height = 1800;
menuBg.tint = 0xFFFFFF;
menuBg.alpha = 0.9;
self.addChild(menuBg);
// Center the menu
self.x = 2048 / 2 - menuBg.width / 2;
self.y = 2732 / 2 - menuBg.height / 2;
// Add logo
var logo = self.attachAsset('logo', {
anchorX: 0.5,
anchorY: 0.5
});
logo.x = menuBg.width / 2;
logo.y = 300;
// Add title
var titleText = new Text2("SUPERMARKET DASH", {
size: 80,
fill: 0x008000
});
titleText.anchor.set(0.5, 0.5);
titleText.x = menuBg.width / 2;
titleText.y = 550;
self.addChild(titleText);
// Add subtitle
var subtitleText = new Text2("Race against the clock and avoid other shoppers!", {
size: 40,
fill: 0x000000
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = menuBg.width / 2;
subtitleText.y = 650;
self.addChild(subtitleText);
// Add play button
var playButton = new Container();
var playBg = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
playBg.width = 400;
playBg.height = 120;
playBg.tint = 0x00AA00;
playButton.addChild(playBg);
var playText = new Text2("PLAY", {
size: 60,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playButton.addChild(playText);
playButton.x = menuBg.width / 2;
playButton.y = 900;
playButton.interactive = true;
self.addChild(playButton);
// Add instructions
var instructionsText = new Text2("How to play:\n\n• Collect all items on your shopping list\n• Avoid other shoppers and obstacles\n• Get to the cashier before time runs out\n• Defeat shopping demons before they reach the cashier", {
size: 35,
fill: 0x000000
});
instructionsText.anchor.set(0.5, 0);
instructionsText.x = menuBg.width / 2;
instructionsText.y = 1100;
self.addChild(instructionsText);
// Add event listeners
playButton.down = function (x, y, obj) {
LK.getSound('button').play();
self.onPlayClicked();
};
self.onPlayClicked = function () {
// This will be set from outside
};
return self;
});
var MiniMap = Container.expand(function () {
var self = Container.call(this);
// Create minimap background
var mapBg = LK.getAsset('obstacle', {
anchorX: 0,
anchorY: 0
});
mapBg.width = 300;
mapBg.height = 225;
mapBg.tint = 0xDDDDDD;
mapBg.alpha = 0.7;
self.addChild(mapBg);
// Container for map items
self.mapItems = new Container();
self.addChild(self.mapItems);
// Factor to scale actual positions to minimap size
self.scaleX = 300 / 2048;
self.scaleY = 225 / 2732;
// Update minimap with current game state
self.update = function (cart, shoppers, items, obstacles, aisles) {
// Clear previous map items
while (self.mapItems.children.length > 0) {
self.mapItems.removeChild(self.mapItems.children[0]);
}
// Draw aisles
for (var i = 0; i < aisles.length; i++) {
var aisleIcon = LK.getAsset('aisle', {
anchorX: 0.5,
anchorY: 0.5
});
aisleIcon.x = aisles[i].x * self.scaleX;
aisleIcon.y = aisles[i].y * self.scaleY;
aisleIcon.width = 12;
aisleIcon.height = 225;
aisleIcon.alpha = 0.6;
self.mapItems.addChild(aisleIcon);
}
// Draw items on list that haven't been collected
for (var j = 0; j < items.length; j++) {
if (items[j].onList && !items[j].collected) {
var itemIcon = LK.getAsset('item', {
anchorX: 0.5,
anchorY: 0.5
});
itemIcon.x = items[j].x * self.scaleX;
itemIcon.y = items[j].y * self.scaleY;
itemIcon.width = 8;
itemIcon.height = 8;
itemIcon.tint = 0xFFFF00;
self.mapItems.addChild(itemIcon);
}
}
// Draw obstacles
for (var k = 0; k < obstacles.length; k++) {
var obstacleIcon = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleIcon.x = obstacles[k].x * self.scaleX;
obstacleIcon.y = obstacles[k].y * self.scaleY;
obstacleIcon.width = 10;
obstacleIcon.height = 10;
obstacleIcon.tint = 0xFF0000;
self.mapItems.addChild(obstacleIcon);
}
// Draw shoppers
for (var m = 0; m < shoppers.length; m++) {
var shopperIcon = LK.getAsset('shopper', {
anchorX: 0.5,
anchorY: 0.5
});
shopperIcon.x = shoppers[m].x * self.scaleX;
shopperIcon.y = shoppers[m].y * self.scaleY;
shopperIcon.width = 6;
shopperIcon.height = 12;
shopperIcon.tint = 0xFF0000;
self.mapItems.addChild(shopperIcon);
}
// Draw cart (player) last so it's on top
if (cart) {
var cartIcon = LK.getAsset('cart', {
anchorX: 0.5,
anchorY: 0.5
});
cartIcon.x = cart.x * self.scaleX;
cartIcon.y = cart.y * self.scaleY;
cartIcon.width = 15;
cartIcon.height = 15;
cartIcon.tint = 0x0000FF;
self.mapItems.addChild(cartIcon);
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
var warningText = new Text2('⚠️', {
size: 32,
fill: 0x000000
});
warningText.anchor.set(0.5, 0.5);
self.addChild(warningText);
self.duration = 5000; // 5 seconds
self.createTime = Date.now();
self.update = function () {
// Check if obstacle should be removed
if (Date.now() - self.createTime > self.duration) {
self.readyToRemove = true;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Create power-up visual
var powerUpGraphics = self.attachAsset('item', {
anchorX: 0.5,
anchorY: 0.5
});
// Make it visually distinct
powerUpGraphics.tint = 0x00FFFF;
self.type = 'speed'; // Default type
self.duration = 5000; // Default duration: 5 seconds
self.active = false;
self.collected = false;
// Set power-up type and properties
self.setType = function (type) {
self.type = type;
var typeText = new Text2(type.toUpperCase(), {
size: 20,
fill: 0xFFFFFF
});
typeText.anchor.set(0.5, 0.5);
self.addChild(typeText);
// Set appearance based on type
switch (type) {
case 'speed':
powerUpGraphics.tint = 0x00FFFF; // Cyan
self.duration = 5000;
break;
case 'magnet':
powerUpGraphics.tint = 0xFF00FF; // Magenta
self.duration = 7000;
break;
case 'shield':
powerUpGraphics.tint = 0x0000FF; // Blue
self.duration = 10000;
break;
}
};
self.collect = function () {
self.collected = true;
self.visible = false;
};
return self;
});
var Shopper = Container.expand(function () {
var self = Container.call(this);
var shopperGraphics = self.attachAsset('shopper', {
anchorX: 0.5,
anchorY: 0.5
});
self.isMoving = false;
self.startX = 0;
self.startY = 0;
self.targetX = 0;
self.targetY = 0;
self.lastX = 0;
self.lastY = 0;
// Initialize shopper movement
self.startMoving = function () {
// Stop any existing movement
tween.stop(self);
// Remember starting position
self.startX = self.x;
self.startY = self.y;
self.lastX = self.x;
self.lastY = self.y;
// Choose a random destination within the aisle area
var randomDistance = 100 + Math.random() * 300;
var randomAngle = Math.random() * Math.PI * 2;
self.targetX = self.x + Math.cos(randomAngle) * randomDistance;
self.targetY = self.y + Math.sin(randomAngle) * randomDistance;
// Constrain to game boundaries
self.targetX = Math.max(100, Math.min(2048 - 100, self.targetX));
self.targetY = Math.max(100, Math.min(2732 - 100, self.targetY));
// Randomize movement duration (2-5 seconds)
var duration = 2000 + Math.random() * 3000;
// Use tween to smoothly move to the destination
tween(self, {
x: self.targetX,
y: self.targetY
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Wait for a moment before moving again
LK.setTimeout(function () {
self.startMoving();
}, 500 + Math.random() * 1000);
}
});
self.isMoving = true;
};
self.update = function () {
// Keep track of last position for intersection detection
self.lastX = self.x;
self.lastY = self.y;
// Start moving if not already moving
if (!self.isMoving) {
self.startMoving();
}
};
return self;
});
var ShoppingCart = Container.expand(function () {
var self = Container.call(this);
var cartGraphics = self.attachAsset('cart', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.budget = 100;
self.collectedItems = [];
self.isColliding = false;
self.powerUps = {};
self.magnetRange = 0;
// Visually indicate active power-ups
self.powerUpIndicator = new Container();
self.addChild(self.powerUpIndicator);
self.powerUpIndicator.y = -100;
self.setBudget = function (amount) {
self.budget = amount;
};
self.addItem = function (item) {
if (self.budget >= item.price) {
self.budget -= item.price;
self.collectedItems.push(item.name);
return true;
}
return false;
};
// Apply a power-up effect
self.applyPowerUp = function (type, duration) {
// Clear previous power-up of this type if active
if (self.powerUps[type] && self.powerUps[type].timer) {
LK.clearTimeout(self.powerUps[type].timer);
}
// Set up power-up
self.powerUps[type] = {
active: true,
startTime: Date.now(),
duration: duration
};
// Apply immediate effects
switch (type) {
case 'speed':
self.originalSpeed = self.speed;
self.speed = 10; // Double speed
break;
case 'magnet':
self.magnetRange = 200; // Set item attraction range
break;
case 'shield':
// Visual indicator
if (!self.shieldGraphics) {
self.shieldGraphics = LK.getAsset('item', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 200
});
self.shieldGraphics.tint = 0x0000FF;
self.shieldGraphics.alpha = 0.3;
self.addChildAt(self.shieldGraphics, 0);
} else {
self.shieldGraphics.visible = true;
}
break;
}
// Update indicator
self.updatePowerUpIndicator();
// Set timer to remove power-up
self.powerUps[type].timer = LK.setTimeout(function () {
self.removePowerUp(type);
}, duration);
};
// Remove power-up effect
self.removePowerUp = function (type) {
if (!self.powerUps[type] || !self.powerUps[type].active) {
return;
}
// Remove effects
switch (type) {
case 'speed':
self.speed = self.originalSpeed;
break;
case 'magnet':
self.magnetRange = 0;
break;
case 'shield':
if (self.shieldGraphics) {
self.shieldGraphics.visible = false;
}
break;
}
// Update status
self.powerUps[type].active = false;
self.updatePowerUpIndicator();
};
// Update the visual indicator of active power-ups
self.updatePowerUpIndicator = function () {
// Clear current indicators
while (self.powerUpIndicator.children.length > 0) {
self.powerUpIndicator.removeChild(self.powerUpIndicator.children[0]);
}
// Add indicators for active power-ups
var xPos = 0;
var types = Object.keys(self.powerUps);
for (var i = 0; i < types.length; i++) {
if (self.powerUps[types[i]] && self.powerUps[types[i]].active) {
// Calculate remaining time
var elapsed = Date.now() - self.powerUps[types[i]].startTime;
var remaining = Math.max(0, self.powerUps[types[i]].duration - elapsed);
var seconds = Math.ceil(remaining / 1000);
var indicator = new Text2(types[i] + ": " + seconds + "s", {
size: 20,
fill: 0xFFFFFF
});
indicator.anchor.set(0.5, 0);
indicator.x = xPos;
self.powerUpIndicator.addChild(indicator);
xPos += 100;
}
}
};
return self;
});
var ShoppingDemon = Container.expand(function () {
var self = Container.call(this);
// Create demon visuals - using shopper asset with demonic tint
var demonGraphics = self.attachAsset('shopper', {
anchorX: 0.5,
anchorY: 0.5
});
// Make demon visually distinct with red tint
demonGraphics.tint = 0xFF0000;
// Scale up the demon slightly to make it more threatening
demonGraphics.scaleX = 1.2;
demonGraphics.scaleY = 1.2;
// Add demon label
var demonLabel = new Text2("DEMON", {
size: 30,
fill: 0xFF0000
});
demonLabel.anchor.set(0.5, 0);
demonLabel.y = -120;
self.addChild(demonLabel);
// Movement properties
self.speed = 2;
self.target = null;
self.cashier = null;
self.lastX = 0;
self.lastY = 0;
self.active = true;
// Set cashier target
self.setTarget = function (cashier) {
self.cashier = cashier;
};
// Update demon movement
self.update = function () {
// Keep track of last position
self.lastX = self.x;
self.lastY = self.y;
// If we have a cashier target, move toward it
if (self.cashier && self.active) {
// Calculate direction to cashier
var dx = self.cashier.x - self.x;
var dy = self.cashier.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move toward cashier if not already there
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Rotate demon to face direction of movement
demonGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
}
}
};
// Flash demon when hit
self.hit = function () {
LK.effects.flashObject(self, 0xFFFFFF, 300);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xFFFFFF // White background
});
/****
* Game Code
****/
// Game state variables
var gameStarted = false;
var timeRemaining = 60; // seconds
var level = 1;
var shoppingList = [];
var aisles = [];
var shoppers = [];
var items = [];
var powerUps = [];
var obstacles = [];
var specialDealTimer = null;
var cleanupTimer = null;
var powerUpUpdateTimer = null;
var demonTimer = null;
var demons = [];
var cart;
var gameArea;
var demon;
var mainMenu;
var showingMainMenu = true;
// UI elements
var budgetText, timerText, shoppingListText, levelText, messageText, miniMap;
// Create game area (container for all game elements)
gameArea = new Container();
game.addChild(gameArea);
// Create main menu
function createMainMenu() {
mainMenu = new MainMenu();
game.addChild(mainMenu);
// Set event handler for play button
mainMenu.onPlayClicked = function () {
// Hide menu and start game
showingMainMenu = false;
mainMenu.visible = false;
// Initialize game level
initLevel();
};
}
// Create the main menu
createMainMenu();
// Initialize level
function initLevel() {
// Hide main menu if visible
if (mainMenu && mainMenu.visible) {
mainMenu.visible = false;
showingMainMenu = false;
}
// Clear previous level elements
clearLevel();
// Set level properties
timeRemaining = 60 + level * 10;
// Create aisles (4 aisles)
for (var i = 0; i < 5; i++) {
var aisle = LK.getAsset('aisle', {
anchorX: 0.5,
anchorY: 0.5
});
aisle.x = 100 + i * 450;
aisle.y = 2732 / 2;
gameArea.addChild(aisle);
aisles.push(aisle);
}
// Generate shopping list (3-7 items depending on level)
var numItems = 3 + Math.min(level, 4);
generateShoppingList(numItems);
// Create items in store
createStoreItems();
// Create shoppers (obstacles)
var numShoppers = 3 + level;
createShoppers(numShoppers);
// Create player's cart
cart = new ShoppingCart();
cart.x = 2048 / 2;
cart.y = 2732 - 200;
cart.setBudget(100 + level * 20);
gameArea.addChild(cart);
// Create power-ups
createPowerUps();
// Set up timers for special events
setupEventTimers();
// Update UI
updateUI();
// Create cashier at the bottom of store
var cashier = new Cashier();
cashier.x = 2048 / 2;
cashier.y = 2732 - 100;
gameArea.addChild(cashier);
// Create shopping demon
var demon = new ShoppingDemon();
demon.x = 100;
demon.y = 200;
demon.setTarget(cashier);
gameArea.addChild(demon);
// Store reference to shopping demon
game.demon = demon;
// Start the game
gameStarted = true;
LK.playMusic('bgmusic');
}
function clearLevel() {
// Clear all arrays
aisles = [];
shoppers = [];
items = [];
obstacles = [];
shoppingList = [];
demons = [];
demon = null;
game.demon = null;
// Clear all timers
if (specialDealTimer) {
LK.clearInterval(specialDealTimer);
specialDealTimer = null;
}
if (cleanupTimer) {
LK.clearInterval(cleanupTimer);
cleanupTimer = null;
}
if (demonTimer) {
LK.clearInterval(demonTimer);
demonTimer = null;
}
// Remove all children from game area
while (gameArea.children.length > 0) {
gameArea.removeChild(gameArea.children[0]);
}
}
function generateShoppingList(numItems) {
var possibleItems = [{
name: "Milk",
price: 3.49
}, {
name: "Bread",
price: 2.99
}, {
name: "Eggs",
price: 4.29
}, {
name: "Cereal",
price: 4.99
}, {
name: "Bananas",
price: 1.99
}, {
name: "Chips",
price: 3.79
}, {
name: "Soda",
price: 5.49
}, {
name: "Pizza",
price: 7.99
}, {
name: "Ice Cream",
price: 6.49
}, {
name: "Chicken",
price: 8.99
}];
// Shuffle array
for (var i = possibleItems.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = possibleItems[i];
possibleItems[i] = possibleItems[j];
possibleItems[j] = temp;
}
// Take first numItems
shoppingList = possibleItems.slice(0, numItems);
// Update shopping list display
updateShoppingListText();
}
function createStoreItems() {
// Create items from shopping list
for (var i = 0; i < shoppingList.length; i++) {
var item = new Item();
var aisleIndex = Math.floor(Math.random() * aisles.length);
var aisle = aisles[aisleIndex];
item.x = aisle.x + (Math.random() * 200 - 100);
item.y = 200 + Math.random() * (2732 - 400);
item.setValue(shoppingList[i].name, shoppingList[i].price, true);
gameArea.addChild(item);
items.push(item);
}
// Create additional random items not on list
var numExtraItems = 10 + level * 2;
var possibleItems = [{
name: "Apples",
price: 3.99
}, {
name: "Soup",
price: 2.49
}, {
name: "Yogurt",
price: 4.79
}, {
name: "Coffee",
price: 7.99
}, {
name: "Pasta",
price: 1.99
}, {
name: "Candy",
price: 3.29
}, {
name: "Juice",
price: 4.49
}, {
name: "Paper",
price: 5.99
}, {
name: "Soap",
price: 3.59
}, {
name: "Cookies",
price: 4.29
}, {
name: "Cheese",
price: 5.49
}, {
name: "Water",
price: 3.99
}, {
name: "Tissues",
price: 2.79
}, {
name: "Detergent",
price: 8.99
}, {
name: "Toothpaste",
price: 3.99
}];
for (var j = 0; j < numExtraItems; j++) {
var extraItem = new Item();
var extraAisleIndex = Math.floor(Math.random() * aisles.length);
var extraAisle = aisles[extraAisleIndex];
var itemData = possibleItems[Math.floor(Math.random() * possibleItems.length)];
extraItem.x = extraAisle.x + (Math.random() * 200 - 100);
extraItem.y = 200 + Math.random() * (2732 - 400);
extraItem.setValue(itemData.name, itemData.price, false);
gameArea.addChild(extraItem);
items.push(extraItem);
}
}
function createShoppers(numShoppers) {
for (var i = 0; i < numShoppers; i++) {
var shopper = new Shopper();
var aisleIndex = Math.floor(Math.random() * aisles.length);
var aisle = aisles[aisleIndex];
shopper.x = aisle.x + (Math.random() * 200 - 100);
shopper.y = 200 + Math.random() * (2732 - 400);
shopperGraphics = shopper.children[0];
// Randomly rotate the shopper
shopperGraphics.rotation = Math.random() * Math.PI * 2;
gameArea.addChild(shopper);
shoppers.push(shopper);
// Stagger the movement starts
LK.setTimeout(function (s) {
return function () {
s.startMoving();
};
}(shopper), i * 300);
}
}
function setupEventTimers() {
// Special deals event (every 10-15 seconds)
specialDealTimer = LK.setInterval(function () {
createSpecialDeal();
}, 10000 + Math.random() * 5000);
// Cleanup event (every 15-20 seconds)
cleanupTimer = LK.setInterval(function () {
createCleanupObstacle();
}, 15000 + Math.random() * 5000);
// Demon spawner event (every 20-30 seconds)
demonTimer = LK.setInterval(function () {
spawnDemon();
}, 20000 + Math.random() * 10000);
}
function createSpecialDeal() {
// Pick a random item to make a special deal
if (items.length > 0) {
var randomIndex = Math.floor(Math.random() * items.length);
var item = items[randomIndex];
if (!item.isSpecial && !item.collected) {
item.makeSpecialDeal();
// Show flash sale message
showMessage("FLASH SALE!", 2000);
}
}
}
function createCleanupObstacle() {
// Create cleanup on a random aisle
var randomAisleIndex = Math.floor(Math.random() * aisles.length);
var aisle = aisles[randomAisleIndex];
var obstacle = new Obstacle();
obstacle.x = aisle.x;
obstacle.y = 500 + Math.random() * 1500;
gameArea.addChild(obstacle);
obstacles.push(obstacle);
// Show cleanup message
showMessage("CLEANUP ON AISLE " + (randomAisleIndex + 1), 2000);
}
function updateShoppingListText() {
var listText = "Shopping List:\n";
var remainingItems = 0;
for (var i = 0; i < shoppingList.length; i++) {
var collected = false;
// Check if item has been collected
if (cart && cart.collectedItems) {
collected = cart.collectedItems.indexOf(shoppingList[i].name) !== -1;
}
if (!collected) {
remainingItems++;
listText += "• " + shoppingList[i].name + " - $" + shoppingList[i].price.toFixed(2) + "\n";
} else {
listText += "✓ " + shoppingList[i].name + " - $" + shoppingList[i].price.toFixed(2) + "\n";
}
}
if (shoppingListText) {
shoppingListText.setText(listText);
}
return remainingItems;
}
function showMessage(text, duration) {
if (messageText) {
messageText.setText(text);
messageText.visible = true;
LK.setTimeout(function () {
messageText.visible = false;
}, duration);
}
}
function createUI() {
// Create budget display
budgetText = new Text2("Budget: $0.00", {
size: 40,
fill: 0x008000
});
budgetText.anchor.set(0, 0);
LK.gui.topRight.addChild(budgetText);
// Create timer display
timerText = new Text2("Time: 0:00", {
size: 40,
fill: 0xDE2027
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// Create level display
levelText = new Text2("Level: 1", {
size: 40,
fill: 0x0071CE
});
levelText.anchor.set(1, 0);
LK.gui.topLeft.addChild(levelText);
// Move it a bit to the right to avoid the platform menu
levelText.x += 120;
// Create shopping list display
shoppingListText = new Text2("Shopping List:", {
size: 30,
fill: 0x000000
});
shoppingListText.anchor.set(1, 0);
shoppingListText.x = -20; // Move it a bit to the left to ensure visibility
LK.gui.right.addChild(shoppingListText);
// Create message text for events
messageText = new Text2("", {
size: 60,
fill: 0xFF0000
});
messageText.anchor.set(0.5, 0.5);
messageText.visible = false;
LK.gui.center.addChild(messageText);
// Create minimap in bottom left corner
miniMap = new MiniMap();
miniMap.x = 20;
miniMap.y = -250; // Position from bottom
LK.gui.bottomLeft.addChild(miniMap);
}
function updateUI() {
if (!cart) {
return;
}
// Update budget display
budgetText.setText("Budget: $" + cart.budget.toFixed(2));
// Update timer display
var minutes = Math.floor(timeRemaining / 60);
var seconds = timeRemaining % 60;
timerText.setText("Time: " + minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
// Update level display
levelText.setText("Level: " + level);
// Update shopping list
var remainingItems = updateShoppingListText();
// If no items remaining, highlight cashier to indicate checkout
if (remainingItems === 0) {
// Find cashier and set indicator
for (var c = 0; c < gameArea.children.length; c++) {
if (gameArea.children[c] instanceof Cashier) {
gameArea.children[c].showCheckoutReady();
break;
}
}
// No longer win automatically - need to go to cashier
}
}
// Handle touch/drag controls
var dragging = false;
function handleMove(x, y, obj) {
if (dragging && cart) {
// Move the cart to the touch position
cart.x = x;
cart.y = y;
// Keep within game boundaries
cart.x = Math.max(cart.width / 2, Math.min(2048 - cart.width / 2, cart.x));
cart.y = Math.max(cart.height / 2, Math.min(2732 - cart.height / 2, cart.y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (showingMainMenu) {
// Let the menu handle its own click events
return;
}
if (!gameStarted) {
initLevel();
return;
}
if (cart && Math.abs(x - cart.x) < cart.width / 2 && Math.abs(y - cart.y) < cart.height / 2) {
dragging = true;
}
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragging = false;
};
// Main game loop
var lastSecondTick = 0;
game.update = function () {
if (showingMainMenu) {
// Don't update game while showing menu
return;
}
if (!gameStarted) {
return;
}
// Update timer once per second
if (LK.ticks % 60 === 0) {
timeRemaining--;
updateUI();
// Check if time is up
if (timeRemaining <= 0) {
gameStarted = false;
showMessage("TIME'S UP!", 2000);
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
}
// Update power-up indicators every 16 frames (roughly 4 times per second)
if (cart && LK.ticks % 15 === 0) {
cart.updatePowerUpIndicator();
// Update minimap
if (miniMap) {
miniMap.update(cart, shoppers, items, obstacles, aisles);
}
}
// Apply magnet effect if active
if (cart && cart.powerUps.magnet && cart.powerUps.magnet.active && cart.magnetRange > 0) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (!item.collected && !(item instanceof PowerUp)) {
var dx = cart.x - item.x;
var dy = cart.y - item.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < cart.magnetRange) {
// Move item toward cart
var speed = 5 + (1 - distance / cart.magnetRange) * 10;
item.x += dx / distance * speed;
item.y += dy / distance * speed;
}
}
}
}
// Update all shoppers
for (var i = 0; i < shoppers.length; i++) {
shoppers[i].update();
}
// Update all obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
obstacles[j].update();
if (obstacles[j].readyToRemove) {
gameArea.removeChild(obstacles[j]);
obstacles.splice(j, 1);
}
}
// Check for collisions with cart
if (cart) {
// Check for collisions with items
for (var k = 0; k < items.length; k++) {
var item = items[k];
if (!item.collected && cart.intersects(item)) {
// Check if item is a power-up
if (item instanceof PowerUp) {
// Collect power-up
item.collect();
LK.getSound('pickup').play();
LK.setScore(LK.getScore() + 15);
// Apply the power-up effect
cart.applyPowerUp(item.type, item.duration);
showMessage(item.type.toUpperCase() + " POWER-UP!", 1000);
continue;
}
if (item.onList) {
// Collect item on shopping list
if (cart.addItem(item)) {
item.collect();
LK.getSound('pickup').play();
LK.setScore(LK.getScore() + 10);
updateUI();
} else {
// Not enough budget
if (!cart.isColliding) {
showMessage("Not enough budget!", 1000);
cart.isColliding = true;
LK.setTimeout(function () {
cart.isColliding = false;
}, 1000);
}
}
} else if (item.isSpecial) {
// Collect special item
if (cart.addItem(item)) {
item.collect();
LK.getSound('deal').play();
LK.setScore(LK.getScore() + 5);
updateUI();
} else {
// Not enough budget
if (!cart.isColliding) {
showMessage("Not enough budget!", 1000);
cart.isColliding = true;
LK.setTimeout(function () {
cart.isColliding = false;
}, 1000);
}
}
}
}
}
// Check for collisions with shoppers
for (var m = 0; m < shoppers.length; m++) {
if (cart.intersects(shoppers[m]) && !cart.isColliding) {
// Check if shield power-up is active
if (cart.powerUps.shield && cart.powerUps.shield.active) {
// Shield protects from collision
LK.getSound('collision').play();
LK.effects.flashObject(cart, 0x0000FF, 500); // Blue flash for shield
cart.isColliding = true;
showMessage("SHIELD PROTECTED YOU!", 1000);
// Move shopper away
var dx = shoppers[m].x - cart.x;
var dy = shoppers[m].y - cart.y;
var distance = Math.sqrt(dx * dx + dy * dy);
shoppers[m].x += dx / distance * 150;
shoppers[m].y += dy / distance * 150;
LK.setTimeout(function () {
cart.isColliding = false;
}, 1000);
} else {
// Collision with shopper - Game Over!
LK.getSound('collision').play();
LK.effects.flashObject(cart, 0xFF0000, 500);
cart.isColliding = true;
// Show death message and end game
showMessage("GAME OVER! Other shopper crashed into you!", 2000);
gameStarted = false;
updateUI();
LK.setTimeout(function () {
LK.showGameOver();
// Show main menu after game over
LK.setTimeout(function () {
mainMenu.visible = true;
showingMainMenu = true;
}, 1000);
}, 2000);
}
}
}
// Check for collisions with obstacles
for (var n = 0; n < obstacles.length; n++) {
if (cart.intersects(obstacles[n]) && !cart.isColliding) {
// Collision with obstacle
LK.getSound('collision').play();
LK.effects.flashObject(cart, 0xFF0000, 500);
cart.isColliding = true;
// Penalty
timeRemaining = Math.max(0, timeRemaining - 3);
updateUI();
LK.setTimeout(function () {
cart.isColliding = false;
}, 1000);
}
}
// Update and check collision with demon from initial level
if (game.demon && game.demon.active) {
// Update demon
game.demon.update();
// Check if demon collided with cashier
for (var c = 0; c < gameArea.children.length; c++) {
if (gameArea.children[c] instanceof Cashier && game.demon.intersects(gameArea.children[c]) && game.demon.active) {
// Demon reached cashier - Game Over!
LK.getSound('collision').play();
LK.effects.flashScreen(0xFF0000, 1000);
showMessage("GAME OVER! Demon reached the cashier!", 2000);
gameStarted = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
return;
}
}
// Check if player touched the demon
if (cart && cart.intersects(game.demon) && !cart.isColliding) {
// Player touched demon - defeat it!
game.demon.hit();
game.demon.active = false;
LK.getSound('pickup').play();
LK.setScore(LK.getScore() + 50);
showMessage("DEMON DEFEATED! +50 POINTS", 2000);
// Make demon disappear slowly
tween(game.demon, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
gameArea.removeChild(game.demon);
}
});
}
}
// Update and check collision with spawned demons
for (var d = demons.length - 1; d >= 0; d--) {
var currentDemon = demons[d];
// Update demon
if (currentDemon.active) {
currentDemon.update();
// Check if demon collided with cashier
for (var c = 0; c < gameArea.children.length; c++) {
if (gameArea.children[c] instanceof Cashier && currentDemon.intersects(gameArea.children[c]) && currentDemon.active) {
// Demon reached cashier - Game Over!
LK.getSound('collision').play();
LK.effects.flashScreen(0xFF0000, 1000);
showMessage("GAME OVER! Demon reached the cashier!", 2000);
gameStarted = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
return;
}
}
// Check if player touched the demon
if (cart && cart.intersects(currentDemon) && !cart.isColliding) {
// Player touched demon - defeat it!
currentDemon.hit();
currentDemon.active = false;
LK.getSound('pickup').play();
LK.setScore(LK.getScore() + 50);
showMessage("DEMON DEFEATED! +50 POINTS", 2000);
// Make demon disappear slowly
tween(currentDemon, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function (demonIndex) {
return function () {
if (demons[demonIndex]) {
gameArea.removeChild(demons[demonIndex]);
demons.splice(demonIndex, 1);
}
};
}(d)
});
// Set cart as colliding briefly to prevent multiple demon hits
cart.isColliding = true;
LK.setTimeout(function () {
cart.isColliding = false;
}, 500);
}
}
}
// Check for collision with cashier for level completion
for (var c = 0; c < gameArea.children.length; c++) {
if (gameArea.children[c] instanceof Cashier && cart.intersects(gameArea.children[c])) {
// Check if all items have been collected
var remainingItems = updateShoppingListText();
if (remainingItems === 0 && !cart.isColliding) {
// Level complete!
level++;
showMessage("CHECKOUT COMPLETE! LEVEL UP!", 3000);
LK.setTimeout(initLevel, 3000);
gameStarted = false;
// Award bonus points for remaining time
var timeBonus = timeRemaining * 2;
LK.setScore(LK.getScore() + timeBonus);
break;
} else if (remainingItems > 0 && !cart.isColliding) {
// Still have items to collect
showMessage("Finish your shopping first!", 1000);
cart.isColliding = true;
LK.setTimeout(function () {
cart.isColliding = false;
}, 1000);
}
}
}
}
};
// Initialize UI
createUI();
// Don't show start instructions since we now have a menu
function createPowerUps() {
// Create 3 power-ups of different types, randomly placed in aisles
var powerUpTypes = ['speed', 'magnet', 'shield'];
for (var i = 0; i < powerUpTypes.length; i++) {
var powerUp = new PowerUp();
var aisleIndex = Math.floor(Math.random() * aisles.length);
var aisle = aisles[aisleIndex];
powerUp.x = aisle.x + (Math.random() * 200 - 100);
powerUp.y = 200 + Math.random() * (2732 - 400);
powerUp.setType(powerUpTypes[i]);
gameArea.addChild(powerUp);
items.push(powerUp); // Add to items array for collision detection
}
}
function spawnDemon() {
if (!gameStarted) {
return;
}
// Create a new demon
var newDemon = new ShoppingDemon();
// Place demon at a random edge of the screen
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
newDemon.x = Math.random() * 2048;
newDemon.y = 50;
break;
case 1:
// Right
newDemon.x = 2048 - 50;
newDemon.y = Math.random() * 2732;
break;
case 2:
// Bottom
newDemon.x = Math.random() * 2048;
newDemon.y = 2732 - 50;
break;
case 3:
// Left
newDemon.x = 50;
newDemon.y = Math.random() * 2732;
break;
}
// Find the cashier to target
for (var c = 0; c < gameArea.children.length; c++) {
if (gameArea.children[c] instanceof Cashier) {
newDemon.setTarget(gameArea.children[c]);
break;
}
}
// Initialize tracking properties
newDemon.lastX = newDemon.x;
newDemon.lastY = newDemon.y;
// Add to game
gameArea.addChild(newDemon);
demons.push(newDemon);
// Show warning message
showMessage("SHOPPING DEMON APPROACHING!", 2000);
}
Top-down image of a shopping cart. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Top-down image of a person. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Sale! Sign. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Water spill. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Box of food. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Shield. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Cart with letters saying WALMART DASH!. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows