User prompt
Pointer assentini 30 birim aşağıya indir
User prompt
Memeleri açıklayan yazıları kaldır
User prompt
Spin again yazısını y doğrusunda 100 birim aşağıya indir
User prompt
20 tane meme card assenti oluştur. Rastgele bu meme kartlardan biri seçilsin döndüğünde
User prompt
Please fix the bug: 'Graphics is not a constructor' in or related to this line: 'var section = new Graphics();' Line Number: 237
Code edit (1 edits merged)
Please save this source code
User prompt
Spin to Meme
Initial prompt
"Spin to Meme" is a web-based casual game where players spin a colorful wheel to randomly determine which internet meme they are most aligned with. Each spin generates a unique meme result, accompanied by a fun personality description.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var City = Container.expand(function () { var self = Container.call(this); // Create city graphics using shape self.cityGraphic = self.attachAsset('hero', { // Assign to self.cityGraphic anchorX: 0.5, anchorY: 0.5 }); // Default city properties self.name = ""; self.captured = false; // Flag for hero capture self.enemyCaptured = false; // Flag for enemy capture self.soldiers = 0; // Track soldier count // Change city color self.cityGraphic.tint = 0x888888; // Default gray color for uncaptured cities // City name text var cityNameText = new Text2("", { size: 40, fill: 0xFFFFFF }); cityNameText.anchor.set(0.5, 0.5); cityNameText.y = 80; self.addChild(cityNameText); // Helper function to normalize dot speed function normalizeSpeed(dot) { var speed = Math.sqrt(dot.vx * dot.vx + dot.vy * dot.vy); if (speed > 1.5) { dot.vx = dot.vx / speed * 1.5; dot.vy = dot.vy / speed * 1.5; } else if (speed < 0.5) { dot.vx = (dot.vx / speed || Math.random() - 0.5) * 0.5; dot.vy = (dot.vy / speed || Math.random() - 0.5) * 0.5; } } // Container for soldier dots self.soldierDotsContainer = new Container(); self.addChild(self.soldierDotsContainer); // Update city with name self.setName = function (name) { self.name = name; cityNameText.setText(name); }; // Set soldier count self.setSoldierCount = function (count) { count = Math.min(count, 50); // Cap soldier count at 50 self.soldiers = count; // Clear existing soldier dots self.soldierDotsContainer.removeChildren(); // Determine dot color based on capture status var dotColor = 0x888888; // Default neutral color (gray) var dotAsset = 'bullet'; // Default asset if (self.captured) { dotColor = 0x1fb6f2; // Hero color (blue) dotAsset = 'bullet'; } else if (self.enemyCaptured) { dotColor = 0xff0000; // Enemy color (red) dotAsset = 'enemyDot'; } // Create new soldier dots based on count var dotSize = 15; // Smaller dots inside the city var cityRadius = self.cityGraphic.width * 0.4; // Place dots within 80% of the radius for (var i = 0; i < self.soldiers; i++) { var dot = LK.getAsset(dotAsset, { // Use appropriate asset width: dotSize, height: dotSize, anchorX: 0.5, anchorY: 0.5 }); dot.tint = dotColor; // Set color based on control // Random position within the city radius var angle = Math.random() * Math.PI * 2; var radius = Math.random() * cityRadius; dot.x = Math.cos(angle) * radius; dot.y = Math.sin(angle) * radius; // Add random movement properties dot.vx = (Math.random() - 0.5) * 2; // Random velocity x (-1 to 1) dot.vy = (Math.random() - 0.5) * 2; // Random velocity y (-1 to 1) dot.maxRadius = cityRadius; // Store max radius for boundary check self.soldierDotsContainer.addChild(dot); } }; // Capture city function self.capture = function () { if (!self.captured) { self.captured = true; self.cityGraphic.tint = 0x00FF00; // Change to green when captured // Reset soldier count to zero when captured by the hero self.setSoldierCount(0); // Reset to zero // Animation effect when captured - simplified with a single tween tween(self.cityGraphic, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(self.cityGraphic, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } else { // Reinforcement logic is now handled directly when soldiers arrive } //{H} // Keep original line ID nearby if applicable }; // Make city interactive self.down = function () { // When city is clicked, don't capture it automatically // We'll only capture cities when soldiers reach them }; // Add update method to move dots self.update = function () { var cityRadiusSq = self.cityGraphic.width * 0.4 * (self.cityGraphic.width * 0.4); // Squared radius for cheaper checks for (var i = 0; i < self.soldierDotsContainer.children.length; i++) { var dot = self.soldierDotsContainer.children[i]; // Move dot dot.x += dot.vx; dot.y += dot.vy; // Check boundaries and reverse velocity if needed var distSq = dot.x * dot.x + dot.y * dot.y; if (distSq > cityRadiusSq) { // Simple reflection: reverse velocity component perpendicular to boundary // Or simpler: just reverse velocity if out of bounds dot.x -= dot.vx; // Move back dot.y -= dot.vy; dot.vx *= -1; dot.vy *= -1; // Add slight randomness to avoid getting stuck in bounce loops dot.vx += (Math.random() - 0.5) * 0.2; dot.vy += (Math.random() - 0.5) * 0.2; // Use normalizeSpeed helper function normalizeSpeed(dot); } else { // Occasionally change direction slightly even when inside if (Math.random() < 0.01) { // 1% chance each frame dot.vx += (Math.random() - 0.5) * 0.5; dot.vy += (Math.random() - 0.5) * 0.5; // Use normalizeSpeed helper function normalizeSpeed(dot); } } } }; return self; }); var Hero = Container.expand(function () { var self = Container.call(this); // Default hero asset (will be replaced with selected meme) var heroGraphic = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); // Add soldier count text to the right side of hero var soldierCountText = new Text2("0", { size: 60, fill: 0xFFFFFF }); soldierCountText.anchor.set(0, 0.5); soldierCountText.x = 300; // Position to the right of the hero soldierCountText.y = 0; // Center vertically with the hero self.addChild(soldierCountText); // Container for soldier dots var soldierDotsContainer = new Container(); self.addChild(soldierDotsContainer); // Track soldier count self.soldiers = 0; // Set soldier count function self.setSoldierCount = function (count) { self.soldiers = count; soldierCountText.setText(count.toString()); // Clear existing soldier dots soldierDotsContainer.removeChildren(); // Create new soldier dots based on count var dotSize = 20; var dotSpacing = 10; var startX = 450; // Position dots to the right of the soldier count text var dotsPerRow = 40; // Maximum dots per row var rowSpacing = 30; // Spacing between rows for (var i = 0; i < self.soldiers; i++) { var dot = LK.getAsset('bullet', { // Using 'bullet' asset as a small dot width: dotSize, height: dotSize, anchorX: 0.5, anchorY: 0.5 }); dot.tint = 0x1fb6f2; // Match hero color var row = Math.floor(i / dotsPerRow); var col = i % dotsPerRow; dot.x = startX + (dotSize + dotSpacing) * col; dot.y = rowSpacing * row; soldierDotsContainer.addChild(dot); } }; // Initialize with 40 soldiers self.setSoldierCount(40); // Method to move soldier dots from the hero base to a target position self.moveSoldiersTo = function (targetX, targetY) { // Ensure we have soldiers to move if (self.soldiers <= 0) return; // Let's send all soldiers for now var soldiersToSend = self.soldiers; var dotAssetId = 'bullet'; // Asset for hero dots var dotTint = 0x1fb6f2; // Hero color var dotSize = 20; // Check if the hero is actually on the stage to get global position if (!self.parent) return; // Calculate start position (simplified) var startPos = { x: self.x, y: self.y }; // Get positions of dots from the soldierDotsContainer var dotPositions = []; if (soldierDotsContainer && soldierDotsContainer.children) { for (var i = 0; i < soldierDotsContainer.children.length; i++) { var dot = soldierDotsContainer.children[i]; // Use simple offset from hero position dotPositions.push({ x: self.x + dot.x, y: self.y + dot.y }); } } // Clear the hero's local soldier dots display and count self.setSoldierCount(0); // Animate each soldier dot individually for (var i = 0; i < soldiersToSend; i++) { // Use the dot's actual position if available, otherwise use hero center var startX = i < dotPositions.length ? dotPositions[i].x : startPos.x; var startY = i < dotPositions.length ? dotPositions[i].y : startPos.y; // Calculate duration based on distance var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); var duration = Math.max(200, distance * 2); // Minimum 200ms, 2ms per pixel // Add a random delay so they don't all move at once var delay = Math.random() * 300; // Create and animate dot with sequential tweens (function (startX, startY) { LK.setTimeout(function () { // Create the temporary dot var tempDot = LK.getAsset(dotAssetId, { width: dotSize, height: dotSize, anchorX: 0.5, anchorY: 0.5 }); tempDot.tint = dotTint; tempDot.x = startX; tempDot.y = startY; game.addChild(tempDot); // First tween: move to target tween(tempDot, { x: targetX, y: targetY }, { duration: duration, easing: tween.linear, onFinish: function onFinish() { var cityHit = false; var cityInteracted = false; // Check for city interaction if (game.cities) { for (var j = 0; j < game.cities.length; j++) { var city = game.cities[j]; // Distance check to city var hitDx = city.x - targetX; var hitDy = city.y - targetY; if (hitDx * hitDx + hitDy * hitDy < 50 * 50) { cityHit = true; // Process city interaction if (city.enemyCaptured) { // Against enemy city if (city.soldiers > 1) { city.setSoldierCount(city.soldiers - 1); } else { city.enemyCaptured = false; city.capture(); city.setSoldierCount(Math.max(0, 1 - city.soldiers)); cityInteracted = true; } } else if (city.captured) { // Reinforce friendly city city.setSoldierCount(city.soldiers + 1); cityInteracted = true; } else { // Against neutral city if (city.soldiers > 1) { city.setSoldierCount(city.soldiers - 1); } else { city.capture(); city.setSoldierCount(Math.max(0, 1 - city.soldiers)); cityInteracted = true; } } break; // Found a city, stop checking } } } // Return animation if needed if (cityInteracted && hero && hero.parent) { // Second tween: return to hero tween(tempDot, { x: hero.x, y: hero.y }, { duration: Math.max(200, distance * 2), easing: tween.linear, onFinish: function onFinish() { // Remove dot and increment hero count if (tempDot.parent) { tempDot.parent.removeChild(tempDot); } if (hero && hero.setSoldierCount) { hero.setSoldierCount(hero.soldiers + 1); } } }); } else { // Remove dot if no return needed if (tempDot.parent) { tempDot.parent.removeChild(tempDot); } } } }); }, delay); })(startX, startY); } }; // Method to update hero with selected meme self.updateWithMeme = function (memeIndex) { // Remove current graphic self.removeChild(heroGraphic); // Add new meme image based on index var memeAssetName = 'meme' + (memeIndex % 41 + 1); heroGraphic = LK.getAsset(memeAssetName, { anchorX: 0.5, anchorY: 0.5 }); // Scale to appropriate size heroGraphic.scale.set(0.75); self.addChild(heroGraphic); }; return self; }); var MemeResultCard = Container.expand(function () { var self = Container.call(this); // Initially hidden self.visible = false; var card = self.attachAsset('memeCard', { anchorX: 0.5, anchorY: 0.5 }); // Meme image placeholder var memeImage = null; // Meme title var titleText = new Text2("Your Spirit Meme", { size: 80, fill: 0x333333 }); titleText.anchor.set(0.5, 0); titleText.y = -500; self.addChild(titleText); // Meme name var memeNameText = new Text2("", { size: 60, fill: 0xFF5722 }); memeNameText.anchor.set(0.5, 0); memeNameText.y = -400; self.addChild(memeNameText); // Description var descriptionText = new Text2("", { size: 40, fill: 0x555555 }); descriptionText.anchor.set(0.5, 0); descriptionText.y = -280; descriptionText.wordWrap = true; descriptionText.wordWrapWidth = 1400; self.addChild(descriptionText); // Close button var closeButton = new Text2("START GAME", { size: 100, fill: 0x3498DB }); closeButton.anchor.set(0.5, 0.5); closeButton.y = 550; closeButton.interactive = true; self.addChild(closeButton); closeButton.down = function () { tween(closeButton, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); }; closeButton.up = function () { tween(closeButton, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { self.hide(); // Change background to 'arkaplan' image var newBackground = LK.getAsset('arkaplan', { anchorX: 0.5, anchorY: 0.5 }); newBackground.x = 2048 / 2; newBackground.y = 2732 / 2; game.addChild(newBackground); if (self.onClose) { self.onClose(); // Remove all game elements except hero game.removeChild(wheel); game.removeChild(pointer); game.removeChild(spinButton); game.removeChild(gameTitle); game.removeChild(subtitle); game.removeChild(background); game.removeChild(resultCard); // Create cities array in game scope if (!game.cities) { game.cities = []; // City names var cityNames = ["İnstagram", "Facebook", "Snapchat", "Pinterest", "X", "Youtube"]; // Create 6 cities and position them around the screen for (var i = 0; i < 6; i++) { var city = new City(); city.setName(cityNames[i]); // Set initial soldier count to exactly 30 for all cities city.setSoldierCount(30); // Position cities in a grid (2 rows, 3 columns) var row = Math.floor(i / 3); var col = i % 3; city.x = 400 + col * 700; // Move Istanbul, Ankara and Izmir 80 units lower on Y axis if (i < 3) { // First 3 cities are İnstagram, Facebook, Snapchat city.y = 880 + row * 900; // Added 80 to original y position } else { city.y = 960 + row * 900; // Added 160 to original y position for Bursa, Antalya, Konya } // Add city to game and store in array game.addChild(city); game.cities.push(city); } } // Position hero in top left corner of the screen hero.x = 290; // Updated to be 190 units to the right of previous position hero.y = 280; // Updated to be 180 units below the original position // Ensure hero is added to the scene if (!hero.parent) { game.addChild(hero); } // Add enemy to the bottom right corner of the screen // Make enemy a global variable enemy = LK.getAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); enemy.x = 2048 - 250; // Right side of screen with some margin enemy.y = 2732 - 250; // Bottom of screen with some margin game.addChild(enemy); // Add soldier count text to the left of the enemy var enemySoldierCountText = new Text2("0", { size: 60, fill: 0xFFFFFF }); // Container for soldier dots var enemySoldierDotsContainer = new Container(); // Position the container relative to the enemy enemySoldierDotsContainer.x = -enemy.width / 2; enemySoldierDotsContainer.y = 0; // Add the container to the enemy enemy.addChild(enemySoldierDotsContainer); enemySoldierCountText.anchor.set(1, 0.5); enemySoldierCountText.x = enemy.x - 300; // Position to the left of the enemy enemySoldierCountText.y = enemy.y; // Center vertically with the enemy enemySoldierCountText.setText("150"); // Set initial enemy soldier count to 150 enemy.soldiers = 150; // Add soldiers property to enemy object game.addChild(enemySoldierCountText); // Initialize with 200 soldiers enemy.setSoldierCount = function (count) { enemy.soldiers = count; enemySoldierCountText.setText(count.toString()); // Clear existing soldier dots enemySoldierDotsContainer.removeChildren(); // Create new soldier dots based on count var dotSize = 20; // Same size as hero soldier dots var dotSpacing = 5; var dotsPerRow = 36; var rowSpacing = 5; var startX = -enemy.width / 2 - 120; // Start 120 units to the left of the enemy graphic var startY = -(Math.ceil(count / dotsPerRow) * (dotSize + rowSpacing)) / 2; // Center vertically for (var i = 0; i < enemy.soldiers; i++) { var dot = LK.getAsset('bullet', { // Using 'bullet' asset as a small dot width: dotSize, height: dotSize, anchorX: 0.5, anchorY: 0.5 }); dot.tint = 0xff0000; // Match enemy color var row = Math.floor(i / dotsPerRow); var col = i % dotsPerRow; dot.x = startX - (dotSize + dotSpacing) * col; // Position to the left dot.y = startY + (dotSize + rowSpacing) * row; enemySoldierDotsContainer.addChild(dot); } }; enemy.setSoldierCount(enemy.soldiers); // Render initial dots enemy.addChild(enemySoldierDotsContainer); // Add method for enemy to move soldiers enemy.moveSoldiersTo = function (targetX, targetY, soldiersToSend) { if (enemy.soldiers <= 0 || enemySoldierDotsContainer.children.length === 0 || soldiersToSend <= 0) return; // Ensure we don't send more soldiers than we have soldiersToSend = Math.min(soldiersToSend, enemy.soldiers); soldiersToSend = Math.min(soldiersToSend, enemySoldierDotsContainer.children.length); if (soldiersToSend <= 0) return; var dotsToMove = []; // Select dots to move for (var i = 0; i < soldiersToSend; i++) { if (enemySoldierDotsContainer.children.length > 0) { dotsToMove.push(enemySoldierDotsContainer.children[enemySoldierDotsContainer.children.length - 1 - i]); } } // For each dot, animate movement with simplified sequence for (var i = 0; i < dotsToMove.length; i++) { var dot = dotsToMove[i]; enemySoldierDotsContainer.removeChild(dot); // Calculate start position and distance var startX = enemy.x + dot.x; var startY = enemy.y + dot.y; var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); var duration = distance * 2; var delay = Math.random() * 200; // Use IIFE to capture current values (function (dotWidth, dotHeight, dotTint, startX, startY) { LK.setTimeout(function () { // Create temporary dot var tempDot = LK.getAsset('enemyDot', { width: dotWidth, height: dotHeight, anchorX: 0.5, anchorY: 0.5 }); tempDot.tint = dotTint; tempDot.x = startX; tempDot.y = startY; game.addChild(tempDot); // Single tween with city interaction check tween(tempDot, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeInOut, onFinish: function onFinish() { var cityHit = false; var cityInteracted = false; var targetCity = null; // Check if we hit a city if (game.cities) { for (var j = 0; j < game.cities.length; j++) { var city = game.cities[j]; if (Math.abs(city.x - targetX) < 50 && Math.abs(city.y - targetY) < 50) { cityHit = true; targetCity = city; // Process city interaction based on ownership if (city.captured) { // Against hero city if (city.soldiers > 1) { city.setSoldierCount(city.soldiers - 1); } else { // Enemy captures hero city city.captured = false; city.enemyCaptured = true; if (city.cityGraphic) { city.cityGraphic.tint = 0xFF0000; } city.setSoldierCount(0); city.setSoldierCount(1); // Add 20 soldiers to enemy total count when capturing a city enemy.setSoldierCount(enemy.soldiers + 20); } } else if (city.enemyCaptured) { // Reinforce enemy city city.setSoldierCount(city.soldiers + 1); cityInteracted = true; } else { // Against neutral city if (city.soldiers > 1) { city.setSoldierCount(city.soldiers - 1); } else { // Enemy captures neutral city city.enemyCaptured = true; if (city.cityGraphic) { city.cityGraphic.tint = 0xFF0000; } city.setSoldierCount(0); city.setSoldierCount(1); // Add 20 soldiers to enemy total count when capturing a city enemy.setSoldierCount(enemy.soldiers + 20); } } break; } } } // Return animation if needed if (cityInteracted && enemy && enemy.parent) { tween(tempDot, { x: enemy.x, y: enemy.y }, { duration: Math.max(200, distance * 2), easing: tween.linear, onFinish: function onFinish() { if (tempDot.parent) { tempDot.parent.removeChild(tempDot); } if (enemy && enemy.setSoldierCount) { enemy.setSoldierCount(enemy.soldiers + 1); } } }); } else { if (tempDot.parent) { tempDot.parent.removeChild(tempDot); } } } }); }, delay); })(dot.width, dot.height, dot.tint, startX, startY); } // Reduce enemy soldier count enemy.setSoldierCount(enemy.soldiers - soldiersToSend); }; // Add basic AI update logic to the enemy enemy.aiUpdate = function () { // Only run AI logic if the game is active and enemy has soldiers if (!isGameActive || !enemy.parent || enemy.soldiers <= 0 || !game.cities || game.cities.length === 0) { return; } // Throttle AI decision making (e.g., every 5 seconds) if (LK.ticks % 300 !== 0) { // 300 ticks = 5 seconds at 60 FPS return; } // Store available cities (not already controlled by enemy) var availableCities = []; for (var i = 0; i < game.cities.length; i++) { var city = game.cities[i]; // Skip cities already controlled by the enemy (identified by their graphic) if (city.cityGraphic && city.cityGraphic.lk && city.cityGraphic.lk.assetId === 'enemy') { continue; // Skip this city } availableCities.push(city); } // Choose a random city from available cities var targetCity = null; if (availableCities.length > 0) { // Pick a random city from the available ones var randomIndex = Math.floor(Math.random() * availableCities.length); targetCity = availableCities[randomIndex]; } // If a target city is found, send soldiers if (targetCity) { // Send half of the soldiers, minimum 1 var soldiersToSend = Math.max(1, Math.floor(enemy.soldiers / 2)); enemy.moveSoldiersTo(targetCity.x, targetCity.y, soldiersToSend); } }; // Create and add Rules Button to the GUI var rulesButton = new Text2("Rules", { size: 50, // Adjust size as needed fill: 0xFFFFFF // White color for the text }); rulesButton.anchor.set(1, 0); // Anchor to its top-right point for positioning rulesButton.interactive = true; rulesButton.down = function () { // Visual feedback on press: scale down tween(rulesButton, { scaleX: 0.95, scaleY: 0.95 }, { duration: 50 }); }; rulesButton.up = function () { // Visual feedback on release: scale back, then action tween(rulesButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 50, onFinish: function onFinish_rulesButton() { // Renamed callback for clarity if (rulesPopupInstance) { rulesPopupInstance.show(); } } }); }; // Add to top-right of the GUI overlay, with some padding LK.gui.topRight.addChild(rulesButton); rulesButton.x = -100; // 100px padding from the right screen edge (moved 80 units left from previous -20) rulesButton.y = 100; // Moved 80 units down (was 20) // Initialize RulesPopup if not already done (should be done once when game scene is set up) if (!rulesPopupInstance) { rulesPopupInstance = new RulesPopup(); LK.gui.center.addChild(rulesPopupInstance); // Add to GUI center, it will be invisible initially } } } }); }; self.showResult = function (memeName, index) { memeNameText.setText(""); // Remove meme name text descriptionText.setText(""); // Remove description text // Remove previous meme image if exists if (memeImage) { self.removeChild(memeImage); memeImage = null; } // Add new meme image based on index var memeAssetName = 'meme' + (index % 41 + 1); memeImage = LK.getAsset(memeAssetName, { anchorX: 0.5, anchorY: 0.5 }); memeImage.y = 100; self.addChild(memeImage); self.visible = true; // Simplified animation with a single tween for the card card.scale.set(0.1); card.alpha = 0; tween(card, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 500, easing: tween.elasticOut }); }; self.hide = function () { tween(card, { scaleX: 0.1, scaleY: 0.1, alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.visible = false; } }); }; function getMemeDescription(memeName, index) { var descriptions = ["You're observant and always noticing new opportunities, even when you should be focusing on what's right in front of you. You appreciate the complexity of choices and aren't afraid to show interest in something new and exciting.", "You're expressive and dramatic, never afraid to show your emotions. When you're upset, everyone knows it. You're also great at standing your ground even when faced with confusion or chaos.", "You have clear preferences and aren't afraid to express what you like and dislike. You make decisions confidently and know exactly what works for you. You're also not afraid to pass on trends that don't match your vibe.", "Your mind works in fascinating ways, and you love exploring ideas to their fullest extent. You can take simple concepts and develop them into complex philosophies. You appreciate intellectual growth and deep thinking.", "You're contemplative and always considering new perspectives. You challenge conventional wisdom and aren't afraid to question assumptions. Your thoughtful nature makes you excellent at solving problems.", "You're authentic in your reactions and wear your emotions on your sleeve. When something surprises you, everyone knows it. You bring honesty and genuine reactions to every situation.", "Much wow! Such personality! You're quirky, fun-loving, and don't take yourself too seriously. You approach life with curiosity and enthusiasm, finding joy in simple pleasures.", "You remain calm even when everything around you is falling apart. Your ability to accept challenging situations with a sense of humor makes you resilient. You're the steady presence others look to during chaos.", "You celebrate victories, both big and small. Your positive attitude helps you recognize achievements and builds confidence. You inspire others with your enthusiasm for life's successes.", "You embrace your awkwardness and aren't afraid to be yourself, even in uncomfortable situations. Your authenticity makes you relatable, and you find humor in life's awkward moments.", "You're innovative and think outside the box. Your creative approach to problems leads to unique solutions that others might not see.", "You're resilient and adaptive, thriving even in challenging situations. Your ability to find humor in difficulties makes you unstoppable.", "You're bold and unafraid to make a statement. When you enter a room, people notice, and your confidence is contagious to those around you.", "You're witty and quick with comebacks. Your sense of humor brightens people's days and helps diffuse tense situations.", "You're thoughtful and considerate, always putting others before yourself. Your empathy makes you an excellent friend and confidant.", "You're spontaneous and embrace life's unexpected moments. Your ability to go with the flow makes adventures more exciting.", "You're ambitious and persistent, never giving up on your goals even when faced with obstacles. Your determination inspires others.", "You're perceptive and notice details others miss. Your attention to the little things makes you excellent at understanding complex situations.", "You're balanced and maintain perspective even in chaotic times. Your ability to stay centered makes you a reliable presence.", "You're enthusiastic and approach life with infectious energy. Your passion ignites excitement in those around you.", "You have a keen eye for value and opportunities. Always finding ways to maximize gains with minimal effort - a natural entrepreneur!", "You're adaptable and practical, making the best of any situation with a quirky sense of humor. You navigate life with creative resourcefulness.", "You have a mischievous streak and enjoy creating a bit of chaos. Your adventurous spirit makes life exciting for everyone around you.", "You're contemplative and introspective, often lost in thought about life's deeper meanings. Your philosophical nature brings wisdom to conversations.", "You're expressive and communicate volumes without saying a word. Your authenticity resonates with people on a deeper level.", "You attract misfortune with surprising regularity, but face it with remarkable resilience and humor. Your ability to bounce back inspires others.", "You're steadfast in your opinions and enjoy intellectual debates. Your logical thinking and articulate expression make you persuasive in arguments.", "You maintain a slightly pessimistic outlook as a defense mechanism. Your sarcastic humor and straightforward nature are refreshing to those who know you.", "You possess a clever wit and enjoy a bit of harmless teasing. Your ability to find humor in everyday situations makes you delightful company.", "You're worldly and experienced, with fascinating stories to share. Your confidence and charm draw people to you naturally.", "You're intensely passionate about the people and things you care about. Your enthusiasm, while sometimes overwhelming, comes from a place of genuine love.", "You're sensitive to minor inconveniences and aren't afraid to express your frustrations. Your honesty about life's smaller struggles is relatable to everyone.", "You're efficient and value your time highly. You cut through unnecessary complications to get straight to what's important.", "You're optimistic and believe in possibilities. Your enthusiasm for new ventures inspires confidence in others.", "You celebrate life's victories with genuine joy. Your positive attitude and confidence help you overcome obstacles with grace.", "You question everything and aren't afraid to challenge conventional thinking. Your skeptical nature leads to deeper insights and understanding.", "You're perceptive about patterns and connections others miss. Your mind works in fascinating, sometimes paranoid ways that lead to unique insights.", "You're passionate about your interests and willing to invest in what you love. Your enthusiasm is contagious and inspires others to pursue their passions.", "You have a playful sense of humor that catches people off guard. Your ability to bring joy through unexpected means makes you unforgettable.", "You're practical and straightforward. You appreciate clear communication and have little patience for unnecessary complications.", "You're charming with a mischievous streak. Your ability to deliver uncomfortable truths with a smile makes difficult conversations easier."]; return descriptions[index % descriptions.length]; } return self; }); var RulesPopup = Container.expand(function () { var self = Container.call(this); self.visible = false; // Background var bg = self.attachAsset('rules_popup_bg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.85 }); var titleText = new Text2("Game Rules", { size: 70, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.y = -bg.height / 2 + 100; // Positioned from the top of the background self.addChild(titleText); var rulesContent = "1. Your soldiers move to the platform you click on.\n2. Your enemy gets 20 more troops for each platform they conquer.\n3. The one who conquers on platform 6 wins"; // Updated rules with new rule #3 var rulesText = new Text2(rulesContent, { size: 50, fill: 0xFFFFFF, wordWrap: true, wordWrapWidth: bg.width - 150, // Give some padding for word wrap align: 'center' // Center the text lines }); rulesText.anchor.set(0.5, 0.5); // Anchor to its own center rulesText.y = 0; // Vertically center the rules text block within the popup self.addChild(rulesText); var closeButton = new Text2("Kapat", { size: 60, fill: 0x3498DB // A nice blue color for the button }); closeButton.anchor.set(0.5, 0.5); closeButton.y = bg.height / 2 - 100; // Positioned from the bottom of the background closeButton.interactive = true; self.addChild(closeButton); closeButton.down = function () { tween(closeButton, { scaleX: 0.95, scaleY: 0.95 }, { duration: 50 }); }; closeButton.up = function () { tween(closeButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 50, onFinish: function onFinish() { self.hide(); } }); }; self.show = function () { self.visible = true; isGamePausedByRules = true; // Set global pause flag // If added to LK.gui, it should handle being on top. // If added to 'game', may need to bring to front: // if (self.parent) { self.parent.setChildIndex(self, self.parent.children.length - 1); } }; self.hide = function () { self.visible = false; isGamePausedByRules = false; // Unset global pause flag }; return self; }); var SpinButton = Container.expand(function () { var self = Container.call(this); var buttonGraphic = self.attachAsset('spinButton', { anchorX: 0.5, anchorY: 0.5 }); var label = new Text2("SPIN", { size: 60, fill: 0xFFFFFF }); label.anchor.set(0.5, 0.5); self.addChild(label); self.down = function (x, y, obj) { tween(buttonGraphic, { scale: 0.9 }, { duration: 100 }); }; self.up = function (x, y, obj) { tween(buttonGraphic, { scale: 1 }, { duration: 100, onFinish: function onFinish() { if (self.onSpin) { self.onSpin(); } } }); }; return self; }); var SpinWheel = Container.expand(function () { var self = Container.call(this); // Wheel background var wheelBase = self.attachAsset('wheel', { anchorX: 0.5, anchorY: 0.5 }); // Define meme categories var memeCategories = ["Distracted Boyfriend", "Woman Yelling at Cat", "Drake Hotline Bling", "Expanding Brain", "Think About It", "Surprised Pikachu", "Doge", "This is Fine", "Success Kid", "Awkward Penguin", "Galaxy Brain", "Disaster Girl", "Hide the Pain Harold", "Confused Math Lady", "One Does Not Simply", "Evil Kermit", "SpongeBob Meme", "Crying Jordan", "Confused Nick Young", "Roll Safe", "Stonks", "Bernie Mittens", "Disaster Girl", "Sad Keanu", "Pepe the Frog", "Bad Luck Brian", "Change My Mind", "Grumpy Cat", "Condescending Wonka", "The Most Interesting Man", "Overly Attached Girlfriend", "First World Problems", "Ain't Nobody Got Time", "Doge to the Moon", "Success Baby", "Futurama Fry", "Conspiracy Keanu", "Shut Up and Take My Money", "Rick Roll", "That Would Be Great", "Willy Wonka"]; // Create wheel sections for (var i = 0; i < memeCategories.length; i++) { var section = new WheelSection(i, memeCategories.length, memeCategories[i]); self.addChild(section); } // Track wheel state self.isSpinning = false; self.currentRotation = 0; self.targetRotation = 0; self.spinSpeed = 0; self.deceleration = 0; self.memeSections = memeCategories; self.spin = function () { if (self.isSpinning) return; // Play spin sound LK.getSound('spinSound').play(); self.isSpinning = true; self.spinSpeed = 0.2 + Math.random() * 0.1; // Random starting speed // Determine how many rotations (5-10) plus a random section var rotations = 5 + Math.floor(Math.random() * 5); var randomSection = Math.floor(Math.random() * 41); // Updated to include all 41 memes var sectionAngle = 2 * Math.PI / memeCategories.length; // Calculate target rotation: current + full rotations + position to the random section self.targetRotation = self.currentRotation + rotations * 2 * Math.PI + randomSection * sectionAngle; // Calculate deceleration rate to gradually stop at the target var totalAngleToTravel = self.targetRotation - self.currentRotation; self.deceleration = self.spinSpeed * self.spinSpeed / (2 * totalAngleToTravel); }; self.update = function () { if (self.isSpinning) { // Apply current speed self.currentRotation += self.spinSpeed; self.rotation = self.currentRotation; // Play wheel sound while spinning if (!self.wheelSoundPlaying) { LK.getSound('Wheel').play(); self.wheelSoundPlaying = true; } // Decelerate if (self.currentRotation < self.targetRotation) { self.spinSpeed -= self.deceleration; // Don't let speed go negative if (self.spinSpeed <= 0.001) { self.spinSpeed = 0.001; } } else { // We've reached or passed the target self.isSpinning = false; self.wheelSoundPlaying = false; self.currentRotation = self.targetRotation; self.rotation = self.currentRotation; // Calculate which section is at the top (pointer position) self.onSpinComplete(); } } else { // Stop wheel sound when not spinning if (self.wheelSoundPlaying) { LK.getSound('Wheel').stop(); self.wheelSoundPlaying = false; } } }; self.onSpinComplete = function () { // Calculate which section is at the pointer (top) var pointingAngle = (-self.rotation % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI); var sectionAngle = 2 * Math.PI / memeCategories.length; var sectionIndex = Math.floor(pointingAngle / sectionAngle); sectionIndex = (memeCategories.length - sectionIndex) % memeCategories.length; // Report the result if (self.onResult) { self.onResult(memeCategories[sectionIndex], sectionIndex); } // Play result sound LK.getSound('resultSound').play(); }; return self; }); var WheelSection = Container.expand(function (sectionIndex, totalSections, text) { var self = Container.call(this); var radius = 650; var angle = sectionIndex / totalSections * Math.PI * 2; var nextAngle = (sectionIndex + 1) / totalSections * Math.PI * 2; // Create a custom shape for the section using LK.getAsset var sectionShape = { width: radius * 2, height: radius * 2, color: getColorForSection(sectionIndex), shape: 'section_' + sectionIndex }; var section = LK.getAsset('section_' + sectionIndex, { anchorX: 0.5, anchorY: 0.5 }); // Position it correctly self.addChild(section); // No text labels on wheel sections function getColorForSection(index) { // A few vibrant colors that work well together var colors = [0xFF5757, // Red 0x47B8FF, // Blue 0xFFD557, // Yellow 0x7DFF57, // Green 0xFF57F7, // Pink 0x57FFBD, // Teal 0xFF8A57, // Orange 0xA757FF, // Purple 0x57FFFF, // Cyan 0xBCFF57, // Lime 0xFF9966, // Coral 0x66FF99, // Light Green 0x9966FF, // Lavender 0xFF66FF, // Magenta 0x66FFFF, // Light Blue 0xFFFF66, // Light Yellow 0x996633, // Brown 0x3399FF, // Sky Blue 0xFF3399, // Rose 0x33FF99 // Seafoam ]; return colors[index % colors.length]; } return self; }); /**** * Initialize Game ****/ // Initialize shapes for all wheel sections var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Set up game elements // Initialize shapes for all wheel sections for (var i = 0; i < 41; i++) { var radius = 650; var angle = i / 41 * Math.PI * 2; var nextAngle = (i + 1) / 41 * Math.PI * 2; // Define section shape } // Add background image var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; game.addChild(background); var wheel = new SpinWheel(); game.addChild(wheel); wheel.x = 2048 / 2; wheel.y = 2732 / 2 - 200; // Add pointer var pointer = LK.getAsset('pointer', { anchorX: 0.5, anchorY: 0 }); game.addChild(pointer); pointer.x = wheel.x; pointer.y = wheel.y - wheel.height / 2 - 20 + 230; // Moved 230 units down (150+80) pointer.rotation = Math.PI; // Point downward // Add spin button var spinButton = new SpinButton(); game.addChild(spinButton); spinButton.x = wheel.x; spinButton.y = wheel.y + wheel.height / 2 + 200; // Add result card (initially hidden) var resultCard = new MemeResultCard(); game.addChild(resultCard); resultCard.x = wheel.x; resultCard.y = wheel.y; // Title var gameTitle = new Text2("Spin to Meme", { size: 120, fill: 0x000000 }); gameTitle.anchor.set(0.5, 0.5); gameTitle.x = wheel.x; gameTitle.y = 280; // Moved 80 units down from original position game.addChild(gameTitle); // Subtitle var subtitle = new Text2("Discover Your Spirit Meme", { size: 60, fill: 0x000000 }); subtitle.anchor.set(0.5, 0.5); subtitle.x = wheel.x; subtitle.y = 380; // Moved 80 units down from original position game.addChild(subtitle); // Create hero but don't add to scene initially var hero = new Hero(); hero.x = wheel.x + 700; // Position to the right side of the wheel hero.y = wheel.y; var enemy = null; // Declare global enemy variable // hero will be added to scene only after START GAME button is clicked // Game state var isGameActive = true; var isGamePausedByRules = false; // Flag to control game pause state for rules var rulesPopupInstance; // Placeholder for the rules popup // Connect components spinButton.onSpin = function () { if (isGameActive && !wheel.isSpinning && !resultCard.visible) { wheel.spin(); } }; wheel.onResult = function (meme, index) { LK.setTimeout(function () { // Update hero with selected meme hero.updateWithMeme(index); // Show result card resultCard.showResult(meme, index); }, 500); }; resultCard.onClose = function () { isGameActive = true; }; // Add timer to increase hero soldier count every second var lastSoldierIncreaseTime = Date.now(); // Add down event handler to game for moving soldiers game.down = function (x, y, obj) { // Only handle if we're in gameplay mode (wheel is gone) and hero exists if (hero && hero.parent && !wheel.parent && game.cities) { var clickedOnCity = false; var targetCity = null; // Check if the click location is near any city center for (var i = 0; i < game.cities.length; i++) { var city = game.cities[i]; var dx = x - city.x; var dy = y - city.y; var distanceSq = dx * dx + dy * dy; // Use a squared click radius for efficiency (e.g., 150px radius) var clickRadiusSq = 150 * 150; if (distanceSq < clickRadiusSq) { clickedOnCity = true; targetCity = city; // Store the target city break; // Found a city, no need to check others } } // Only move soldiers if a city was clicked if (clickedOnCity && targetCity) { // Move hero's soldier dots toward the clicked city's center // Pass the actual city coordinates to ensure accuracy hero.moveSoldiersTo(targetCity.x, targetCity.y); } } }; // Game update loop game.update = function () { if (isGamePausedByRules) { return; // Skip game updates if rules popup is visible } if (wheel) { wheel.update(); } // If hero exists and game is in gameplay mode (not in wheel screen) if (hero && hero.parent && !wheel.parent && !isGamePausedByRules) { // Added !isGamePausedByRules // Check if a second has passed var currentTime = Date.now(); if (currentTime - lastSoldierIncreaseTime >= 1000) { // Increase soldier count by 3 hero.setSoldierCount(hero.soldiers + 3); // Update last increase time lastSoldierIncreaseTime = currentTime; } } // Update enemy AI if the enemy exists if (enemy && enemy.aiUpdate && !isGamePausedByRules) { // Added !isGamePausedByRules enemy.aiUpdate(); } // Update cities (move soldier dots) if (game.cities) { var capturedCitiesCount = 0; // Track number of captured cities for (var i = 0; i < game.cities.length; i++) { game.cities[i].update(); if (game.cities[i].captured) { capturedCitiesCount++; } } // Check if 6 cities are captured by the hero if (capturedCitiesCount >= 6) { // End the game and display 'end' text LK.showGameOver('end'); } // Check if 6 cities are captured by the enemy var enemyCapturedCitiesCount = 0; for (var j = 0; j < game.cities.length; j++) { if (game.cities[j].enemyCaptured) { enemyCapturedCitiesCount++; } } if (enemyCapturedCitiesCount >= 6) { // End the game when enemy captures 6 cities LK.showGameOver('end'); } } // Increase soldier count in captured cities every second (60 ticks) if (game.cities && LK.ticks % 60 === 0 && !isGamePausedByRules) { // Added !isGamePausedByRules for (var i = 0; i < game.cities.length; i++) { var city = game.cities[i]; // Increase if captured by hero OR enemy, and soldier count is less than 50 if ((city.captured || city.enemyCaptured) && city.soldiers < 50) { city.setSoldierCount(city.soldiers + 1); } } } }; // Start background music LK.playMusic('bgMusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var City = Container.expand(function () {
var self = Container.call(this);
// Create city graphics using shape
self.cityGraphic = self.attachAsset('hero', {
// Assign to self.cityGraphic
anchorX: 0.5,
anchorY: 0.5
});
// Default city properties
self.name = "";
self.captured = false; // Flag for hero capture
self.enemyCaptured = false; // Flag for enemy capture
self.soldiers = 0; // Track soldier count
// Change city color
self.cityGraphic.tint = 0x888888; // Default gray color for uncaptured cities
// City name text
var cityNameText = new Text2("", {
size: 40,
fill: 0xFFFFFF
});
cityNameText.anchor.set(0.5, 0.5);
cityNameText.y = 80;
self.addChild(cityNameText);
// Helper function to normalize dot speed
function normalizeSpeed(dot) {
var speed = Math.sqrt(dot.vx * dot.vx + dot.vy * dot.vy);
if (speed > 1.5) {
dot.vx = dot.vx / speed * 1.5;
dot.vy = dot.vy / speed * 1.5;
} else if (speed < 0.5) {
dot.vx = (dot.vx / speed || Math.random() - 0.5) * 0.5;
dot.vy = (dot.vy / speed || Math.random() - 0.5) * 0.5;
}
}
// Container for soldier dots
self.soldierDotsContainer = new Container();
self.addChild(self.soldierDotsContainer);
// Update city with name
self.setName = function (name) {
self.name = name;
cityNameText.setText(name);
};
// Set soldier count
self.setSoldierCount = function (count) {
count = Math.min(count, 50); // Cap soldier count at 50
self.soldiers = count;
// Clear existing soldier dots
self.soldierDotsContainer.removeChildren();
// Determine dot color based on capture status
var dotColor = 0x888888; // Default neutral color (gray)
var dotAsset = 'bullet'; // Default asset
if (self.captured) {
dotColor = 0x1fb6f2; // Hero color (blue)
dotAsset = 'bullet';
} else if (self.enemyCaptured) {
dotColor = 0xff0000; // Enemy color (red)
dotAsset = 'enemyDot';
}
// Create new soldier dots based on count
var dotSize = 15; // Smaller dots inside the city
var cityRadius = self.cityGraphic.width * 0.4; // Place dots within 80% of the radius
for (var i = 0; i < self.soldiers; i++) {
var dot = LK.getAsset(dotAsset, {
// Use appropriate asset
width: dotSize,
height: dotSize,
anchorX: 0.5,
anchorY: 0.5
});
dot.tint = dotColor; // Set color based on control
// Random position within the city radius
var angle = Math.random() * Math.PI * 2;
var radius = Math.random() * cityRadius;
dot.x = Math.cos(angle) * radius;
dot.y = Math.sin(angle) * radius;
// Add random movement properties
dot.vx = (Math.random() - 0.5) * 2; // Random velocity x (-1 to 1)
dot.vy = (Math.random() - 0.5) * 2; // Random velocity y (-1 to 1)
dot.maxRadius = cityRadius; // Store max radius for boundary check
self.soldierDotsContainer.addChild(dot);
}
};
// Capture city function
self.capture = function () {
if (!self.captured) {
self.captured = true;
self.cityGraphic.tint = 0x00FF00; // Change to green when captured
// Reset soldier count to zero when captured by the hero
self.setSoldierCount(0); // Reset to zero
// Animation effect when captured - simplified with a single tween
tween(self.cityGraphic, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(self.cityGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
} else {
// Reinforcement logic is now handled directly when soldiers arrive
} //{H} // Keep original line ID nearby if applicable
};
// Make city interactive
self.down = function () {
// When city is clicked, don't capture it automatically
// We'll only capture cities when soldiers reach them
};
// Add update method to move dots
self.update = function () {
var cityRadiusSq = self.cityGraphic.width * 0.4 * (self.cityGraphic.width * 0.4); // Squared radius for cheaper checks
for (var i = 0; i < self.soldierDotsContainer.children.length; i++) {
var dot = self.soldierDotsContainer.children[i];
// Move dot
dot.x += dot.vx;
dot.y += dot.vy;
// Check boundaries and reverse velocity if needed
var distSq = dot.x * dot.x + dot.y * dot.y;
if (distSq > cityRadiusSq) {
// Simple reflection: reverse velocity component perpendicular to boundary
// Or simpler: just reverse velocity if out of bounds
dot.x -= dot.vx; // Move back
dot.y -= dot.vy;
dot.vx *= -1;
dot.vy *= -1;
// Add slight randomness to avoid getting stuck in bounce loops
dot.vx += (Math.random() - 0.5) * 0.2;
dot.vy += (Math.random() - 0.5) * 0.2;
// Use normalizeSpeed helper function
normalizeSpeed(dot);
} else {
// Occasionally change direction slightly even when inside
if (Math.random() < 0.01) {
// 1% chance each frame
dot.vx += (Math.random() - 0.5) * 0.5;
dot.vy += (Math.random() - 0.5) * 0.5;
// Use normalizeSpeed helper function
normalizeSpeed(dot);
}
}
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
// Default hero asset (will be replaced with selected meme)
var heroGraphic = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
// Add soldier count text to the right side of hero
var soldierCountText = new Text2("0", {
size: 60,
fill: 0xFFFFFF
});
soldierCountText.anchor.set(0, 0.5);
soldierCountText.x = 300; // Position to the right of the hero
soldierCountText.y = 0; // Center vertically with the hero
self.addChild(soldierCountText);
// Container for soldier dots
var soldierDotsContainer = new Container();
self.addChild(soldierDotsContainer);
// Track soldier count
self.soldiers = 0;
// Set soldier count function
self.setSoldierCount = function (count) {
self.soldiers = count;
soldierCountText.setText(count.toString());
// Clear existing soldier dots
soldierDotsContainer.removeChildren();
// Create new soldier dots based on count
var dotSize = 20;
var dotSpacing = 10;
var startX = 450; // Position dots to the right of the soldier count text
var dotsPerRow = 40; // Maximum dots per row
var rowSpacing = 30; // Spacing between rows
for (var i = 0; i < self.soldiers; i++) {
var dot = LK.getAsset('bullet', {
// Using 'bullet' asset as a small dot
width: dotSize,
height: dotSize,
anchorX: 0.5,
anchorY: 0.5
});
dot.tint = 0x1fb6f2; // Match hero color
var row = Math.floor(i / dotsPerRow);
var col = i % dotsPerRow;
dot.x = startX + (dotSize + dotSpacing) * col;
dot.y = rowSpacing * row;
soldierDotsContainer.addChild(dot);
}
};
// Initialize with 40 soldiers
self.setSoldierCount(40);
// Method to move soldier dots from the hero base to a target position
self.moveSoldiersTo = function (targetX, targetY) {
// Ensure we have soldiers to move
if (self.soldiers <= 0) return;
// Let's send all soldiers for now
var soldiersToSend = self.soldiers;
var dotAssetId = 'bullet'; // Asset for hero dots
var dotTint = 0x1fb6f2; // Hero color
var dotSize = 20;
// Check if the hero is actually on the stage to get global position
if (!self.parent) return;
// Calculate start position (simplified)
var startPos = {
x: self.x,
y: self.y
};
// Get positions of dots from the soldierDotsContainer
var dotPositions = [];
if (soldierDotsContainer && soldierDotsContainer.children) {
for (var i = 0; i < soldierDotsContainer.children.length; i++) {
var dot = soldierDotsContainer.children[i];
// Use simple offset from hero position
dotPositions.push({
x: self.x + dot.x,
y: self.y + dot.y
});
}
}
// Clear the hero's local soldier dots display and count
self.setSoldierCount(0);
// Animate each soldier dot individually
for (var i = 0; i < soldiersToSend; i++) {
// Use the dot's actual position if available, otherwise use hero center
var startX = i < dotPositions.length ? dotPositions[i].x : startPos.x;
var startY = i < dotPositions.length ? dotPositions[i].y : startPos.y;
// Calculate duration based on distance
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var duration = Math.max(200, distance * 2); // Minimum 200ms, 2ms per pixel
// Add a random delay so they don't all move at once
var delay = Math.random() * 300;
// Create and animate dot with sequential tweens
(function (startX, startY) {
LK.setTimeout(function () {
// Create the temporary dot
var tempDot = LK.getAsset(dotAssetId, {
width: dotSize,
height: dotSize,
anchorX: 0.5,
anchorY: 0.5
});
tempDot.tint = dotTint;
tempDot.x = startX;
tempDot.y = startY;
game.addChild(tempDot);
// First tween: move to target
tween(tempDot, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.linear,
onFinish: function onFinish() {
var cityHit = false;
var cityInteracted = false;
// Check for city interaction
if (game.cities) {
for (var j = 0; j < game.cities.length; j++) {
var city = game.cities[j];
// Distance check to city
var hitDx = city.x - targetX;
var hitDy = city.y - targetY;
if (hitDx * hitDx + hitDy * hitDy < 50 * 50) {
cityHit = true;
// Process city interaction
if (city.enemyCaptured) {
// Against enemy city
if (city.soldiers > 1) {
city.setSoldierCount(city.soldiers - 1);
} else {
city.enemyCaptured = false;
city.capture();
city.setSoldierCount(Math.max(0, 1 - city.soldiers));
cityInteracted = true;
}
} else if (city.captured) {
// Reinforce friendly city
city.setSoldierCount(city.soldiers + 1);
cityInteracted = true;
} else {
// Against neutral city
if (city.soldiers > 1) {
city.setSoldierCount(city.soldiers - 1);
} else {
city.capture();
city.setSoldierCount(Math.max(0, 1 - city.soldiers));
cityInteracted = true;
}
}
break; // Found a city, stop checking
}
}
}
// Return animation if needed
if (cityInteracted && hero && hero.parent) {
// Second tween: return to hero
tween(tempDot, {
x: hero.x,
y: hero.y
}, {
duration: Math.max(200, distance * 2),
easing: tween.linear,
onFinish: function onFinish() {
// Remove dot and increment hero count
if (tempDot.parent) {
tempDot.parent.removeChild(tempDot);
}
if (hero && hero.setSoldierCount) {
hero.setSoldierCount(hero.soldiers + 1);
}
}
});
} else {
// Remove dot if no return needed
if (tempDot.parent) {
tempDot.parent.removeChild(tempDot);
}
}
}
});
}, delay);
})(startX, startY);
}
};
// Method to update hero with selected meme
self.updateWithMeme = function (memeIndex) {
// Remove current graphic
self.removeChild(heroGraphic);
// Add new meme image based on index
var memeAssetName = 'meme' + (memeIndex % 41 + 1);
heroGraphic = LK.getAsset(memeAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Scale to appropriate size
heroGraphic.scale.set(0.75);
self.addChild(heroGraphic);
};
return self;
});
var MemeResultCard = Container.expand(function () {
var self = Container.call(this);
// Initially hidden
self.visible = false;
var card = self.attachAsset('memeCard', {
anchorX: 0.5,
anchorY: 0.5
});
// Meme image placeholder
var memeImage = null;
// Meme title
var titleText = new Text2("Your Spirit Meme", {
size: 80,
fill: 0x333333
});
titleText.anchor.set(0.5, 0);
titleText.y = -500;
self.addChild(titleText);
// Meme name
var memeNameText = new Text2("", {
size: 60,
fill: 0xFF5722
});
memeNameText.anchor.set(0.5, 0);
memeNameText.y = -400;
self.addChild(memeNameText);
// Description
var descriptionText = new Text2("", {
size: 40,
fill: 0x555555
});
descriptionText.anchor.set(0.5, 0);
descriptionText.y = -280;
descriptionText.wordWrap = true;
descriptionText.wordWrapWidth = 1400;
self.addChild(descriptionText);
// Close button
var closeButton = new Text2("START GAME", {
size: 100,
fill: 0x3498DB
});
closeButton.anchor.set(0.5, 0.5);
closeButton.y = 550;
closeButton.interactive = true;
self.addChild(closeButton);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
self.hide();
// Change background to 'arkaplan' image
var newBackground = LK.getAsset('arkaplan', {
anchorX: 0.5,
anchorY: 0.5
});
newBackground.x = 2048 / 2;
newBackground.y = 2732 / 2;
game.addChild(newBackground);
if (self.onClose) {
self.onClose();
// Remove all game elements except hero
game.removeChild(wheel);
game.removeChild(pointer);
game.removeChild(spinButton);
game.removeChild(gameTitle);
game.removeChild(subtitle);
game.removeChild(background);
game.removeChild(resultCard);
// Create cities array in game scope
if (!game.cities) {
game.cities = [];
// City names
var cityNames = ["İnstagram", "Facebook", "Snapchat", "Pinterest", "X", "Youtube"];
// Create 6 cities and position them around the screen
for (var i = 0; i < 6; i++) {
var city = new City();
city.setName(cityNames[i]);
// Set initial soldier count to exactly 30 for all cities
city.setSoldierCount(30);
// Position cities in a grid (2 rows, 3 columns)
var row = Math.floor(i / 3);
var col = i % 3;
city.x = 400 + col * 700;
// Move Istanbul, Ankara and Izmir 80 units lower on Y axis
if (i < 3) {
// First 3 cities are İnstagram, Facebook, Snapchat
city.y = 880 + row * 900; // Added 80 to original y position
} else {
city.y = 960 + row * 900; // Added 160 to original y position for Bursa, Antalya, Konya
}
// Add city to game and store in array
game.addChild(city);
game.cities.push(city);
}
}
// Position hero in top left corner of the screen
hero.x = 290; // Updated to be 190 units to the right of previous position
hero.y = 280; // Updated to be 180 units below the original position
// Ensure hero is added to the scene
if (!hero.parent) {
game.addChild(hero);
}
// Add enemy to the bottom right corner of the screen
// Make enemy a global variable
enemy = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
enemy.x = 2048 - 250; // Right side of screen with some margin
enemy.y = 2732 - 250; // Bottom of screen with some margin
game.addChild(enemy);
// Add soldier count text to the left of the enemy
var enemySoldierCountText = new Text2("0", {
size: 60,
fill: 0xFFFFFF
});
// Container for soldier dots
var enemySoldierDotsContainer = new Container();
// Position the container relative to the enemy
enemySoldierDotsContainer.x = -enemy.width / 2;
enemySoldierDotsContainer.y = 0;
// Add the container to the enemy
enemy.addChild(enemySoldierDotsContainer);
enemySoldierCountText.anchor.set(1, 0.5);
enemySoldierCountText.x = enemy.x - 300; // Position to the left of the enemy
enemySoldierCountText.y = enemy.y; // Center vertically with the enemy
enemySoldierCountText.setText("150"); // Set initial enemy soldier count to 150
enemy.soldiers = 150; // Add soldiers property to enemy object
game.addChild(enemySoldierCountText);
// Initialize with 200 soldiers
enemy.setSoldierCount = function (count) {
enemy.soldiers = count;
enemySoldierCountText.setText(count.toString());
// Clear existing soldier dots
enemySoldierDotsContainer.removeChildren();
// Create new soldier dots based on count
var dotSize = 20; // Same size as hero soldier dots
var dotSpacing = 5;
var dotsPerRow = 36;
var rowSpacing = 5;
var startX = -enemy.width / 2 - 120; // Start 120 units to the left of the enemy graphic
var startY = -(Math.ceil(count / dotsPerRow) * (dotSize + rowSpacing)) / 2; // Center vertically
for (var i = 0; i < enemy.soldiers; i++) {
var dot = LK.getAsset('bullet', {
// Using 'bullet' asset as a small dot
width: dotSize,
height: dotSize,
anchorX: 0.5,
anchorY: 0.5
});
dot.tint = 0xff0000; // Match enemy color
var row = Math.floor(i / dotsPerRow);
var col = i % dotsPerRow;
dot.x = startX - (dotSize + dotSpacing) * col; // Position to the left
dot.y = startY + (dotSize + rowSpacing) * row;
enemySoldierDotsContainer.addChild(dot);
}
};
enemy.setSoldierCount(enemy.soldiers); // Render initial dots
enemy.addChild(enemySoldierDotsContainer);
// Add method for enemy to move soldiers
enemy.moveSoldiersTo = function (targetX, targetY, soldiersToSend) {
if (enemy.soldiers <= 0 || enemySoldierDotsContainer.children.length === 0 || soldiersToSend <= 0) return;
// Ensure we don't send more soldiers than we have
soldiersToSend = Math.min(soldiersToSend, enemy.soldiers);
soldiersToSend = Math.min(soldiersToSend, enemySoldierDotsContainer.children.length);
if (soldiersToSend <= 0) return;
var dotsToMove = [];
// Select dots to move
for (var i = 0; i < soldiersToSend; i++) {
if (enemySoldierDotsContainer.children.length > 0) {
dotsToMove.push(enemySoldierDotsContainer.children[enemySoldierDotsContainer.children.length - 1 - i]);
}
}
// For each dot, animate movement with simplified sequence
for (var i = 0; i < dotsToMove.length; i++) {
var dot = dotsToMove[i];
enemySoldierDotsContainer.removeChild(dot);
// Calculate start position and distance
var startX = enemy.x + dot.x;
var startY = enemy.y + dot.y;
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var duration = distance * 2;
var delay = Math.random() * 200;
// Use IIFE to capture current values
(function (dotWidth, dotHeight, dotTint, startX, startY) {
LK.setTimeout(function () {
// Create temporary dot
var tempDot = LK.getAsset('enemyDot', {
width: dotWidth,
height: dotHeight,
anchorX: 0.5,
anchorY: 0.5
});
tempDot.tint = dotTint;
tempDot.x = startX;
tempDot.y = startY;
game.addChild(tempDot);
// Single tween with city interaction check
tween(tempDot, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
var cityHit = false;
var cityInteracted = false;
var targetCity = null;
// Check if we hit a city
if (game.cities) {
for (var j = 0; j < game.cities.length; j++) {
var city = game.cities[j];
if (Math.abs(city.x - targetX) < 50 && Math.abs(city.y - targetY) < 50) {
cityHit = true;
targetCity = city;
// Process city interaction based on ownership
if (city.captured) {
// Against hero city
if (city.soldiers > 1) {
city.setSoldierCount(city.soldiers - 1);
} else {
// Enemy captures hero city
city.captured = false;
city.enemyCaptured = true;
if (city.cityGraphic) {
city.cityGraphic.tint = 0xFF0000;
}
city.setSoldierCount(0);
city.setSoldierCount(1);
// Add 20 soldiers to enemy total count when capturing a city
enemy.setSoldierCount(enemy.soldiers + 20);
}
} else if (city.enemyCaptured) {
// Reinforce enemy city
city.setSoldierCount(city.soldiers + 1);
cityInteracted = true;
} else {
// Against neutral city
if (city.soldiers > 1) {
city.setSoldierCount(city.soldiers - 1);
} else {
// Enemy captures neutral city
city.enemyCaptured = true;
if (city.cityGraphic) {
city.cityGraphic.tint = 0xFF0000;
}
city.setSoldierCount(0);
city.setSoldierCount(1);
// Add 20 soldiers to enemy total count when capturing a city
enemy.setSoldierCount(enemy.soldiers + 20);
}
}
break;
}
}
}
// Return animation if needed
if (cityInteracted && enemy && enemy.parent) {
tween(tempDot, {
x: enemy.x,
y: enemy.y
}, {
duration: Math.max(200, distance * 2),
easing: tween.linear,
onFinish: function onFinish() {
if (tempDot.parent) {
tempDot.parent.removeChild(tempDot);
}
if (enemy && enemy.setSoldierCount) {
enemy.setSoldierCount(enemy.soldiers + 1);
}
}
});
} else {
if (tempDot.parent) {
tempDot.parent.removeChild(tempDot);
}
}
}
});
}, delay);
})(dot.width, dot.height, dot.tint, startX, startY);
}
// Reduce enemy soldier count
enemy.setSoldierCount(enemy.soldiers - soldiersToSend);
};
// Add basic AI update logic to the enemy
enemy.aiUpdate = function () {
// Only run AI logic if the game is active and enemy has soldiers
if (!isGameActive || !enemy.parent || enemy.soldiers <= 0 || !game.cities || game.cities.length === 0) {
return;
}
// Throttle AI decision making (e.g., every 5 seconds)
if (LK.ticks % 300 !== 0) {
// 300 ticks = 5 seconds at 60 FPS
return;
}
// Store available cities (not already controlled by enemy)
var availableCities = [];
for (var i = 0; i < game.cities.length; i++) {
var city = game.cities[i];
// Skip cities already controlled by the enemy (identified by their graphic)
if (city.cityGraphic && city.cityGraphic.lk && city.cityGraphic.lk.assetId === 'enemy') {
continue; // Skip this city
}
availableCities.push(city);
}
// Choose a random city from available cities
var targetCity = null;
if (availableCities.length > 0) {
// Pick a random city from the available ones
var randomIndex = Math.floor(Math.random() * availableCities.length);
targetCity = availableCities[randomIndex];
}
// If a target city is found, send soldiers
if (targetCity) {
// Send half of the soldiers, minimum 1
var soldiersToSend = Math.max(1, Math.floor(enemy.soldiers / 2));
enemy.moveSoldiersTo(targetCity.x, targetCity.y, soldiersToSend);
}
};
// Create and add Rules Button to the GUI
var rulesButton = new Text2("Rules", {
size: 50,
// Adjust size as needed
fill: 0xFFFFFF // White color for the text
});
rulesButton.anchor.set(1, 0); // Anchor to its top-right point for positioning
rulesButton.interactive = true;
rulesButton.down = function () {
// Visual feedback on press: scale down
tween(rulesButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 50
});
};
rulesButton.up = function () {
// Visual feedback on release: scale back, then action
tween(rulesButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 50,
onFinish: function onFinish_rulesButton() {
// Renamed callback for clarity
if (rulesPopupInstance) {
rulesPopupInstance.show();
}
}
});
};
// Add to top-right of the GUI overlay, with some padding
LK.gui.topRight.addChild(rulesButton);
rulesButton.x = -100; // 100px padding from the right screen edge (moved 80 units left from previous -20)
rulesButton.y = 100; // Moved 80 units down (was 20)
// Initialize RulesPopup if not already done (should be done once when game scene is set up)
if (!rulesPopupInstance) {
rulesPopupInstance = new RulesPopup();
LK.gui.center.addChild(rulesPopupInstance); // Add to GUI center, it will be invisible initially
}
}
}
});
};
self.showResult = function (memeName, index) {
memeNameText.setText(""); // Remove meme name text
descriptionText.setText(""); // Remove description text
// Remove previous meme image if exists
if (memeImage) {
self.removeChild(memeImage);
memeImage = null;
}
// Add new meme image based on index
var memeAssetName = 'meme' + (index % 41 + 1);
memeImage = LK.getAsset(memeAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
memeImage.y = 100;
self.addChild(memeImage);
self.visible = true;
// Simplified animation with a single tween for the card
card.scale.set(0.1);
card.alpha = 0;
tween(card, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500,
easing: tween.elasticOut
});
};
self.hide = function () {
tween(card, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
}
});
};
function getMemeDescription(memeName, index) {
var descriptions = ["You're observant and always noticing new opportunities, even when you should be focusing on what's right in front of you. You appreciate the complexity of choices and aren't afraid to show interest in something new and exciting.", "You're expressive and dramatic, never afraid to show your emotions. When you're upset, everyone knows it. You're also great at standing your ground even when faced with confusion or chaos.", "You have clear preferences and aren't afraid to express what you like and dislike. You make decisions confidently and know exactly what works for you. You're also not afraid to pass on trends that don't match your vibe.", "Your mind works in fascinating ways, and you love exploring ideas to their fullest extent. You can take simple concepts and develop them into complex philosophies. You appreciate intellectual growth and deep thinking.", "You're contemplative and always considering new perspectives. You challenge conventional wisdom and aren't afraid to question assumptions. Your thoughtful nature makes you excellent at solving problems.", "You're authentic in your reactions and wear your emotions on your sleeve. When something surprises you, everyone knows it. You bring honesty and genuine reactions to every situation.", "Much wow! Such personality! You're quirky, fun-loving, and don't take yourself too seriously. You approach life with curiosity and enthusiasm, finding joy in simple pleasures.", "You remain calm even when everything around you is falling apart. Your ability to accept challenging situations with a sense of humor makes you resilient. You're the steady presence others look to during chaos.", "You celebrate victories, both big and small. Your positive attitude helps you recognize achievements and builds confidence. You inspire others with your enthusiasm for life's successes.", "You embrace your awkwardness and aren't afraid to be yourself, even in uncomfortable situations. Your authenticity makes you relatable, and you find humor in life's awkward moments.", "You're innovative and think outside the box. Your creative approach to problems leads to unique solutions that others might not see.", "You're resilient and adaptive, thriving even in challenging situations. Your ability to find humor in difficulties makes you unstoppable.", "You're bold and unafraid to make a statement. When you enter a room, people notice, and your confidence is contagious to those around you.", "You're witty and quick with comebacks. Your sense of humor brightens people's days and helps diffuse tense situations.", "You're thoughtful and considerate, always putting others before yourself. Your empathy makes you an excellent friend and confidant.", "You're spontaneous and embrace life's unexpected moments. Your ability to go with the flow makes adventures more exciting.", "You're ambitious and persistent, never giving up on your goals even when faced with obstacles. Your determination inspires others.", "You're perceptive and notice details others miss. Your attention to the little things makes you excellent at understanding complex situations.", "You're balanced and maintain perspective even in chaotic times. Your ability to stay centered makes you a reliable presence.", "You're enthusiastic and approach life with infectious energy. Your passion ignites excitement in those around you.", "You have a keen eye for value and opportunities. Always finding ways to maximize gains with minimal effort - a natural entrepreneur!", "You're adaptable and practical, making the best of any situation with a quirky sense of humor. You navigate life with creative resourcefulness.", "You have a mischievous streak and enjoy creating a bit of chaos. Your adventurous spirit makes life exciting for everyone around you.", "You're contemplative and introspective, often lost in thought about life's deeper meanings. Your philosophical nature brings wisdom to conversations.", "You're expressive and communicate volumes without saying a word. Your authenticity resonates with people on a deeper level.", "You attract misfortune with surprising regularity, but face it with remarkable resilience and humor. Your ability to bounce back inspires others.", "You're steadfast in your opinions and enjoy intellectual debates. Your logical thinking and articulate expression make you persuasive in arguments.", "You maintain a slightly pessimistic outlook as a defense mechanism. Your sarcastic humor and straightforward nature are refreshing to those who know you.", "You possess a clever wit and enjoy a bit of harmless teasing. Your ability to find humor in everyday situations makes you delightful company.", "You're worldly and experienced, with fascinating stories to share. Your confidence and charm draw people to you naturally.", "You're intensely passionate about the people and things you care about. Your enthusiasm, while sometimes overwhelming, comes from a place of genuine love.", "You're sensitive to minor inconveniences and aren't afraid to express your frustrations. Your honesty about life's smaller struggles is relatable to everyone.", "You're efficient and value your time highly. You cut through unnecessary complications to get straight to what's important.", "You're optimistic and believe in possibilities. Your enthusiasm for new ventures inspires confidence in others.", "You celebrate life's victories with genuine joy. Your positive attitude and confidence help you overcome obstacles with grace.", "You question everything and aren't afraid to challenge conventional thinking. Your skeptical nature leads to deeper insights and understanding.", "You're perceptive about patterns and connections others miss. Your mind works in fascinating, sometimes paranoid ways that lead to unique insights.", "You're passionate about your interests and willing to invest in what you love. Your enthusiasm is contagious and inspires others to pursue their passions.", "You have a playful sense of humor that catches people off guard. Your ability to bring joy through unexpected means makes you unforgettable.", "You're practical and straightforward. You appreciate clear communication and have little patience for unnecessary complications.", "You're charming with a mischievous streak. Your ability to deliver uncomfortable truths with a smile makes difficult conversations easier."];
return descriptions[index % descriptions.length];
}
return self;
});
var RulesPopup = Container.expand(function () {
var self = Container.call(this);
self.visible = false;
// Background
var bg = self.attachAsset('rules_popup_bg', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.85
});
var titleText = new Text2("Game Rules", {
size: 70,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -bg.height / 2 + 100; // Positioned from the top of the background
self.addChild(titleText);
var rulesContent = "1. Your soldiers move to the platform you click on.\n2. Your enemy gets 20 more troops for each platform they conquer.\n3. The one who conquers on platform 6 wins"; // Updated rules with new rule #3
var rulesText = new Text2(rulesContent, {
size: 50,
fill: 0xFFFFFF,
wordWrap: true,
wordWrapWidth: bg.width - 150,
// Give some padding for word wrap
align: 'center' // Center the text lines
});
rulesText.anchor.set(0.5, 0.5); // Anchor to its own center
rulesText.y = 0; // Vertically center the rules text block within the popup
self.addChild(rulesText);
var closeButton = new Text2("Kapat", {
size: 60,
fill: 0x3498DB // A nice blue color for the button
});
closeButton.anchor.set(0.5, 0.5);
closeButton.y = bg.height / 2 - 100; // Positioned from the bottom of the background
closeButton.interactive = true;
self.addChild(closeButton);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 50
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 50,
onFinish: function onFinish() {
self.hide();
}
});
};
self.show = function () {
self.visible = true;
isGamePausedByRules = true; // Set global pause flag
// If added to LK.gui, it should handle being on top.
// If added to 'game', may need to bring to front:
// if (self.parent) { self.parent.setChildIndex(self, self.parent.children.length - 1); }
};
self.hide = function () {
self.visible = false;
isGamePausedByRules = false; // Unset global pause flag
};
return self;
});
var SpinButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphic = self.attachAsset('spinButton', {
anchorX: 0.5,
anchorY: 0.5
});
var label = new Text2("SPIN", {
size: 60,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
self.down = function (x, y, obj) {
tween(buttonGraphic, {
scale: 0.9
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(buttonGraphic, {
scale: 1
}, {
duration: 100,
onFinish: function onFinish() {
if (self.onSpin) {
self.onSpin();
}
}
});
};
return self;
});
var SpinWheel = Container.expand(function () {
var self = Container.call(this);
// Wheel background
var wheelBase = self.attachAsset('wheel', {
anchorX: 0.5,
anchorY: 0.5
});
// Define meme categories
var memeCategories = ["Distracted Boyfriend", "Woman Yelling at Cat", "Drake Hotline Bling", "Expanding Brain", "Think About It", "Surprised Pikachu", "Doge", "This is Fine", "Success Kid", "Awkward Penguin", "Galaxy Brain", "Disaster Girl", "Hide the Pain Harold", "Confused Math Lady", "One Does Not Simply", "Evil Kermit", "SpongeBob Meme", "Crying Jordan", "Confused Nick Young", "Roll Safe", "Stonks", "Bernie Mittens", "Disaster Girl", "Sad Keanu", "Pepe the Frog", "Bad Luck Brian", "Change My Mind", "Grumpy Cat", "Condescending Wonka", "The Most Interesting Man", "Overly Attached Girlfriend", "First World Problems", "Ain't Nobody Got Time", "Doge to the Moon", "Success Baby", "Futurama Fry", "Conspiracy Keanu", "Shut Up and Take My Money", "Rick Roll", "That Would Be Great", "Willy Wonka"];
// Create wheel sections
for (var i = 0; i < memeCategories.length; i++) {
var section = new WheelSection(i, memeCategories.length, memeCategories[i]);
self.addChild(section);
}
// Track wheel state
self.isSpinning = false;
self.currentRotation = 0;
self.targetRotation = 0;
self.spinSpeed = 0;
self.deceleration = 0;
self.memeSections = memeCategories;
self.spin = function () {
if (self.isSpinning) return;
// Play spin sound
LK.getSound('spinSound').play();
self.isSpinning = true;
self.spinSpeed = 0.2 + Math.random() * 0.1; // Random starting speed
// Determine how many rotations (5-10) plus a random section
var rotations = 5 + Math.floor(Math.random() * 5);
var randomSection = Math.floor(Math.random() * 41); // Updated to include all 41 memes
var sectionAngle = 2 * Math.PI / memeCategories.length;
// Calculate target rotation: current + full rotations + position to the random section
self.targetRotation = self.currentRotation + rotations * 2 * Math.PI + randomSection * sectionAngle;
// Calculate deceleration rate to gradually stop at the target
var totalAngleToTravel = self.targetRotation - self.currentRotation;
self.deceleration = self.spinSpeed * self.spinSpeed / (2 * totalAngleToTravel);
};
self.update = function () {
if (self.isSpinning) {
// Apply current speed
self.currentRotation += self.spinSpeed;
self.rotation = self.currentRotation;
// Play wheel sound while spinning
if (!self.wheelSoundPlaying) {
LK.getSound('Wheel').play();
self.wheelSoundPlaying = true;
}
// Decelerate
if (self.currentRotation < self.targetRotation) {
self.spinSpeed -= self.deceleration;
// Don't let speed go negative
if (self.spinSpeed <= 0.001) {
self.spinSpeed = 0.001;
}
} else {
// We've reached or passed the target
self.isSpinning = false;
self.wheelSoundPlaying = false;
self.currentRotation = self.targetRotation;
self.rotation = self.currentRotation;
// Calculate which section is at the top (pointer position)
self.onSpinComplete();
}
} else {
// Stop wheel sound when not spinning
if (self.wheelSoundPlaying) {
LK.getSound('Wheel').stop();
self.wheelSoundPlaying = false;
}
}
};
self.onSpinComplete = function () {
// Calculate which section is at the pointer (top)
var pointingAngle = (-self.rotation % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
var sectionAngle = 2 * Math.PI / memeCategories.length;
var sectionIndex = Math.floor(pointingAngle / sectionAngle);
sectionIndex = (memeCategories.length - sectionIndex) % memeCategories.length;
// Report the result
if (self.onResult) {
self.onResult(memeCategories[sectionIndex], sectionIndex);
}
// Play result sound
LK.getSound('resultSound').play();
};
return self;
});
var WheelSection = Container.expand(function (sectionIndex, totalSections, text) {
var self = Container.call(this);
var radius = 650;
var angle = sectionIndex / totalSections * Math.PI * 2;
var nextAngle = (sectionIndex + 1) / totalSections * Math.PI * 2;
// Create a custom shape for the section using LK.getAsset
var sectionShape = {
width: radius * 2,
height: radius * 2,
color: getColorForSection(sectionIndex),
shape: 'section_' + sectionIndex
};
var section = LK.getAsset('section_' + sectionIndex, {
anchorX: 0.5,
anchorY: 0.5
});
// Position it correctly
self.addChild(section);
// No text labels on wheel sections
function getColorForSection(index) {
// A few vibrant colors that work well together
var colors = [0xFF5757,
// Red
0x47B8FF,
// Blue
0xFFD557,
// Yellow
0x7DFF57,
// Green
0xFF57F7,
// Pink
0x57FFBD,
// Teal
0xFF8A57,
// Orange
0xA757FF,
// Purple
0x57FFFF,
// Cyan
0xBCFF57,
// Lime
0xFF9966,
// Coral
0x66FF99,
// Light Green
0x9966FF,
// Lavender
0xFF66FF,
// Magenta
0x66FFFF,
// Light Blue
0xFFFF66,
// Light Yellow
0x996633,
// Brown
0x3399FF,
// Sky Blue
0xFF3399,
// Rose
0x33FF99 // Seafoam
];
return colors[index % colors.length];
}
return self;
});
/****
* Initialize Game
****/
// Initialize shapes for all wheel sections
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Set up game elements
// Initialize shapes for all wheel sections
for (var i = 0; i < 41; i++) {
var radius = 650;
var angle = i / 41 * Math.PI * 2;
var nextAngle = (i + 1) / 41 * Math.PI * 2;
// Define section shape
}
// Add background image
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
game.addChild(background);
var wheel = new SpinWheel();
game.addChild(wheel);
wheel.x = 2048 / 2;
wheel.y = 2732 / 2 - 200;
// Add pointer
var pointer = LK.getAsset('pointer', {
anchorX: 0.5,
anchorY: 0
});
game.addChild(pointer);
pointer.x = wheel.x;
pointer.y = wheel.y - wheel.height / 2 - 20 + 230; // Moved 230 units down (150+80)
pointer.rotation = Math.PI; // Point downward
// Add spin button
var spinButton = new SpinButton();
game.addChild(spinButton);
spinButton.x = wheel.x;
spinButton.y = wheel.y + wheel.height / 2 + 200;
// Add result card (initially hidden)
var resultCard = new MemeResultCard();
game.addChild(resultCard);
resultCard.x = wheel.x;
resultCard.y = wheel.y;
// Title
var gameTitle = new Text2("Spin to Meme", {
size: 120,
fill: 0x000000
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = wheel.x;
gameTitle.y = 280; // Moved 80 units down from original position
game.addChild(gameTitle);
// Subtitle
var subtitle = new Text2("Discover Your Spirit Meme", {
size: 60,
fill: 0x000000
});
subtitle.anchor.set(0.5, 0.5);
subtitle.x = wheel.x;
subtitle.y = 380; // Moved 80 units down from original position
game.addChild(subtitle);
// Create hero but don't add to scene initially
var hero = new Hero();
hero.x = wheel.x + 700; // Position to the right side of the wheel
hero.y = wheel.y;
var enemy = null; // Declare global enemy variable
// hero will be added to scene only after START GAME button is clicked
// Game state
var isGameActive = true;
var isGamePausedByRules = false; // Flag to control game pause state for rules
var rulesPopupInstance; // Placeholder for the rules popup
// Connect components
spinButton.onSpin = function () {
if (isGameActive && !wheel.isSpinning && !resultCard.visible) {
wheel.spin();
}
};
wheel.onResult = function (meme, index) {
LK.setTimeout(function () {
// Update hero with selected meme
hero.updateWithMeme(index);
// Show result card
resultCard.showResult(meme, index);
}, 500);
};
resultCard.onClose = function () {
isGameActive = true;
};
// Add timer to increase hero soldier count every second
var lastSoldierIncreaseTime = Date.now();
// Add down event handler to game for moving soldiers
game.down = function (x, y, obj) {
// Only handle if we're in gameplay mode (wheel is gone) and hero exists
if (hero && hero.parent && !wheel.parent && game.cities) {
var clickedOnCity = false;
var targetCity = null;
// Check if the click location is near any city center
for (var i = 0; i < game.cities.length; i++) {
var city = game.cities[i];
var dx = x - city.x;
var dy = y - city.y;
var distanceSq = dx * dx + dy * dy;
// Use a squared click radius for efficiency (e.g., 150px radius)
var clickRadiusSq = 150 * 150;
if (distanceSq < clickRadiusSq) {
clickedOnCity = true;
targetCity = city; // Store the target city
break; // Found a city, no need to check others
}
}
// Only move soldiers if a city was clicked
if (clickedOnCity && targetCity) {
// Move hero's soldier dots toward the clicked city's center
// Pass the actual city coordinates to ensure accuracy
hero.moveSoldiersTo(targetCity.x, targetCity.y);
}
}
};
// Game update loop
game.update = function () {
if (isGamePausedByRules) {
return; // Skip game updates if rules popup is visible
}
if (wheel) {
wheel.update();
}
// If hero exists and game is in gameplay mode (not in wheel screen)
if (hero && hero.parent && !wheel.parent && !isGamePausedByRules) {
// Added !isGamePausedByRules
// Check if a second has passed
var currentTime = Date.now();
if (currentTime - lastSoldierIncreaseTime >= 1000) {
// Increase soldier count by 3
hero.setSoldierCount(hero.soldiers + 3);
// Update last increase time
lastSoldierIncreaseTime = currentTime;
}
}
// Update enemy AI if the enemy exists
if (enemy && enemy.aiUpdate && !isGamePausedByRules) {
// Added !isGamePausedByRules
enemy.aiUpdate();
}
// Update cities (move soldier dots)
if (game.cities) {
var capturedCitiesCount = 0; // Track number of captured cities
for (var i = 0; i < game.cities.length; i++) {
game.cities[i].update();
if (game.cities[i].captured) {
capturedCitiesCount++;
}
}
// Check if 6 cities are captured by the hero
if (capturedCitiesCount >= 6) {
// End the game and display 'end' text
LK.showGameOver('end');
}
// Check if 6 cities are captured by the enemy
var enemyCapturedCitiesCount = 0;
for (var j = 0; j < game.cities.length; j++) {
if (game.cities[j].enemyCaptured) {
enemyCapturedCitiesCount++;
}
}
if (enemyCapturedCitiesCount >= 6) {
// End the game when enemy captures 6 cities
LK.showGameOver('end');
}
}
// Increase soldier count in captured cities every second (60 ticks)
if (game.cities && LK.ticks % 60 === 0 && !isGamePausedByRules) {
// Added !isGamePausedByRules
for (var i = 0; i < game.cities.length; i++) {
var city = game.cities[i];
// Increase if captured by hero OR enemy, and soldier count is less than 50
if ((city.captured || city.enemyCaptured) && city.soldiers < 50) {
city.setSoldierCount(city.soldiers + 1);
}
}
}
};
// Start background music
LK.playMusic('bgMusic');