/**** * Classes ****/ var CloseButton = Container.expand(function (shopInstance) { var self = Container.call(this); self.shopInstance = shopInstance; var itemBg = self.attachAsset('closeButton', { anchorX: 0.5, anchorY: 0.5, x: 740, y: -780 }); self.down = function (x, y, obj) { shop.visible = false; addCustomers(dailyCustomerAmount); }; }); var CustomerBase = Container.expand(function () { var self = Container.call(this); var sprite = 'customer' + Math.ceil(Math.random() * 8); var customerGraphics = self.attachAsset(sprite, { anchorX: 0.5, anchorY: 0.5 }); self.anchorX = 0.5; self.anchorY = 0.5; self.done = false; self.delay = 0; self.happy = false; self.update = function () { if (self.done) { if (self.delay-- <= 0) { self.x += queueSpeed * 8; self.y += Math.cos(LK.ticks / 2) * 15 * (Math.random() * 0.3 + 0.7); self.rotation += 0.05 - Math.random() * 0.1; if (self.happy && LK.ticks % 10 == 0) { createHeartExplosion(self.x, self.y - 100); } if (self.x > 2300) { self.destroy(); } } } }; }); // Customer1 class // EmptyGlass class var EmptyGlass = Container.expand(function () { var self = Container.call(this); var emptyGlassGraphics = self.attachAsset('emptyGlass', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); /* var fillGlassGraphics = self.attachAsset('emptyGlass', { anchorX: 0.5, anchorY: 0.5, alpha: 1, tint: '0xffff00' });*/ var fullText = new Text2('0%', { size: 100, fill: "#ffffff", stroke: '#000000', strokeThickness: 10, weight: 300, anchorX: 0.5, anchorY: 0.5 }); fullText.x = -50; fullText.y = -50; self.addChild(fullText); self.update = function () { // EmptyGlass specific update logic }; self.updateText = function (i) { fullText.setText(i + '%'); fullText.x = -50 - fullText.width / 4; }; }); var GameOverBackground = Container.expand(function (shopInstance) { var self = Container.call(this); var bg = self.attachAsset('gameOverBackground', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2732 / 2 }); var goText = new Text2('', { size: 85, fill: "#ffffff", stroke: '#000000', strokeThickness: 10, weight: 300, align: 'left' }); var finalScore = totalEarned * 2 + drinksServed * 3 + daysSpent * 10; var text = 'Congratulations!\n- You worked hard and finally get to enjoy summer!\n'; text += '- You served ' + drinksServed + ' drinks and lemonades\n'; text += '- You made ' + totalEarned + ' $'; text += ' in ' + daysSpent + ' days\n\nYour final score is ' + finalScore + '\n\n'; goText.setText(text); goText.x = 20; goText.y = 500; self.addChild(goText); var endText = new Text2('(Click anywhere to submit your score and end the game.)', { size: 65, fill: "#ffffff", stroke: '#000000', strokeThickness: 10, weight: 300, align: 'left' }); endText.x = 20; endText.y = 1250; self.addChild(endText); self.on('down', function () { LK.setScore(finalScore); LK.showGameOver(); }); }); // Girl class var Girl = Container.expand(function () { var self = Container.call(this); var girlGraphics = self.attachAsset('girl', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Girl specific update logic }; }); var GreenCheckmark = Container.expand(function () { var self = Container.call(this); var checkmarkGraphics = self.attachAsset('greenCheckmark', { anchorX: 0.5, anchorY: 0.5 }); }); var Heart = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.scale.x = self.scale.y = 0.8 + Math.random() * 0.7; self.lifetime = 0; self.delay = 0; self.update = function () { if (self.delay-- <= 0) { self.x += self.vx; self.y += self.vy; self.lifetime--; if (self.lifetime <= 0) { self.destroy(); } } }; }); // Ice class var Ice = Container.expand(function () { var self = Container.call(this); var iceGraphics = self.attachAsset('ice', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Ice specific update logic }; }); // IngredientButton class var IngredientButton = Container.expand(function (i, k) { var self = Container.call(this); self.done = false; self.right = false; var ingredientButtonGraphics = self.attachAsset('ingredientButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.75, scaleY: 0.75 //x: i * 400 //(i - item.ingredients.length / 2) * 400 }); var ingredientSprite = LK.getAsset('' + k, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.75, scaleY: 0.75 //x: ingredientButton.x //i * 400 //(i - item.ingredients.length / 2) * 400 }); self.addChild(ingredientSprite); self.moveTo = function (targetX, targetY, duration) { var startX = self.x; var startY = self.y; var bezierPoints = generateBezierPoints({ x: startX, y: startY }, { x: targetX, y: targetY }, { x: 400, //(startX + targetX) / 2, y: 200 //startY - 200 }, { x: 1600, //(startX + targetX) / 2, y: 200 //targetY + 200 }, duration * 60); var currentTick = 0; self.update = function () { if (currentTick < bezierPoints.length) { self.x = bezierPoints[currentTick].x; self.y = bezierPoints[currentTick].y; self.scale.x -= 0.003; self.scale.y -= 0.003; currentTick++; } else { self.x = targetX; self.y = targetY; // Stop updating once the target is reached self.update = null; self.done = true; //LK.setScore(LK.getScore() + 1); //scoreTxt.setText('$ ' + LK.getScore()); emptyGlass.updateText(Math.floor(100 * currentOrderedItemCompletion / currentOrderedItemSize)); // Check if drink is ready. (Todo: Maybe wait a second while it mixes before removing it all.) var countDone = 0; for (var i = 0; i < ingredientButtons.length; i++) { if (ingredientButtons[i].done) { countDone++; } } emptyGlass.updateText(Math.floor(100 * countDone / currentOrderedItemSize)); //if (currentOrderedItemCompletion == currentOrderedItemSize && allDone) { if (countDone == currentOrderedItemSize) { // Remove emptyGlass and ingredients and replace with the drink. emptyGlass.destroy(); instructionLabel.visible = false; createStarExplosion(emptyGlass.x - 100, emptyGlass.y); for (var i = 0; i < ingredientButtons.length; i++) { ingredientButtons[i].destroy(); } ingredientButtons = []; // Also remove the speechBubble here. speechBubble.destroy(); // But we can maybe reuse the itemSprite instead of destroying. itemSprite.x = 1500; itemSprite.y = 1400; itemSprite.scale.x = 2.2; itemSprite.scale.y = 2.2; // Move itemSprite to the rightmost customer and scale it down var rightmostCustomer = customers[0]; //customers[customers.length - 1]; moveDrinkToCustomer(itemSprite, rightmostCustomer.x, rightmostCustomer.y, 1); //LK.setScore(LK.getScore() + currentOrder.price); coins += currentOrder.price; scoreTxt.setText('$ ' + coins); totalEarned += currentOrder.price; // TODO: Here a few coins should flip from customer to girl and money label be upgraded //customers[0].addChild(itemSprite); //waitCounter = 100; //itemSprite.destroy(); } } }; }; // Event handler called when a press happens on element. self.down = function (x, y, obj) { ingredientButtonGraphics.alpha = 0; if (self.right) { currentOrderedItemCompletion++; // Try to move the completion status of current order to give a Y position of theingredient in the glass var destY = emptyGlass.y + emptyGlass.height / 2 - currentOrderedItemCompletion * 150; // Also try to give the X position a bit of variation / alternation. var destX = currentOrderedItemCompletion % 2 == 0 ? 25 : -25; self.moveTo(emptyGlass.x + destX, destY, 1); self.down = null; } else { // Show a minus $2 sign and move button down. var minusSign = new minusPopup(); minusSign.x = self.x; minusSign.y = self.y - 200; coins -= 2; if (coins < 0) { coins = 0; } scoreTxt.setText('$ ' + coins); game.addChild(minusSign); self.moveDown(1024, 5000, 1); self.down = null; } }; self.moveDown = function (targetX, targetY, duration) { var startX = self.x; var startY = self.y; var bezierPoints = generateBezierPoints({ x: startX, y: startY }, { x: targetX, y: targetY }, { x: 1024, //(startX + targetX) / 2, y: 2000 //startY - 200 }, { x: 1024, //(startX + targetX) / 2, y: 2000 //targetY + 200 }, duration * 60); var currentTick = 0; self.update = function () { if (currentTick < bezierPoints.length) { self.x = bezierPoints[currentTick].x; self.y = bezierPoints[currentTick].y; self.scale.x -= 0.003; self.scale.y -= 0.003; currentTick++; } else { self.x = targetX; self.y = targetY; // Stop updating once the target is reached self.update = null; //self.done = true; } }; }; }); //<Assets used in the game will automatically appear here> // Lemon class var Lemon = Container.expand(function () { var self = Container.call(this); var lemonGraphics = self.attachAsset('lemon', { anchorX: 0.5, anchorY: 0.5 }); }); // LemonadeStand class var LemonadeStand = Container.expand(function () { var self = Container.call(this); var standGraphics = self.attachAsset('stand', { anchorX: 0.5, anchorY: 0.5 }); }); var ShopItem = Container.expand(function (id, price) { var self = Container.call(this); // Initialize shop item properties self.id = id; self.price = price; self.purchased = false; self.maxed = false; self.recipe = ''; var itemBg = self.attachAsset('shopItemBackground', { anchorX: 0.5, anchorY: 0.5 }); // Attach asset based on the item id var itemGraphic = self.attachAsset(self.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); var nameTxt = new Text2('', { size: 42, fill: "#ffffff", stroke: '#2B1700', strokeThickness: 10 }); //orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie if (self.id == 'orangeJuice') { nameTxt.setText('Orange Juice'); self.recipe = '- Orange\n- Ice Water'; } else if (self.id == 'strawberryDrink') { nameTxt.setText('Strawberry Daiquiry'); self.recipe = '- Strawberry\n- Sugar\n- Ice Water'; } else if (self.id == 'watermelonDrink') { nameTxt.setText('Melon Slush'); self.recipe = '- Watermelon\n- Strawberry\n- Ice Water'; } else if (self.id == 'bananaMilkshake') { nameTxt.setText('Banana Milkshake'); self.recipe = '- Banana\n- Milk\n- Ice'; } else if (self.id == 'berriesDrink') { nameTxt.setText('Berries Lemonade'); self.recipe = '- Strawberry\n- Blueberry\n- Sugar\n- Ice Water'; } else if (self.id == 'pinaDrink') { nameTxt.setText('PiƱa Colada'); self.recipe = '- Coconut\n- Pineapple\n- Milk'; } else if (self.id == 'mangoLassie') { nameTxt.setText('Mango Lassie'); self.recipe = '- Mango\n- Sugar\n- Milk'; } else if (self.id == 'yacht') { nameTxt.setText('Dream Boat'); self.recipe = 'Finally!\nMy dream boat\nis mine!'; } //nameTxt.x = -self.width / 2; nameTxt.x -= nameTxt.width / 2; nameTxt.y = -self.height / 2 - nameTxt.height; self.addChild(nameTxt); var costTxt = new Text2('', { size: 42, fill: "#ffffff", stroke: '#2B1700', strokeThickness: 10 }); costTxt.setText('' + self.price); costTxt.x = -30; costTxt.y = self.height / 2 - 65; self.addChild(costTxt); var upgradeButton = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5 }); upgradeButton.scale.x = upgradeButton.scale.y = 0.9; upgradeButton.y = 275; upgradeButton.alpha = 1; var bTxt = new Text2('', { size: 42, fill: "#ffffff", stroke: '#2B1700', strokeThickness: 10 }); bTxt.setText('Buy'); bTxt.x = -36; bTxt.y = self.height / 2 - 40; self.addChild(bTxt); // Method to reset the item's purchase state (optional, depending on game design) self.reset = function () { self.purchased = false; // Optionally, update the item's appearance to indicate it's not purchased }; self.bought = function () { //console.log('updateCost called'); //costTxt.destroy(); costTxt.y += 26; //costTxt.fill = '#cccccc'; costTxt.setText(self.recipe); costTxt.x = -costTxt.width / 2; upgradeButton.destroy(); bTxt.destroy(); self.maxed = true; scoreTxt.setText('$ ' + coins); //todo, maybe add green checkmark to indicate already owned. var green = new GreenCheckmark(); green.x = 110; //self.width / 2 - green.width / 2; green.y = 110; //self.height / 2 - green.height / 2; self.addChild(green); dailyCustomerAmount++; }; }); var ShopWindow = Container.expand(function () { var self = Container.call(this); // Initialize shop window properties and background graphic self.items = []; // Array to hold shop items self.x = 1024; // Center horizontally self.y = 1360; //1566; // Center vertically self.visible = false; // Initially hidden self.scale.x = 1.0; self.scale.y = 1.0; // Add background graphic to shop window var backgroundGraphic = self.attachAsset('shopBackground', { anchorX: 0.5, anchorY: 0.5, x: 30, y: 0 }); // [orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie] // 7,10,12,15,20,25,30 self.addChild(backgroundGraphic); var item1 = new ShopItem('orangeJuice', 30); item1.x = -540; item1.y = -350; var item2 = new ShopItem('strawberryDrink', 50); item2.x = -180; item2.y = -350; var item3 = new ShopItem('watermelonDrink', 75); item3.x = 180; item3.y = -350; var item4 = new ShopItem('bananaMilkshake', 100); item4.x = 540; item4.y = -350; var item5 = new ShopItem('berriesDrink', 150); item5.x = -540; item5.y = 300; var item6 = new ShopItem('pinaDrink', 200); item6.x = -180; item6.y = 300; var item7 = new ShopItem('mangoLassie', 250); item7.x = 180; item7.y = 300; var item8 = new ShopItem('yacht', 500); item8.x = 540; item8.y = 300; self.addChild(item1); self.addChild(item2); self.addChild(item3); self.addChild(item4); self.addChild(item5); self.addChild(item6); self.addChild(item7); self.addChild(item8); // [orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie] item1.down = function (x, y, obj) { if (coins >= item1.price && !item1.maxed) { coins -= item1.price; item1.bought(); availableItems.push(orangeJuice); } }; item2.down = function (x, y, obj) { if (coins >= item2.price && !item2.maxed) { coins -= item2.price; item2.bought(); availableItems.push(strawberryDrink); } }; item3.down = function (x, y, obj) { if (coins >= item3.price && !item3.maxed) { coins -= item3.price; item3.bought(); availableItems.push(watermelonDrink); } }; item4.down = function (x, y, obj) { if (coins >= item4.price && !item4.maxed) { coins -= item4.price; item4.bought(); availableItems.push(bananaMilkshake); } }; item5.down = function (x, y, obj) { if (coins >= item5.price && !item5.maxed) { coins -= item5.price; item5.bought(); availableItems.push(berriesDrink); } }; item6.down = function (x, y, obj) { if (coins >= item6.price && !item6.maxed) { coins -= item6.price; item6.bought(); availableItems.push(pinaDrink); } }; item7.down = function (x, y, obj) { if (coins >= item7.price && !item7.maxed) { coins -= item7.price; item7.bought(); availableItems.push(mangoLassie); } }; item8.down = function (x, y, obj) { if (coins >= item8.price && !item8.maxed) { coins -= item8.price; item8.bought(); //availableItems.push(watermelonDrink); // TODO: Finally bought the yacht. var gob = new GameOverBackground(); game.addChild(gob); scoreTxt.destroy(); } }; var shopTxt = new Text2('Time to shop for new recipes', { size: 80, fill: "#ffffff", stroke: "#2B1700", strokeThickness: 10, align: 'center', weight: 800 }); shopTxt.anchor.set(0.5, 0.5); // Sets anchor to the center of the bottom edge of the text. shopTxt.y = -self.height / 2 + 720; self.addChild(shopTxt); var closeButton = new CloseButton(self); self.addChild(closeButton); self.show = function () { game.addChild(self); self.visible = true; }; self.hide = function () { self.visible = false; }; }); var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.lifetime = 0; self.update = function () { self.x += self.vx; self.y += self.vy; self.lifetime--; if (self.lifetime <= 0) { self.destroy(); } }; }); // Sugar class var Sugar = Container.expand(function () { var self = Container.call(this); var sugarGraphics = self.attachAsset('sugar', { anchorX: 0.5, anchorY: 0.5 }); }); var earnedPopup = Container.expand(function (money) { var self = Container.call(this); var mText = new Text2('$' + money, { size: 90, fill: "#eeee33", stroke: '#000000', strokeThickness: 10, weight: 800 }); self.addChild(mText); self.update = function () { self.y -= 8; if (self.y < 1000) { self.destroy(); } }; }); var minusPopup = Container.expand(function () { var self = Container.call(this); var mText = new Text2('-2$', { size: 90, fill: "#ff3333", stroke: '#000000', strokeThickness: 10, weight: 800 }); self.addChild(mText); self.update = function () { self.y -= 8; if (self.y < 1400) { self.destroy(); } }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Init game with sky blue background }); /**** * Game Code ****/ var drinksServed = 0; var daysSpent = 0; var instructionTxt; function updateCoinsText() { coinsTxt.setText('Star Coins: ' + coins); } function showMoneyEarned(x, y, money) { y -= 150; var mText = new earnedPopup(money); mText.x = x; mText.y = y; game.addChild(mText); } ; var coins = 0; function createHeartExplosion(x, y) { //y -= 50; y -= 25 + Math.random() * 75; var heartCount = 1; var heartSpeed = 6; var heartLifetime = 60; // frames for (var i = 0; i < heartCount; i++) { var heart = new Heart(); heart.x = x; heart.y = y; // - 30 * i; heart.delay = i * 6; var rand = Math.random() * Math.PI / 8; heart.rotation += Math.random() < 0.5 ? rand : -rand; heart.vx = (Math.random() - 0.5) * heartSpeed * 0.2; heart.vy = -heartSpeed; //-Math.random() * heartSpeed; heart.lifetime = heartLifetime; game.addChild(heart); } } /** * Creates a star explosion effect at the specified coordinates. * * @param {Number} x - The x-coordinate of the explosion center. * @param {Number} y - The y-coordinate of the explosion center. */ function createStarExplosion(x, y) { var starCount = 20; var starSpeed = 30; var starLifetime = 120; // frames for (var i = 0; i < starCount; i++) { var star = new Star(); star.x = x; star.y = y; var angle = i / starCount * 2 * Math.PI; star.vx = starSpeed * Math.cos(angle); star.vy = starSpeed * Math.sin(angle); star.lifetime = starLifetime; game.addChild(star); } } function globalMoveTo() { self.x--; } ; var lemonadeStand; var scoreTxt; var score = 0; var background = game.addChild(LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, x: 1024, y: 2732 / 2 })); function easeOutBounce(x) { var n1 = 7.5625; var d1 = 2.75; if (x < 1 / d1) { return n1 * x * x; } else if (x < 2 / d1) { return n1 * (x -= 1.5 / d1) * x + 0.75; } else if (x < 2.5 / d1) { return n1 * (x -= 2.25 / d1) * x + 0.9375; } else { return n1 * (x -= 2.625 / d1) * x + 0.984375; } } ; function easeOutElastic(x) { //var c4 = 2 * Math.PI / 3; var c4 = 2 * Math.PI / .3; //return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1; //return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1; return x === 0 ? 0 : x === 1 ? 1 : 0.25 * Math.pow(2, -5 * x) * Math.cos((x * 10 - 0.75) * c4) + 1; } // Initialize game elements function initGameElements() { // Create and position girl var girl = new Girl(); girl.x = 2048 / 2; girl.y = 2732 - 1150; game.addChild(girl); // Create and position lemonade stand lemonadeStand = new LemonadeStand(); lemonadeStand.x = 2048 / 2; lemonadeStand.y = 2732 - 1100; game.addChild(lemonadeStand); // Create and position score text scoreTxt = new Text2('$ 0', { size: 100, fill: "#33ee33", stroke: '#000000', strokeThickness: 10, weight: 300 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); } // Update score function updateScore() { scoreTxt.setText('$ ' + score); } // Initialize game elements initGameElements(); var customerTypes = [CustomerBase]; //[Customer1, Customer2, Customer3, Customer4, Customer5, Customer6, Customer7, Customer8]; var customers = []; var backgroundOverlay = game.addChild(LK.getAsset('backgroundOverlay', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, x: 1024, y: 2732 / 2 })); var dailyCustomerAmount = 7; addCustomers(dailyCustomerAmount); function addCustomers(amount) { daysSpent++; for (var i = 0; i < amount; i++) { //var t = new customerTypes[Math.floor(Math.random() * customerTypes.length)](); var t = new CustomerBase(); t.y = 1800; t.x = 500 - 250 * i - 50; t.anchorY = 2; game.addChild(t); customers.push(t); queueUpdateCounter = 0; // re-add the foreground overlay game.addChild(backgroundOverlay); } } ; var lemonade = { sprite: 'lemonade', offsetX: 25, offsetY: -300, ingredients: ['lemon', 'sugar', 'water'], price: 5 }; var orangeJuice = { sprite: 'orangeJuice', offsetX: 60, offsetY: -300, ingredients: ['orange', 'water'], price: 7 }; var strawberryDrink = { sprite: 'strawberryDrink', offsetX: 25, offsetY: -300, ingredients: ['strawberry', 'sugar', 'water'], price: 10 }; var watermelonDrink = { sprite: 'watermelonDrink', offsetX: 45, offsetY: -320, ingredients: ['watermelon', 'strawberry', 'water'], price: 12 }; var bananaMilkshake = { sprite: 'bananaMilkshake', offsetX: 45, offsetY: -300, ingredients: ['banana', 'milk', 'water'], price: 15 }; var berriesDrink = { sprite: 'berriesDrink', offsetX: 45, offsetY: -300, ingredients: ['strawberry', 'blueberry', 'sugar', 'water'], price: 20 }; var pinaDrink = { sprite: 'pinaDrink', offsetX: 25, offsetY: -300, ingredients: ['coconut', 'pineapple', 'milk'], price: 25 }; var mangoLassie = { sprite: 'mangoLassie', offsetX: 45, offsetY: -300, ingredients: ['mango', 'sugar', 'milk'], price: 30 }; var allIngredients = ['orange', 'coconut', 'pineapple', 'milk', 'blueberry', 'strawberry', 'watermelon', 'banana', 'sugar', 'water']; var lockedItems = [orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie]; var availableItems = [lemonade]; //[lemonade]; var currentOrder; var currentOrderedItemSize = 0; var currentOrderedItemCompletion = 0; var ingredientButtons = []; var speechBubble; var itemSprite; function orderSomething(obj) { var item = availableItems[Math.floor(Math.random() * availableItems.length)]; currentOrder = item; // just to have a reference in the gobal scope. speechBubble = LK.getAsset('speechBubble', { anchorX: 0.5, anchorY: 1, scaleX: 0.5, scaleY: 0.5, x: obj.x - 250, y: obj.y - obj.height / 2 - 50, rotation: 0.12, alpha: 0.9 }); game.addChild(speechBubble); // Add the sprite of the ordered item inside the speech bubble itemSprite = LK.getAsset(item.sprite, { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, x: speechBubble.x + item.offsetX, y: speechBubble.y + item.offsetY }); game.addChild(itemSprite); // Display the ingredients of the ordered item at the bottom center of the screen if (false) { currentOrderedItemCompletion = 0; currentOrderedItemSize = item.ingredients.length; for (var i = 0; i < currentOrderedItemSize; i++) { var ingredientButton = new IngredientButton(i, item.ingredients[i]); ingredientButton.x = i * 400; ingredientButton.y = 2732 - 500; game.addChild(ingredientButton); if (currentOrderedItemSize == 2) { ingredientButton.x += 800; } else if (currentOrderedItemSize == 3) { ingredientButton.x += 600; } else if (currentOrderedItemSize == 4) { ingredientButton.x += 400; // += 200; } ingredientButtons.push(ingredientButton); } } else { //TODO: maybe make a random or knowledge check to determine if player can make this recipe. // Add the normal options. var buttons = item.ingredients; // Add 1 (or more?) wrong ingredient among the options. var random = buttons[0]; while (buttons.includes(random)) { random = allIngredients[Math.floor(Math.random() * allIngredients.length)]; } var wrongIngredientButton = new IngredientButton(0, random); wrongIngredientButton.right = false; wrongIngredientButton.y = 2732 - 500; game.addChild(wrongIngredientButton); ingredientButtons.push(wrongIngredientButton); // Add the right buttons. // Let the buttons know if they're right or wrong for this recipe, so they can handle presses. currentOrderedItemCompletion = 0; currentOrderedItemSize = item.ingredients.length; for (var i = 0; i < currentOrderedItemSize; i++) { var ingredientButton = new IngredientButton(i, item.ingredients[i]); ingredientButton.y = 2732 - 500; ingredientButton.right = true; game.addChild(ingredientButton); ingredientButtons.push(ingredientButton); } //console.log('before ' + ingredientButtons[0].right); // Shuffle buttons using fisher-yates. fy(ingredientButtons, 0, 0, 0); // Align the buttons. for (var i = 0; i < ingredientButtons.length; i++) { var ingredientButton = ingredientButtons[i]; ingredientButton.x = i * 400; if (currentOrderedItemSize == 2) { ingredientButton.x += 600; } else if (currentOrderedItemSize == 3) { ingredientButton.x += 400; } else if (currentOrderedItemSize == 4) { ingredientButton.x += 200; // += 200; } } //console.log('after ' + ingredientButtons[0].right); //console.table([ingredientButtons[0], ingredientButtons[1], ingredientButtons[2]], ["correct"]); // Display a label 'Add the 2 (or 3 or 4) right ingredient. instructionLabel = new Text2('Add the ' + currentOrderedItemSize + ' right ingredients.', { size: 100, fill: "#ffffff", stroke: '#000000', strokeThickness: 10, weight: 300, align: 'center' }); instructionLabel.x = 1024 - instructionLabel.width / 2; instructionLabel.y = 2500; //instructionLabel.anchor.set(0.5, 0); game.addChild(instructionLabel); // How should wrong ingredient behave when pressed? Maybe move offscreen - with a -2$ sign shown in red? } // Add an empty glass emptyGlass = new EmptyGlass(); game.addChild(emptyGlass); emptyGlass.x = 1600; emptyGlass.y = 1400; } var instructionLabel; function fy(a, b, c, d) { //array,placeholder,placeholder,placeholder c = a.length; while (c) { b = Math.random() * c-- | 0, d = a[c], a[c] = a[b], a[b] = d; } } /** * Generates an array of points along a two-point Bezier curve. * * @param {Object} start - The starting point of the curve {x: Number, y: Number}. * @param {Object} end - The ending point of the curve {x: Number, y: Number}. * @param {Object} anchor1 - The first anchor point of the curve {x: Number, y: Number}. * @param {Object} anchor2 - The second anchor point of the curve {x: Number, y: Number}. * @param {Number} n - The number of points to generate along the curve. * @returns {Array} - An array of points along the Bezier curve. */ function generateBezierPoints(start, end, anchor1, anchor2, n) { var points = []; for (var i = 0; i <= n; i++) { var t = i / n; var x = Math.pow(1 - t, 3) * start.x + 3 * Math.pow(1 - t, 2) * t * anchor1.x + 3 * (1 - t) * Math.pow(t, 2) * anchor2.x + Math.pow(t, 3) * end.x; var y = Math.pow(1 - t, 3) * start.y + 3 * Math.pow(1 - t, 2) * t * anchor1.y + 3 * (1 - t) * Math.pow(t, 2) * anchor2.y + Math.pow(t, 3) * end.y; points.push({ x: x, y: y }); } return points; } ; var totalEarned = 0; var emptyGlass; //var harvestedCounter = 0; var queueSpeed = 3; var queueUpdateCounter = 0; var queueUpdateMax = 240 / queueSpeed; var orderPlaced = false; var waitCounter = 0; function updateCustomers() { if (waitCounter-- > 0) {} else if (!shop.visible) { if (queueUpdateCounter < queueUpdateMax) { queueUpdateCounter++; for (var i = 0; i < customers.length; i++) { customers[i].x += queueSpeed; customers[i].y += Math.cos(LK.ticks / 2) * 15 * (Math.random() * 0.3 + 0.7); customers[i].rotation += 0.05 - Math.random() * 0.1; //customers[i].rotation += LK.ticks % 6 < 3 ? 0.05 : -0.05; } /* if (customers[i].happy && LK.ticks % 10 == 0) { createHeartExplosion(customers[i].x, customers[i].y - 100); }*/ } else if (queueUpdateCounter >= queueUpdateMax && !orderPlaced) { for (var i = 0; i < customers.length; i++) { customers[i].rotation = 0; customers[i].y = 1800; } if (customers.length > 0) { orderSomething(customers[0]); orderPlaced = true; } else if (!shop.visible) { shop.show(); } } } } ; var shop = new ShopWindow(); game.addChild(shop); game.update = function () { updateCustomers(); //itemSprite.update(); }; function moveDrinkToCustomer(sprite, targetX, targetY, duration) { targetX += 50; targetY += 50; var startX = sprite.x; var startY = sprite.y; var startScaleX = sprite.scale.x; var startScaleY = sprite.scale.y; var endScale = 0.3; var bezierPoints = generateBezierPoints({ x: startX, y: startY }, { x: targetX, y: targetY }, { x: (startX + targetX) / 2, y: startY - 200 }, { x: (startX + targetX) / 2, y: targetY + 200 }, duration * 60); var currentTick = 0; sprite.update = function () { if (currentTick < bezierPoints.length) { sprite.x = bezierPoints[currentTick].x; sprite.y = bezierPoints[currentTick].y; sprite.scale.x = startScaleX - (startScaleX - endScale) * (currentTick / bezierPoints.length); sprite.scale.y = startScaleY - (startScaleY - endScale) * (currentTick / bezierPoints.length); currentTick++; } else { sprite.x = 3000; sprite.y = targetY; sprite.scale.x = endScale; sprite.scale.y = endScale; sprite.update = null; //createHeartExplosion(targetX, targetY - 100); showMoneyEarned(targetX, targetY - 100, currentOrder.price); customers[0].happy = true; drinksServed++; var customerDrink = LK.getAsset(currentOrder.sprite, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, x: 50, y: 50 }); customers[0].addChild(customerDrink); customers[0].done = true; customers.splice(0, 1); // This causes the updateCustomers in game.update() to advance the queue. queueUpdateCounter = 0; orderPlaced = false; } }; }
/****
* Classes
****/
var CloseButton = Container.expand(function (shopInstance) {
var self = Container.call(this);
self.shopInstance = shopInstance;
var itemBg = self.attachAsset('closeButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 740,
y: -780
});
self.down = function (x, y, obj) {
shop.visible = false;
addCustomers(dailyCustomerAmount);
};
});
var CustomerBase = Container.expand(function () {
var self = Container.call(this);
var sprite = 'customer' + Math.ceil(Math.random() * 8);
var customerGraphics = self.attachAsset(sprite, {
anchorX: 0.5,
anchorY: 0.5
});
self.anchorX = 0.5;
self.anchorY = 0.5;
self.done = false;
self.delay = 0;
self.happy = false;
self.update = function () {
if (self.done) {
if (self.delay-- <= 0) {
self.x += queueSpeed * 8;
self.y += Math.cos(LK.ticks / 2) * 15 * (Math.random() * 0.3 + 0.7);
self.rotation += 0.05 - Math.random() * 0.1;
if (self.happy && LK.ticks % 10 == 0) {
createHeartExplosion(self.x, self.y - 100);
}
if (self.x > 2300) {
self.destroy();
}
}
}
};
});
// Customer1 class
// EmptyGlass class
var EmptyGlass = Container.expand(function () {
var self = Container.call(this);
var emptyGlassGraphics = self.attachAsset('emptyGlass', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
/*
var fillGlassGraphics = self.attachAsset('emptyGlass', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1,
tint: '0xffff00'
});*/
var fullText = new Text2('0%', {
size: 100,
fill: "#ffffff",
stroke: '#000000',
strokeThickness: 10,
weight: 300,
anchorX: 0.5,
anchorY: 0.5
});
fullText.x = -50;
fullText.y = -50;
self.addChild(fullText);
self.update = function () {
// EmptyGlass specific update logic
};
self.updateText = function (i) {
fullText.setText(i + '%');
fullText.x = -50 - fullText.width / 4;
};
});
var GameOverBackground = Container.expand(function (shopInstance) {
var self = Container.call(this);
var bg = self.attachAsset('gameOverBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2732 / 2
});
var goText = new Text2('', {
size: 85,
fill: "#ffffff",
stroke: '#000000',
strokeThickness: 10,
weight: 300,
align: 'left'
});
var finalScore = totalEarned * 2 + drinksServed * 3 + daysSpent * 10;
var text = 'Congratulations!\n- You worked hard and finally get to enjoy summer!\n';
text += '- You served ' + drinksServed + ' drinks and lemonades\n';
text += '- You made ' + totalEarned + ' $';
text += ' in ' + daysSpent + ' days\n\nYour final score is ' + finalScore + '\n\n';
goText.setText(text);
goText.x = 20;
goText.y = 500;
self.addChild(goText);
var endText = new Text2('(Click anywhere to submit your score and end the game.)', {
size: 65,
fill: "#ffffff",
stroke: '#000000',
strokeThickness: 10,
weight: 300,
align: 'left'
});
endText.x = 20;
endText.y = 1250;
self.addChild(endText);
self.on('down', function () {
LK.setScore(finalScore);
LK.showGameOver();
});
});
// Girl class
var Girl = Container.expand(function () {
var self = Container.call(this);
var girlGraphics = self.attachAsset('girl', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Girl specific update logic
};
});
var GreenCheckmark = Container.expand(function () {
var self = Container.call(this);
var checkmarkGraphics = self.attachAsset('greenCheckmark', {
anchorX: 0.5,
anchorY: 0.5
});
});
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.scale.x = self.scale.y = 0.8 + Math.random() * 0.7;
self.lifetime = 0;
self.delay = 0;
self.update = function () {
if (self.delay-- <= 0) {
self.x += self.vx;
self.y += self.vy;
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
}
}
};
});
// Ice class
var Ice = Container.expand(function () {
var self = Container.call(this);
var iceGraphics = self.attachAsset('ice', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Ice specific update logic
};
});
// IngredientButton class
var IngredientButton = Container.expand(function (i, k) {
var self = Container.call(this);
self.done = false;
self.right = false;
var ingredientButtonGraphics = self.attachAsset('ingredientButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.75,
scaleY: 0.75
//x: i * 400 //(i - item.ingredients.length / 2) * 400
});
var ingredientSprite = LK.getAsset('' + k, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.75,
scaleY: 0.75
//x: ingredientButton.x //i * 400 //(i - item.ingredients.length / 2) * 400
});
self.addChild(ingredientSprite);
self.moveTo = function (targetX, targetY, duration) {
var startX = self.x;
var startY = self.y;
var bezierPoints = generateBezierPoints({
x: startX,
y: startY
}, {
x: targetX,
y: targetY
}, {
x: 400,
//(startX + targetX) / 2,
y: 200 //startY - 200
}, {
x: 1600,
//(startX + targetX) / 2,
y: 200 //targetY + 200
}, duration * 60);
var currentTick = 0;
self.update = function () {
if (currentTick < bezierPoints.length) {
self.x = bezierPoints[currentTick].x;
self.y = bezierPoints[currentTick].y;
self.scale.x -= 0.003;
self.scale.y -= 0.003;
currentTick++;
} else {
self.x = targetX;
self.y = targetY;
// Stop updating once the target is reached
self.update = null;
self.done = true;
//LK.setScore(LK.getScore() + 1);
//scoreTxt.setText('$ ' + LK.getScore());
emptyGlass.updateText(Math.floor(100 * currentOrderedItemCompletion / currentOrderedItemSize));
// Check if drink is ready. (Todo: Maybe wait a second while it mixes before removing it all.)
var countDone = 0;
for (var i = 0; i < ingredientButtons.length; i++) {
if (ingredientButtons[i].done) {
countDone++;
}
}
emptyGlass.updateText(Math.floor(100 * countDone / currentOrderedItemSize));
//if (currentOrderedItemCompletion == currentOrderedItemSize && allDone) {
if (countDone == currentOrderedItemSize) {
// Remove emptyGlass and ingredients and replace with the drink.
emptyGlass.destroy();
instructionLabel.visible = false;
createStarExplosion(emptyGlass.x - 100, emptyGlass.y);
for (var i = 0; i < ingredientButtons.length; i++) {
ingredientButtons[i].destroy();
}
ingredientButtons = [];
// Also remove the speechBubble here.
speechBubble.destroy();
// But we can maybe reuse the itemSprite instead of destroying.
itemSprite.x = 1500;
itemSprite.y = 1400;
itemSprite.scale.x = 2.2;
itemSprite.scale.y = 2.2;
// Move itemSprite to the rightmost customer and scale it down
var rightmostCustomer = customers[0]; //customers[customers.length - 1];
moveDrinkToCustomer(itemSprite, rightmostCustomer.x, rightmostCustomer.y, 1);
//LK.setScore(LK.getScore() + currentOrder.price);
coins += currentOrder.price;
scoreTxt.setText('$ ' + coins);
totalEarned += currentOrder.price;
// TODO: Here a few coins should flip from customer to girl and money label be upgraded
//customers[0].addChild(itemSprite);
//waitCounter = 100;
//itemSprite.destroy();
}
}
};
};
// Event handler called when a press happens on element.
self.down = function (x, y, obj) {
ingredientButtonGraphics.alpha = 0;
if (self.right) {
currentOrderedItemCompletion++;
// Try to move the completion status of current order to give a Y position of theingredient in the glass
var destY = emptyGlass.y + emptyGlass.height / 2 - currentOrderedItemCompletion * 150;
// Also try to give the X position a bit of variation / alternation.
var destX = currentOrderedItemCompletion % 2 == 0 ? 25 : -25;
self.moveTo(emptyGlass.x + destX, destY, 1);
self.down = null;
} else {
// Show a minus $2 sign and move button down.
var minusSign = new minusPopup();
minusSign.x = self.x;
minusSign.y = self.y - 200;
coins -= 2;
if (coins < 0) {
coins = 0;
}
scoreTxt.setText('$ ' + coins);
game.addChild(minusSign);
self.moveDown(1024, 5000, 1);
self.down = null;
}
};
self.moveDown = function (targetX, targetY, duration) {
var startX = self.x;
var startY = self.y;
var bezierPoints = generateBezierPoints({
x: startX,
y: startY
}, {
x: targetX,
y: targetY
}, {
x: 1024,
//(startX + targetX) / 2,
y: 2000 //startY - 200
}, {
x: 1024,
//(startX + targetX) / 2,
y: 2000 //targetY + 200
}, duration * 60);
var currentTick = 0;
self.update = function () {
if (currentTick < bezierPoints.length) {
self.x = bezierPoints[currentTick].x;
self.y = bezierPoints[currentTick].y;
self.scale.x -= 0.003;
self.scale.y -= 0.003;
currentTick++;
} else {
self.x = targetX;
self.y = targetY;
// Stop updating once the target is reached
self.update = null;
//self.done = true;
}
};
};
});
//<Assets used in the game will automatically appear here>
// Lemon class
var Lemon = Container.expand(function () {
var self = Container.call(this);
var lemonGraphics = self.attachAsset('lemon', {
anchorX: 0.5,
anchorY: 0.5
});
});
// LemonadeStand class
var LemonadeStand = Container.expand(function () {
var self = Container.call(this);
var standGraphics = self.attachAsset('stand', {
anchorX: 0.5,
anchorY: 0.5
});
});
var ShopItem = Container.expand(function (id, price) {
var self = Container.call(this);
// Initialize shop item properties
self.id = id;
self.price = price;
self.purchased = false;
self.maxed = false;
self.recipe = '';
var itemBg = self.attachAsset('shopItemBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach asset based on the item id
var itemGraphic = self.attachAsset(self.id, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
var nameTxt = new Text2('', {
size: 42,
fill: "#ffffff",
stroke: '#2B1700',
strokeThickness: 10
});
//orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie
if (self.id == 'orangeJuice') {
nameTxt.setText('Orange Juice');
self.recipe = '- Orange\n- Ice Water';
} else if (self.id == 'strawberryDrink') {
nameTxt.setText('Strawberry Daiquiry');
self.recipe = '- Strawberry\n- Sugar\n- Ice Water';
} else if (self.id == 'watermelonDrink') {
nameTxt.setText('Melon Slush');
self.recipe = '- Watermelon\n- Strawberry\n- Ice Water';
} else if (self.id == 'bananaMilkshake') {
nameTxt.setText('Banana Milkshake');
self.recipe = '- Banana\n- Milk\n- Ice';
} else if (self.id == 'berriesDrink') {
nameTxt.setText('Berries Lemonade');
self.recipe = '- Strawberry\n- Blueberry\n- Sugar\n- Ice Water';
} else if (self.id == 'pinaDrink') {
nameTxt.setText('PiƱa Colada');
self.recipe = '- Coconut\n- Pineapple\n- Milk';
} else if (self.id == 'mangoLassie') {
nameTxt.setText('Mango Lassie');
self.recipe = '- Mango\n- Sugar\n- Milk';
} else if (self.id == 'yacht') {
nameTxt.setText('Dream Boat');
self.recipe = 'Finally!\nMy dream boat\nis mine!';
}
//nameTxt.x = -self.width / 2;
nameTxt.x -= nameTxt.width / 2;
nameTxt.y = -self.height / 2 - nameTxt.height;
self.addChild(nameTxt);
var costTxt = new Text2('', {
size: 42,
fill: "#ffffff",
stroke: '#2B1700',
strokeThickness: 10
});
costTxt.setText('' + self.price);
costTxt.x = -30;
costTxt.y = self.height / 2 - 65;
self.addChild(costTxt);
var upgradeButton = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
upgradeButton.scale.x = upgradeButton.scale.y = 0.9;
upgradeButton.y = 275;
upgradeButton.alpha = 1;
var bTxt = new Text2('', {
size: 42,
fill: "#ffffff",
stroke: '#2B1700',
strokeThickness: 10
});
bTxt.setText('Buy');
bTxt.x = -36;
bTxt.y = self.height / 2 - 40;
self.addChild(bTxt);
// Method to reset the item's purchase state (optional, depending on game design)
self.reset = function () {
self.purchased = false;
// Optionally, update the item's appearance to indicate it's not purchased
};
self.bought = function () {
//console.log('updateCost called');
//costTxt.destroy();
costTxt.y += 26;
//costTxt.fill = '#cccccc';
costTxt.setText(self.recipe);
costTxt.x = -costTxt.width / 2;
upgradeButton.destroy();
bTxt.destroy();
self.maxed = true;
scoreTxt.setText('$ ' + coins);
//todo, maybe add green checkmark to indicate already owned.
var green = new GreenCheckmark();
green.x = 110; //self.width / 2 - green.width / 2;
green.y = 110; //self.height / 2 - green.height / 2;
self.addChild(green);
dailyCustomerAmount++;
};
});
var ShopWindow = Container.expand(function () {
var self = Container.call(this);
// Initialize shop window properties and background graphic
self.items = []; // Array to hold shop items
self.x = 1024; // Center horizontally
self.y = 1360; //1566; // Center vertically
self.visible = false; // Initially hidden
self.scale.x = 1.0;
self.scale.y = 1.0;
// Add background graphic to shop window
var backgroundGraphic = self.attachAsset('shopBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 30,
y: 0
});
// [orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie]
// 7,10,12,15,20,25,30
self.addChild(backgroundGraphic);
var item1 = new ShopItem('orangeJuice', 30);
item1.x = -540;
item1.y = -350;
var item2 = new ShopItem('strawberryDrink', 50);
item2.x = -180;
item2.y = -350;
var item3 = new ShopItem('watermelonDrink', 75);
item3.x = 180;
item3.y = -350;
var item4 = new ShopItem('bananaMilkshake', 100);
item4.x = 540;
item4.y = -350;
var item5 = new ShopItem('berriesDrink', 150);
item5.x = -540;
item5.y = 300;
var item6 = new ShopItem('pinaDrink', 200);
item6.x = -180;
item6.y = 300;
var item7 = new ShopItem('mangoLassie', 250);
item7.x = 180;
item7.y = 300;
var item8 = new ShopItem('yacht', 500);
item8.x = 540;
item8.y = 300;
self.addChild(item1);
self.addChild(item2);
self.addChild(item3);
self.addChild(item4);
self.addChild(item5);
self.addChild(item6);
self.addChild(item7);
self.addChild(item8);
// [orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie]
item1.down = function (x, y, obj) {
if (coins >= item1.price && !item1.maxed) {
coins -= item1.price;
item1.bought();
availableItems.push(orangeJuice);
}
};
item2.down = function (x, y, obj) {
if (coins >= item2.price && !item2.maxed) {
coins -= item2.price;
item2.bought();
availableItems.push(strawberryDrink);
}
};
item3.down = function (x, y, obj) {
if (coins >= item3.price && !item3.maxed) {
coins -= item3.price;
item3.bought();
availableItems.push(watermelonDrink);
}
};
item4.down = function (x, y, obj) {
if (coins >= item4.price && !item4.maxed) {
coins -= item4.price;
item4.bought();
availableItems.push(bananaMilkshake);
}
};
item5.down = function (x, y, obj) {
if (coins >= item5.price && !item5.maxed) {
coins -= item5.price;
item5.bought();
availableItems.push(berriesDrink);
}
};
item6.down = function (x, y, obj) {
if (coins >= item6.price && !item6.maxed) {
coins -= item6.price;
item6.bought();
availableItems.push(pinaDrink);
}
};
item7.down = function (x, y, obj) {
if (coins >= item7.price && !item7.maxed) {
coins -= item7.price;
item7.bought();
availableItems.push(mangoLassie);
}
};
item8.down = function (x, y, obj) {
if (coins >= item8.price && !item8.maxed) {
coins -= item8.price;
item8.bought();
//availableItems.push(watermelonDrink);
// TODO: Finally bought the yacht.
var gob = new GameOverBackground();
game.addChild(gob);
scoreTxt.destroy();
}
};
var shopTxt = new Text2('Time to shop for new recipes', {
size: 80,
fill: "#ffffff",
stroke: "#2B1700",
strokeThickness: 10,
align: 'center',
weight: 800
});
shopTxt.anchor.set(0.5, 0.5); // Sets anchor to the center of the bottom edge of the text.
shopTxt.y = -self.height / 2 + 720;
self.addChild(shopTxt);
var closeButton = new CloseButton(self);
self.addChild(closeButton);
self.show = function () {
game.addChild(self);
self.visible = true;
};
self.hide = function () {
self.visible = false;
};
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.lifetime = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
}
};
});
// Sugar class
var Sugar = Container.expand(function () {
var self = Container.call(this);
var sugarGraphics = self.attachAsset('sugar', {
anchorX: 0.5,
anchorY: 0.5
});
});
var earnedPopup = Container.expand(function (money) {
var self = Container.call(this);
var mText = new Text2('$' + money, {
size: 90,
fill: "#eeee33",
stroke: '#000000',
strokeThickness: 10,
weight: 800
});
self.addChild(mText);
self.update = function () {
self.y -= 8;
if (self.y < 1000) {
self.destroy();
}
};
});
var minusPopup = Container.expand(function () {
var self = Container.call(this);
var mText = new Text2('-2$', {
size: 90,
fill: "#ff3333",
stroke: '#000000',
strokeThickness: 10,
weight: 800
});
self.addChild(mText);
self.update = function () {
self.y -= 8;
if (self.y < 1400) {
self.destroy();
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Init game with sky blue background
});
/****
* Game Code
****/
var drinksServed = 0;
var daysSpent = 0;
var instructionTxt;
function updateCoinsText() {
coinsTxt.setText('Star Coins: ' + coins);
}
function showMoneyEarned(x, y, money) {
y -= 150;
var mText = new earnedPopup(money);
mText.x = x;
mText.y = y;
game.addChild(mText);
}
;
var coins = 0;
function createHeartExplosion(x, y) {
//y -= 50;
y -= 25 + Math.random() * 75;
var heartCount = 1;
var heartSpeed = 6;
var heartLifetime = 60; // frames
for (var i = 0; i < heartCount; i++) {
var heart = new Heart();
heart.x = x;
heart.y = y; // - 30 * i;
heart.delay = i * 6;
var rand = Math.random() * Math.PI / 8;
heart.rotation += Math.random() < 0.5 ? rand : -rand;
heart.vx = (Math.random() - 0.5) * heartSpeed * 0.2;
heart.vy = -heartSpeed; //-Math.random() * heartSpeed;
heart.lifetime = heartLifetime;
game.addChild(heart);
}
}
/**
* Creates a star explosion effect at the specified coordinates.
*
* @param {Number} x - The x-coordinate of the explosion center.
* @param {Number} y - The y-coordinate of the explosion center.
*/
function createStarExplosion(x, y) {
var starCount = 20;
var starSpeed = 30;
var starLifetime = 120; // frames
for (var i = 0; i < starCount; i++) {
var star = new Star();
star.x = x;
star.y = y;
var angle = i / starCount * 2 * Math.PI;
star.vx = starSpeed * Math.cos(angle);
star.vy = starSpeed * Math.sin(angle);
star.lifetime = starLifetime;
game.addChild(star);
}
}
function globalMoveTo() {
self.x--;
}
;
var lemonadeStand;
var scoreTxt;
var score = 0;
var background = game.addChild(LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1,
x: 1024,
y: 2732 / 2
}));
function easeOutBounce(x) {
var n1 = 7.5625;
var d1 = 2.75;
if (x < 1 / d1) {
return n1 * x * x;
} else if (x < 2 / d1) {
return n1 * (x -= 1.5 / d1) * x + 0.75;
} else if (x < 2.5 / d1) {
return n1 * (x -= 2.25 / d1) * x + 0.9375;
} else {
return n1 * (x -= 2.625 / d1) * x + 0.984375;
}
}
;
function easeOutElastic(x) {
//var c4 = 2 * Math.PI / 3;
var c4 = 2 * Math.PI / .3;
//return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
//return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
return x === 0 ? 0 : x === 1 ? 1 : 0.25 * Math.pow(2, -5 * x) * Math.cos((x * 10 - 0.75) * c4) + 1;
}
// Initialize game elements
function initGameElements() {
// Create and position girl
var girl = new Girl();
girl.x = 2048 / 2;
girl.y = 2732 - 1150;
game.addChild(girl);
// Create and position lemonade stand
lemonadeStand = new LemonadeStand();
lemonadeStand.x = 2048 / 2;
lemonadeStand.y = 2732 - 1100;
game.addChild(lemonadeStand);
// Create and position score text
scoreTxt = new Text2('$ 0', {
size: 100,
fill: "#33ee33",
stroke: '#000000',
strokeThickness: 10,
weight: 300
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
}
// Update score
function updateScore() {
scoreTxt.setText('$ ' + score);
}
// Initialize game elements
initGameElements();
var customerTypes = [CustomerBase]; //[Customer1, Customer2, Customer3, Customer4, Customer5, Customer6, Customer7, Customer8];
var customers = [];
var backgroundOverlay = game.addChild(LK.getAsset('backgroundOverlay', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1,
x: 1024,
y: 2732 / 2
}));
var dailyCustomerAmount = 7;
addCustomers(dailyCustomerAmount);
function addCustomers(amount) {
daysSpent++;
for (var i = 0; i < amount; i++) {
//var t = new customerTypes[Math.floor(Math.random() * customerTypes.length)]();
var t = new CustomerBase();
t.y = 1800;
t.x = 500 - 250 * i - 50;
t.anchorY = 2;
game.addChild(t);
customers.push(t);
queueUpdateCounter = 0;
// re-add the foreground overlay
game.addChild(backgroundOverlay);
}
}
;
var lemonade = {
sprite: 'lemonade',
offsetX: 25,
offsetY: -300,
ingredients: ['lemon', 'sugar', 'water'],
price: 5
};
var orangeJuice = {
sprite: 'orangeJuice',
offsetX: 60,
offsetY: -300,
ingredients: ['orange', 'water'],
price: 7
};
var strawberryDrink = {
sprite: 'strawberryDrink',
offsetX: 25,
offsetY: -300,
ingredients: ['strawberry', 'sugar', 'water'],
price: 10
};
var watermelonDrink = {
sprite: 'watermelonDrink',
offsetX: 45,
offsetY: -320,
ingredients: ['watermelon', 'strawberry', 'water'],
price: 12
};
var bananaMilkshake = {
sprite: 'bananaMilkshake',
offsetX: 45,
offsetY: -300,
ingredients: ['banana', 'milk', 'water'],
price: 15
};
var berriesDrink = {
sprite: 'berriesDrink',
offsetX: 45,
offsetY: -300,
ingredients: ['strawberry', 'blueberry', 'sugar', 'water'],
price: 20
};
var pinaDrink = {
sprite: 'pinaDrink',
offsetX: 25,
offsetY: -300,
ingredients: ['coconut', 'pineapple', 'milk'],
price: 25
};
var mangoLassie = {
sprite: 'mangoLassie',
offsetX: 45,
offsetY: -300,
ingredients: ['mango', 'sugar', 'milk'],
price: 30
};
var allIngredients = ['orange', 'coconut', 'pineapple', 'milk', 'blueberry', 'strawberry', 'watermelon', 'banana', 'sugar', 'water'];
var lockedItems = [orangeJuice, strawberryDrink, watermelonDrink, bananaMilkshake, berriesDrink, pinaDrink, mangoLassie];
var availableItems = [lemonade]; //[lemonade];
var currentOrder;
var currentOrderedItemSize = 0;
var currentOrderedItemCompletion = 0;
var ingredientButtons = [];
var speechBubble;
var itemSprite;
function orderSomething(obj) {
var item = availableItems[Math.floor(Math.random() * availableItems.length)];
currentOrder = item; // just to have a reference in the gobal scope.
speechBubble = LK.getAsset('speechBubble', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.5,
scaleY: 0.5,
x: obj.x - 250,
y: obj.y - obj.height / 2 - 50,
rotation: 0.12,
alpha: 0.9
});
game.addChild(speechBubble);
// Add the sprite of the ordered item inside the speech bubble
itemSprite = LK.getAsset(item.sprite, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1,
x: speechBubble.x + item.offsetX,
y: speechBubble.y + item.offsetY
});
game.addChild(itemSprite);
// Display the ingredients of the ordered item at the bottom center of the screen
if (false) {
currentOrderedItemCompletion = 0;
currentOrderedItemSize = item.ingredients.length;
for (var i = 0; i < currentOrderedItemSize; i++) {
var ingredientButton = new IngredientButton(i, item.ingredients[i]);
ingredientButton.x = i * 400;
ingredientButton.y = 2732 - 500;
game.addChild(ingredientButton);
if (currentOrderedItemSize == 2) {
ingredientButton.x += 800;
} else if (currentOrderedItemSize == 3) {
ingredientButton.x += 600;
} else if (currentOrderedItemSize == 4) {
ingredientButton.x += 400; // += 200;
}
ingredientButtons.push(ingredientButton);
}
} else {
//TODO: maybe make a random or knowledge check to determine if player can make this recipe.
// Add the normal options.
var buttons = item.ingredients;
// Add 1 (or more?) wrong ingredient among the options.
var random = buttons[0];
while (buttons.includes(random)) {
random = allIngredients[Math.floor(Math.random() * allIngredients.length)];
}
var wrongIngredientButton = new IngredientButton(0, random);
wrongIngredientButton.right = false;
wrongIngredientButton.y = 2732 - 500;
game.addChild(wrongIngredientButton);
ingredientButtons.push(wrongIngredientButton);
// Add the right buttons.
// Let the buttons know if they're right or wrong for this recipe, so they can handle presses.
currentOrderedItemCompletion = 0;
currentOrderedItemSize = item.ingredients.length;
for (var i = 0; i < currentOrderedItemSize; i++) {
var ingredientButton = new IngredientButton(i, item.ingredients[i]);
ingredientButton.y = 2732 - 500;
ingredientButton.right = true;
game.addChild(ingredientButton);
ingredientButtons.push(ingredientButton);
}
//console.log('before ' + ingredientButtons[0].right);
// Shuffle buttons using fisher-yates.
fy(ingredientButtons, 0, 0, 0);
// Align the buttons.
for (var i = 0; i < ingredientButtons.length; i++) {
var ingredientButton = ingredientButtons[i];
ingredientButton.x = i * 400;
if (currentOrderedItemSize == 2) {
ingredientButton.x += 600;
} else if (currentOrderedItemSize == 3) {
ingredientButton.x += 400;
} else if (currentOrderedItemSize == 4) {
ingredientButton.x += 200; // += 200;
}
}
//console.log('after ' + ingredientButtons[0].right);
//console.table([ingredientButtons[0], ingredientButtons[1], ingredientButtons[2]], ["correct"]);
// Display a label 'Add the 2 (or 3 or 4) right ingredient.
instructionLabel = new Text2('Add the ' + currentOrderedItemSize + ' right ingredients.', {
size: 100,
fill: "#ffffff",
stroke: '#000000',
strokeThickness: 10,
weight: 300,
align: 'center'
});
instructionLabel.x = 1024 - instructionLabel.width / 2;
instructionLabel.y = 2500;
//instructionLabel.anchor.set(0.5, 0);
game.addChild(instructionLabel);
// How should wrong ingredient behave when pressed? Maybe move offscreen - with a -2$ sign shown in red?
}
// Add an empty glass
emptyGlass = new EmptyGlass();
game.addChild(emptyGlass);
emptyGlass.x = 1600;
emptyGlass.y = 1400;
}
var instructionLabel;
function fy(a, b, c, d) {
//array,placeholder,placeholder,placeholder
c = a.length;
while (c) {
b = Math.random() * c-- | 0, d = a[c], a[c] = a[b], a[b] = d;
}
}
/**
* Generates an array of points along a two-point Bezier curve.
*
* @param {Object} start - The starting point of the curve {x: Number, y: Number}.
* @param {Object} end - The ending point of the curve {x: Number, y: Number}.
* @param {Object} anchor1 - The first anchor point of the curve {x: Number, y: Number}.
* @param {Object} anchor2 - The second anchor point of the curve {x: Number, y: Number}.
* @param {Number} n - The number of points to generate along the curve.
* @returns {Array} - An array of points along the Bezier curve.
*/
function generateBezierPoints(start, end, anchor1, anchor2, n) {
var points = [];
for (var i = 0; i <= n; i++) {
var t = i / n;
var x = Math.pow(1 - t, 3) * start.x + 3 * Math.pow(1 - t, 2) * t * anchor1.x + 3 * (1 - t) * Math.pow(t, 2) * anchor2.x + Math.pow(t, 3) * end.x;
var y = Math.pow(1 - t, 3) * start.y + 3 * Math.pow(1 - t, 2) * t * anchor1.y + 3 * (1 - t) * Math.pow(t, 2) * anchor2.y + Math.pow(t, 3) * end.y;
points.push({
x: x,
y: y
});
}
return points;
}
;
var totalEarned = 0;
var emptyGlass;
//var harvestedCounter = 0;
var queueSpeed = 3;
var queueUpdateCounter = 0;
var queueUpdateMax = 240 / queueSpeed;
var orderPlaced = false;
var waitCounter = 0;
function updateCustomers() {
if (waitCounter-- > 0) {} else if (!shop.visible) {
if (queueUpdateCounter < queueUpdateMax) {
queueUpdateCounter++;
for (var i = 0; i < customers.length; i++) {
customers[i].x += queueSpeed;
customers[i].y += Math.cos(LK.ticks / 2) * 15 * (Math.random() * 0.3 + 0.7);
customers[i].rotation += 0.05 - Math.random() * 0.1;
//customers[i].rotation += LK.ticks % 6 < 3 ? 0.05 : -0.05;
} /*
if (customers[i].happy && LK.ticks % 10 == 0) {
createHeartExplosion(customers[i].x, customers[i].y - 100);
}*/
} else if (queueUpdateCounter >= queueUpdateMax && !orderPlaced) {
for (var i = 0; i < customers.length; i++) {
customers[i].rotation = 0;
customers[i].y = 1800;
}
if (customers.length > 0) {
orderSomething(customers[0]);
orderPlaced = true;
} else if (!shop.visible) {
shop.show();
}
}
}
}
;
var shop = new ShopWindow();
game.addChild(shop);
game.update = function () {
updateCustomers();
//itemSprite.update();
};
function moveDrinkToCustomer(sprite, targetX, targetY, duration) {
targetX += 50;
targetY += 50;
var startX = sprite.x;
var startY = sprite.y;
var startScaleX = sprite.scale.x;
var startScaleY = sprite.scale.y;
var endScale = 0.3;
var bezierPoints = generateBezierPoints({
x: startX,
y: startY
}, {
x: targetX,
y: targetY
}, {
x: (startX + targetX) / 2,
y: startY - 200
}, {
x: (startX + targetX) / 2,
y: targetY + 200
}, duration * 60);
var currentTick = 0;
sprite.update = function () {
if (currentTick < bezierPoints.length) {
sprite.x = bezierPoints[currentTick].x;
sprite.y = bezierPoints[currentTick].y;
sprite.scale.x = startScaleX - (startScaleX - endScale) * (currentTick / bezierPoints.length);
sprite.scale.y = startScaleY - (startScaleY - endScale) * (currentTick / bezierPoints.length);
currentTick++;
} else {
sprite.x = 3000;
sprite.y = targetY;
sprite.scale.x = endScale;
sprite.scale.y = endScale;
sprite.update = null;
//createHeartExplosion(targetX, targetY - 100);
showMoneyEarned(targetX, targetY - 100, currentOrder.price);
customers[0].happy = true;
drinksServed++;
var customerDrink = LK.getAsset(currentOrder.sprite, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
x: 50,
y: 50
});
customers[0].addChild(customerDrink);
customers[0].done = true;
customers.splice(0, 1);
// This causes the updateCustomers in game.update() to advance the queue.
queueUpdateCounter = 0;
orderPlaced = false;
}
};
}
A beautiful scenery looking out to sea from an empty beach side promenade on a bright summer day. Happy game illustration style for a casual family friendly game.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
remove the glass and the crate of lemons from the table.
A simple, elegant white speech bubble.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A lemon with a few slices cut off.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A bag of white sugar, open and with a pile of the sugar in front of it.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A pitcher full of nice fresh water and ice cubes.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A round white button for an interface element.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
An empty drinking glass.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A yellow star. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A red heart. simple.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A nice glass of watermelon and strawberry slushice. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A nice glass of banana milkshake. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A nice glass of pina colada. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A nice glass of mango lassie. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
An orange. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A couple of blueberries. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A couple of bananas. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A bottle of milk. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A watermelon and some pieces of watermelon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A mango and a few slices of mango. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A pineapple with a few slices of pineapple in front. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A fullscreen background gui element for an in-game shop. It should be mostly blanks space, but along the edges there could be some structure or decorative vines and items, mostly related to fruits, berries, cocktails in a summer theme.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A modern dream of a sailing boat. game illustration.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A bold green checkmark.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
An idyllic llustration of a beach cove where a blnd girl in a strawhat i en joying an enormous strawberry drink on her sailing boat as the sun sets. Clean game art illustration style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
An idyllic llustration of a beach cove where a blond girl in a straw hat is enjoying an large strawberry drink on the deck of her sailing boat as the sun sets. Clean game illustration style.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.