User prompt
Ok, now there are two issues: 1. THe bezier lines are not rendered anymore. Fix them. 2. The labels of the elements are weirdly shown when the wheel spins, in different places. They shoudl kept their relative positions constant. 3. Hover does not work anymore. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Okyou can remove the debug frame of the top element ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok now it works. However, if your wheel stops on a top element which is disabled, sping it until the closest non disabled element., ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok now you have some problems with neighbours, and that' sbecause your wheel stops sometimes between elements. NEVER stop between elements. You should stop the wheel at a perfect position as before the spinning, with a top element perfectly aligned. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I see. Ok for you the TOP element is the LEFT element <- You neeed the element on the ROCK position, that is 4 positions if you go right on the wheel, from Metal (left). ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Your top calculation is absolutely wrong and it's totally breaking the game. Can you add a debug frame to the element you consider the top element? So taht I can see what is your problem ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Your top element calculation is wrong. I don't know what's so difficult: at the starting point, is ROCK. Just remember those coordinates. Spin the wheel. What is there instead of ROCK - that's the top. Always make sure the wheel after spinning stops with at element aligned on top as in the startt. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I don't think you are properly tracking the top element. I was lightning and you selected scissors. There is an issue with your top element calculation. Also please hide the labels of the elements while spinning. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
No. The marker does not work. Implement it otherwise: don't use a marker, just keep track of the top element (in the beginning it's Rock). Spin the wheel. When it stops, make sure there is an element on top. That element is the AI element. This way, we always know the top element when the wheel stops is the AI element. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
No. So the marker should determine which is the AI button. If the marker stops on top of Metal, AI will chose metal. But there are conditions: it can't never end on a disabled element. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
There should be a bug - it stopped at lightning but gas was selected. I think the marker is pointing to another place?
User prompt
Ok after the VS battle, the wheel is weirdly rotated and it's not even showing the real place where it stopped, there should be a bug. Also all the elements are rotated. So please fix that, make sure the wheel starts after every VS place in the same position as it stars when the game starts. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok you spin the wheel correctly, but there are issues: 1. Elements can't be rotated, keep then facing / oriented teh same place. 2. Reset the wheel after each battle. 3. Add a marker to see which is the one that will be selected after the spinning wheel finishes. 4. Leave 2 seconds before moving to VS screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok, let's make something cool. I want you to mimic a spinning wheel after the user has selected an element. The wheel spins until it stops - that element button where it stops will be the one selected by the AI. Don't change the VS screen or anything else. Also, make sure the wheel never stops spinning on a disabled button. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Hide the bezier lines when in the VS screen
User prompt
Remove the arrow heads from the bezier lines
Code edit (1 edits merged)
Please save this source code
User prompt
Ok about the bezier curves - let's change them. Let's make them have a control point that is always the center of the wheel. So they go from winning element to losing element throw the center of the wheel. Also, make much more segements and the half of the line going to the winning element should be green, the half from the losing element - red ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok the bezier lines work but the curvature is in the opposite side. If the elements are on the right, they should be lie (, if the elements are on the left, then ). ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please do
Code edit (1 edits merged)
Please save this source code
User prompt
The arrows - don't make erase them after you draw them. Leave them. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Disabling is not working. I should NOT be able to reuse any element the user o the AI have used in previous rounds! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The buttons I used are still enabled!!! Please correct. The should be disabled, meaning 1) you can't select them 2) you can't hover them 3) they should be alpha 0.5 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BattleElement = Container.expand(function (elementType, isPlayer) { var self = Container.call(this); self.elementType = elementType; self.isPlayer = isPlayer; var background = self.attachAsset('elementButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); var icon = self.attachAsset(elementType, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); var label = new Text2(elementType.toUpperCase(), { size: 32, fill: 0xffffff }); label.anchor.set(0.5, 0.5); label.y = 220; self.addChild(label); self.playWinAnimation = function () { var effect = self.attachAsset('winEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 500 }); tween(effect, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.removeChild(effect); } }); }; self.playLoseAnimation = function () { var effect = self.attachAsset('loseEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); tween(self, { scaleX: 0.7, scaleY: 0.7, alpha: 0.5 }, { duration: 500 }); tween(effect, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.removeChild(effect); } }); }; return self; }); var ElementButton = Container.expand(function (elementType, index) { var self = Container.call(this); self.elementType = elementType; self.index = index; self.isSelected = false; self.isDisabled = false; var button = self.attachAsset('elementButton', { anchorX: 0.5, anchorY: 0.5 }); var icon = self.attachAsset(elementType, { anchorX: 0.5, anchorY: 0.5 }); var label = new Text2(elementType.toUpperCase(), { size: 24, fill: 0xffffff }); label.anchor.set(0.5, 0.5); self.addChild(label); // Position text toward wheel center self.positionTextTowardCenter = function (centerX, centerY) { var angle = Math.atan2(self.y - centerY, self.x - centerX); var offsetX = Math.cos(angle) * textOffsetTowardCenter; var offsetY = Math.sin(angle) * textOffsetTowardCenter; label.x = -offsetX; label.y = -offsetY; }; self.setSelected = function (selected) { self.isSelected = selected; if (selected) { button.tint = 0xffd700; tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200 }); } else { button.tint = 0xffffff; tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }; self.setDisabled = function (disabled) { self.isDisabled = disabled; if (disabled) { button.alpha = 0.5; icon.alpha = 0.5; label.alpha = 0.5; } else { button.alpha = 1.0; icon.alpha = 1.0; label.alpha = 1.0; } }; self.down = function (x, y, obj) { if (gameState === 'selection' && !self.isDisabled) { LK.getSound('select').play(); selectElement(self.elementType); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xffffff }); /**** * Game Code ****/ // Add background image var backgroundImage = game.attachAsset('background', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.137, scaleY: 1.013 }); backgroundImage.x = 1024; backgroundImage.y = 1366; // Game elements and their relationships var elements = ['rock', 'paper', 'scissors', 'water', 'fire', 'air', 'lightning', 'tree', 'gun', 'sponge', 'smoke', 'gas', 'metal', 'ice', 'sand', 'oil']; // Element defeat relationships (each element defeats 8 others) var defeats = { // Rock: Heavy and solid, crushes fragile things, breaks weapons, absorbs energy 'rock': ['scissors', 'sponge', 'gas', 'metal', 'ice', 'gun', 'tree', 'sand'], // Paper: Wraps and covers, conducts electricity, absorbs liquids, blocks air flow 'paper': ['rock', 'metal', 'water', 'gas', 'sand', 'ice', 'air', 'smoke'], // Scissors: Sharp cutting tool, cuts through soft materials and gases 'scissors': ['paper', 'sponge', 'air', 'tree', 'gas', 'oil', 'ice', 'smoke'], // Water: Extinguishes fire, erodes materials, conducts electricity, flows through spaces 'water': ['fire', 'rock', 'scissors', 'gas', 'oil', 'sand', 'tree', 'metal'], // Fire: Burns combustible materials, melts solids, heats and expands gases 'fire': ['paper', 'scissors', 'sponge', 'ice', 'tree', 'sand', 'oil', 'smoke'], // Air: Feeds fire, disperses gases, creates pressure, moves objects 'air': ['fire', 'gas', 'smoke', 'metal', 'rock', 'oil', 'tree', 'gun'], // Lightning: Electrical discharge, conducts through metals and water, ionizes gases 'lightning': ['water', 'metal', 'gun', 'air', 'paper', 'sponge', 'smoke', 'sand'], // Tree: Absorbs water and nutrients, grows through materials, provides shelter 'tree': ['water', 'paper', 'sponge', 'smoke', 'gun', 'sand', 'ice', 'gas'], // Gun: Projectile weapon, breaks through barriers, fires through gases 'gun': ['scissors', 'rock', 'tree', 'metal', 'gas', 'ice', 'oil', 'paper'], // Sponge: Absorbs liquids and gases, flexible material, filters particles 'sponge': ['water', 'metal', 'air', 'paper', 'gas', 'rock', 'sand', 'smoke'], // Smoke: Obscures vision, suffocates, corrodes metals, covers surfaces 'smoke': ['ice', 'gun', 'rock', 'paper', 'air', 'metal', 'water', 'oil'], // Gas: Expands and fills spaces, displaces air, creates pressure, volatile 'gas': ['paper', 'ice', 'gun', 'smoke', 'air', 'scissors', 'sponge', 'sand'], // Metal: Strong and durable, conducts electricity, resists cutting, heavy 'metal': ['scissors', 'tree', 'ice', 'fire', 'gun', 'oil', 'rock', 'sand'], // Ice: Freezes liquids, slippery surface, preserves, expands when frozen 'ice': ['air', 'water', 'paper', 'sponge', 'fire', 'smoke', 'gun', 'lightning'], // Sand: Abrasive particles, absorbs liquids, extinguishes fire, buries objects 'sand': ['scissors', 'ice', 'gun', 'fire', 'air', 'paper', 'rock', 'lightning'], // Oil: Slippery liquid, flammable, coats surfaces, lubricates mechanisms 'oil': ['rock', 'scissors', 'gun', 'metal', 'water', 'gas', 'lightning', 'fire'] }; // Action keywords for how elements defeat others var actionKeywords = { 'rock': { 'scissors': 'crushes', 'sponge': 'crushes', 'gas': 'disperses', 'metal': 'breaks', 'ice': 'shatters', 'gun': 'blocks', 'tree': 'crushes', 'sand': 'compacts' }, 'paper': { 'rock': 'wraps', 'metal': 'covers', 'water': 'absorbs', 'gas': 'captures', 'sand': 'covers', 'ice': 'insulates', 'air': 'blocks', 'smoke': 'filters' }, 'scissors': { 'paper': 'cuts', 'sponge': 'cuts', 'air': 'cuts', 'tree': 'cuts', 'gas': 'cuts', 'oil': 'cuts', 'ice': 'cuts', 'smoke': 'cuts' }, 'water': { 'fire': 'extinguishes', 'rock': 'erodes', 'scissors': 'rusts', 'gas': 'dissolves', 'oil': 'displaces', 'sand': 'washes', 'tree': 'nourishes', 'metal': 'rusts' }, 'fire': { 'paper': 'burns', 'scissors': 'melts', 'sponge': 'burns', 'ice': 'melts', 'tree': 'burns', 'sand': 'heats', 'oil': 'ignites', 'smoke': 'burns' }, 'air': { 'fire': 'feeds', 'gas': 'disperses', 'smoke': 'clears', 'metal': 'oxidizes', 'rock': 'erodes', 'oil': 'evaporates', 'tree': 'sways', 'gun': 'deflects' }, 'lightning': { 'water': 'electrifies', 'metal': 'conducts', 'gun': 'shorts', 'air': 'ionizes', 'paper': 'ignites', 'sponge': 'shocks', 'smoke': 'disperses', 'sand': 'vitrifies' }, 'tree': { 'water': 'absorbs', 'paper': 'grows over', 'sponge': 'outgrows', 'smoke': 'filters', 'gun': 'blocks', 'sand': 'roots in', 'ice': 'breaks', 'gas': 'absorbs' }, 'gun': { 'scissors': 'shoots', 'rock': 'shatters', 'tree': 'shoots through', 'metal': 'pierces', 'gas': 'ignites', 'ice': 'shatters', 'oil': 'ignites', 'paper': 'pierces' }, 'sponge': { 'water': 'absorbs', 'metal': 'corrodes', 'air': 'filters', 'paper': 'soaks', 'gas': 'absorbs', 'rock': 'erodes', 'sand': 'absorbs', 'smoke': 'filters' }, 'smoke': { 'ice': 'melts', 'gun': 'jams', 'rock': 'corrodes', 'paper': 'stains', 'air': 'pollutes', 'metal': 'corrodes', 'water': 'pollutes', 'oil': 'mixes with' }, 'gas': { 'paper': 'dissolves', 'ice': 'sublimates', 'gun': 'corrodes', 'smoke': 'displaces', 'air': 'displaces', 'scissors': 'corrodes', 'sponge': 'fills', 'sand': 'displaces' }, 'metal': { 'scissors': 'dulls', 'tree': 'cuts', 'ice': 'breaks', 'fire': 'conducts', 'gun': 'reinforces', 'oil': 'repels', 'rock': 'crushes', 'sand': 'compacts' }, 'ice': { 'air': 'freezes', 'water': 'freezes', 'paper': 'freezes', 'sponge': 'freezes', 'fire': 'extinguishes', 'smoke': 'condenses', 'gun': 'jams', 'lightning': 'grounds' }, 'sand': { 'scissors': 'dulls', 'ice': 'melts', 'gun': 'jams', 'fire': 'smothers', 'air': 'fills', 'paper': 'abrades', 'rock': 'erodes', 'lightning': 'grounds' }, 'oil': { 'rock': 'lubricates', 'scissors': 'lubricates', 'gun': 'lubricates', 'metal': 'lubricates', 'water': 'floats on', 'gas': 'dissolves', 'lightning': 'insulates', 'fire': 'feeds' } }; // Game state variables var gameState = 'selection'; // 'selection', 'spinning', 'battle', 'result' var elementButtons = []; var playerElement = null; var aiElement = null; var playerBattleElement = null; var aiBattleElement = null; var vsText = null; var consecutiveWins = 0; var difficultyLevel = 1; var battleTimer = 0; var hoveredButton = null; // Track which button is currently hovered var victoryArrows = []; // Array to store victory arrows var usedPlayerElements = []; // Track elements used by player var usedAIElements = []; // Track elements used by AI var wheelContainer = null; // Container for wheel elements var isWheelSpinning = false; // Track if wheel is currently spinning var wheelRotation = 0; // Current wheel rotation // Function to create victory arrow between two element buttons function createVictoryArrow(fromElement, toElement) { var fromButton = null; var toButton = null; // Find the buttons for the given elements for (var i = 0; i < elementButtons.length; i++) { if (elementButtons[i].elementType === fromElement) { fromButton = elementButtons[i]; } if (elementButtons[i].elementType === toElement) { toButton = elementButtons[i]; } } if (!fromButton || !toButton) { return; // Can't create arrow if buttons not found } // Calculate arrow properties var dx = toButton.x - fromButton.x; var dy = toButton.y - fromButton.y; var distance = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); // Calculate angular separation to determine curve direction var centerX = 1024; var centerY = 1400; var fromAngle = Math.atan2(fromButton.y - centerY, fromButton.x - centerX); var toAngle = Math.atan2(toButton.y - centerY, toButton.x - centerX); var angularDiff = Math.abs(fromAngle - toAngle); if (angularDiff > Math.PI) { angularDiff = 2 * Math.PI - angularDiff; } // Determine curve intensity based on proximity var curvature = 0; if (angularDiff < Math.PI / 2) { // Elements are within 90 degrees of each other curvature = 400; // Strong outward curve } else if (angularDiff < Math.PI) { // Elements are within 180 degrees curvature = 200; // Moderate curve } else { curvature = 100; // Gentle curve for opposite elements } // Use wheel center as control point for Bezier curve var controlX = centerX; var controlY = centerY; // Create arrow container var arrowContainer = new Container(); // Create curved arrow using Bezier curve segments with more segments var numSegments = 50; var segmentWidth = 15; for (var i = 0; i < numSegments; i++) { var t = i / (numSegments - 1); // Quadratic Bezier curve calculation var x = (1 - t) * (1 - t) * fromButton.x + 2 * (1 - t) * t * controlX + t * t * toButton.x; var y = (1 - t) * (1 - t) * fromButton.y + 2 * (1 - t) * t * controlY + t * t * toButton.y; // Calculate next point for rotation var nextT = Math.min(1, (i + 1) / (numSegments - 1)); var nextX = (1 - nextT) * (1 - nextT) * fromButton.x + 2 * (1 - nextT) * nextT * controlX + nextT * nextT * toButton.x; var nextY = (1 - nextT) * (1 - nextT) * fromButton.y + 2 * (1 - nextT) * nextT * controlY + nextT * nextT * toButton.y; // Skip segments too close to buttons var distFromStart = Math.sqrt((x - fromButton.x) * (x - fromButton.x) + (y - fromButton.y) * (y - fromButton.y)); var distFromEnd = Math.sqrt((x - toButton.x) * (x - toButton.x) + (y - toButton.y) * (y - toButton.y)); if (distFromStart < 100 || distFromEnd < 100) { continue; } var segment = arrowContainer.attachAsset('line', { width: segmentWidth, height: 5, anchorX: 0.5, anchorY: 0.5 }); segment.x = x; segment.y = y; // Rotate segment to match curve direction var segmentAngle = Math.atan2(nextY - y, nextX - x); segment.rotation = segmentAngle; // Color segments: first half green (winning element side), second half red (losing element side) if (t < 0.5) { segment.tint = 0x00ff00; // Green color for first half } else { segment.tint = 0xff0000; // Red color for second half } } // Arrowheads removed - only curved line segments remain // Position container at origin (segments are already positioned absolutely) arrowContainer.x = 0; arrowContainer.y = 0; arrowContainer.alpha = 0; // Add to game and animate game.addChild(arrowContainer); victoryArrows.push(arrowContainer); // Animate arrow appearance tween(arrowContainer, { alpha: 1 }, { duration: 500 }); } // Function to get the element at the top position function getTopElement() { // At the start, rock (index 0) is at the top (-PI/2) // Calculate angle per element var anglePerElement = Math.PI * 2 / elements.length; // Normalize rotation to 0-2PI range var normalizedRotation = (wheelContainer.rotation % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2); // Calculate how many element positions we've rotated from the starting position var elementSteps = Math.round(normalizedRotation / anglePerElement); // Find which element is now at the ROCK position (top position) // Since wheel rotates clockwise, we subtract the steps from the starting rock index var topElementIndex = (0 - elementSteps + elements.length * 10) % elements.length; var topElement = elements[topElementIndex]; return topElement; } // Text positioning parameter - distance to move text toward wheel center var textOffsetTowardCenter = 160; // Adjustable parameter for text positioning // UI elements var titleText = new Text2('ULTIMATE ELEMENTS SHOWDOWN', { size: 48, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); LK.gui.top.addChild(titleText); titleText.y = 50; var instructionText = new Text2('Choose your element', { size: 32, fill: 0xCCCCCC }); instructionText.anchor.set(0.5, 0.5); game.addChild(instructionText); instructionText.x = 1024; instructionText.y = 400; var scoreText = new Text2('Score: 0', { size: 36, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); LK.gui.topRight.addChild(scoreText); scoreText.x = -20; scoreText.y = 20; var winsText = new Text2('Wins: 0', { size: 32, fill: 0xFFFFFF }); winsText.anchor.set(1, 0); LK.gui.topRight.addChild(winsText); winsText.x = -20; winsText.y = 70; // Create element selection grid function createElementButtons() { var centerX = 1024; var centerY = 1400; var radius = 800; // Create wheel container for spinning animation wheelContainer = new Container(); wheelContainer.x = centerX; wheelContainer.y = centerY; game.addChild(wheelContainer); for (var i = 0; i < elements.length; i++) { var angle = i / elements.length * Math.PI * 2 - Math.PI / 2; var x = Math.cos(angle) * radius; var y = Math.sin(angle) * radius; var button = wheelContainer.addChild(new ElementButton(elements[i], i)); button.x = x; button.y = y; button.positionTextTowardCenter(0, 0); // Use wheel center as reference elementButtons.push(button); } } // Select element function function selectElement(elementType) { if (gameState !== 'selection') { return; } // Check if element has already been used by player if (usedPlayerElements.indexOf(elementType) !== -1) { return; // Don't allow selection of already used elements } playerElement = elementType; // Update button states for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setSelected(elementButtons[i].elementType === elementType); } // Start wheel spinning animation startWheelSpin(); } // Start wheel spinning animation function startWheelSpin() { gameState = 'spinning'; isWheelSpinning = true; instructionText.setText('AI is choosing...'); // Hide element labels during spinning for (var i = 0; i < elementButtons.length; i++) { var button = elementButtons[i]; var label = button.children[button.children.length - 1]; // Label is the last child if (label && label.setText) { tween(label, { alpha: 0 }, { duration: 300 }); } } // Get available elements for AI (not disabled) var availableElements = []; for (var i = 0; i < elementButtons.length; i++) { if (!elementButtons[i].isDisabled) { availableElements.push(elementButtons[i].elementType); } } // Calculate how many spins we need to ensure we land on an available element var spinAmount = 3 + Math.random() * 3; // 3-6 full rotations var baseRotation = spinAmount * Math.PI * 2; // Choose a random available element to land on var targetElement = availableElements[Math.floor(Math.random() * availableElements.length)]; var targetIndex = elements.indexOf(targetElement); // Calculate angle per element var anglePerElement = Math.PI * 2 / elements.length; // Calculate the rotation needed to put target element at top // Rock (index 0) starts at -PI/2, so target element should be at -PI/2 var targetAngleFromStart = targetIndex * anglePerElement; var rotationToTarget = -targetAngleFromStart; // Negative because wheel rotates clockwise // Final rotation combines base spins with precise positioning var finalRotation = baseRotation + rotationToTarget; // Ensure we stop at exact element positions by rounding to nearest element angle var exactElementPosition = Math.round(finalRotation / anglePerElement) * anglePerElement; finalRotation = exactElementPosition; // Reset wheel rotation for animation wheelContainer.rotation = 0; // Function to check if wheel stopped on disabled element and continue spinning function checkAndContinueSpinning() { // Get the current top element var currentTopElement = getTopElement(); // Find the button for this element var topButton = null; for (var i = 0; i < elementButtons.length; i++) { if (elementButtons[i].elementType === currentTopElement) { topButton = elementButtons[i]; break; } } // If the top element is disabled, continue spinning to next available element if (topButton && topButton.isDisabled) { // Find the next non-disabled element var nextAvailableIndex = -1; var currentIndex = elements.indexOf(currentTopElement); for (var step = 1; step < elements.length; step++) { var checkIndex = (currentIndex + step) % elements.length; var checkElement = elements[checkIndex]; var checkButton = null; for (var i = 0; i < elementButtons.length; i++) { if (elementButtons[i].elementType === checkElement) { checkButton = elementButtons[i]; break; } } if (checkButton && !checkButton.isDisabled) { nextAvailableIndex = checkIndex; break; } } if (nextAvailableIndex !== -1) { // Calculate additional rotation needed to reach next available element var additionalSteps = (nextAvailableIndex - currentIndex + elements.length) % elements.length; var additionalRotation = additionalSteps * anglePerElement; // Continue spinning to the next available element tween(wheelContainer, { rotation: wheelContainer.rotation - additionalRotation }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Check again in case we need to continue further checkAndContinueSpinning(); } }); return; } } // If we reach here, the wheel has stopped on a valid element isWheelSpinning = false; aiElement = currentTopElement; // Show element labels again for (var i = 0; i < elementButtons.length; i++) { var button = elementButtons[i]; var label = button.children[button.children.length - 1]; // Label is the last child if (label && label.setText) { tween(label, { alpha: 1 }, { duration: 300 }); } } // Start battle after wheel stops LK.setTimeout(function () { startBattle(); }, 2000); // Wait 2 seconds before VS screen } // Animate wheel spinning tween(wheelContainer, { rotation: finalRotation }, { duration: 2000 + Math.random() * 1000, // 2-3 seconds easing: tween.easeOut, onFinish: function onFinish() { // Check if we need to continue spinning checkAndContinueSpinning(); } }); } // AI element selection function getAIElement() { // Get available elements (not used by AI yet) var availableElements = []; for (var i = 0; i < elements.length; i++) { if (usedAIElements.indexOf(elements[i]) === -1) { availableElements.push(elements[i]); } } // If no available elements, use all elements (shouldn't happen in normal gameplay) if (availableElements.length === 0) { availableElements = elements.slice(); } // Basic AI that becomes more strategic with difficulty if (difficultyLevel === 1) { // Random selection from available elements return availableElements[Math.floor(Math.random() * availableElements.length)]; } else if (difficultyLevel === 2) { // 30% chance to counter player's last choice if (Math.random() < 0.3 && playerElement) { var counters = []; for (var i = 0; i < availableElements.length; i++) { if (defeats[availableElements[i]] && defeats[availableElements[i]].indexOf(playerElement) !== -1) { counters.push(availableElements[i]); } } if (counters.length > 0) { return counters[Math.floor(Math.random() * counters.length)]; } } return availableElements[Math.floor(Math.random() * availableElements.length)]; } else { // 50% chance to counter player's choice if (Math.random() < 0.5 && playerElement) { var counters = []; for (var i = 0; i < availableElements.length; i++) { if (defeats[availableElements[i]] && defeats[availableElements[i]].indexOf(playerElement) !== -1) { counters.push(availableElements[i]); } } if (counters.length > 0) { return counters[Math.floor(Math.random() * counters.length)]; } } return availableElements[Math.floor(Math.random() * availableElements.length)]; } } // Start battle phase function startBattle() { gameState = 'battle'; // aiElement is already set by wheel spin, only get it if not set if (!aiElement) { aiElement = getAIElement(); } // Track used elements if (usedPlayerElements.indexOf(playerElement) === -1) { usedPlayerElements.push(playerElement); } if (usedAIElements.indexOf(aiElement) === -1) { usedAIElements.push(aiElement); } // Reset hover state hoveredButton = null; // Hide victory arrows during battle for (var i = 0; i < victoryArrows.length; i++) { tween(victoryArrows[i], { alpha: 0 }, { duration: 300 }); } // Hide selection elements and disable them for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setDisabled(true); tween(elementButtons[i], { alpha: 0 }, { duration: 300 }); } instructionText.setText('BATTLE!'); // Create battle elements playerBattleElement = game.addChild(new BattleElement(playerElement, true)); playerBattleElement.x = 400; playerBattleElement.y = 1100; playerBattleElement.alpha = 0; aiBattleElement = game.addChild(new BattleElement(aiElement, false)); aiBattleElement.x = 1648; aiBattleElement.y = 1100; aiBattleElement.alpha = 0; // Animate battle elements in tween(playerBattleElement, { alpha: 1, x: 512 }, { duration: 500 }); tween(aiBattleElement, { alpha: 1, x: 1536 }, { duration: 500 }); // Add VS text vsText = new Text2('VS', { size: 72, fill: 0xFF6B35 }); vsText.anchor.set(0.5, 0.5); vsText.x = 1024; vsText.y = 1100; vsText.alpha = 0; game.addChild(vsText); tween(vsText, { alpha: 1, scaleX: 1.5, scaleY: 1.5 }, { duration: 300, onFinish: function onFinish() { LK.getSound('battle').play(); // Start battle timer battleTimer = 0; } }); } // Get action keyword for how one element defeats another function getActionKeyword(winner, loser) { if (actionKeywords[winner] && actionKeywords[winner][loser]) { return actionKeywords[winner][loser]; } return 'defeats'; } // Check battle result function checkBattleResult() { var playerWins = defeats[playerElement] && defeats[playerElement].indexOf(aiElement) !== -1; var aiWins = defeats[aiElement] && defeats[aiElement].indexOf(playerElement) !== -1; if (playerWins) { return 'player'; } else if (aiWins) { return 'ai'; } else { return 'tie'; } } // Show battle result function showBattleResult() { gameState = 'result'; var result = checkBattleResult(); if (result === 'player') { LK.getSound('win').play(); playerBattleElement.playWinAnimation(); aiBattleElement.playLoseAnimation(); consecutiveWins++; var points = 10 * difficultyLevel * consecutiveWins; LK.setScore(LK.getScore() + points); var actionWord = getActionKeyword(playerElement, aiElement); instructionText.setText(playerElement.toUpperCase() + ' ' + actionWord + ' ' + aiElement.toUpperCase() + '!\nYOU WIN! +' + points + ' points'); instructionText.tint = 0x00ff00; // Increase difficulty every 3 wins if (consecutiveWins % 3 === 0 && difficultyLevel < 3) { difficultyLevel++; } } else if (result === 'ai') { LK.getSound('lose').play(); playerBattleElement.playLoseAnimation(); aiBattleElement.playWinAnimation(); consecutiveWins = 0; var actionWord = getActionKeyword(aiElement, playerElement); instructionText.setText(aiElement.toUpperCase() + ' ' + actionWord + ' ' + playerElement.toUpperCase() + '!\nYOU LOSE!'); instructionText.tint = 0xff0000; } else { instructionText.setText('TIE!'); instructionText.tint = 0xffff00; } // Update UI scoreText.setText('Score: ' + LK.getScore()); winsText.setText('Wins: ' + consecutiveWins); // Return to selection after delay LK.setTimeout(function () { resetForNextRound(); }, 2000); } // Reset for next round function resetForNextRound() { gameState = 'selection'; // Stop any ongoing wheel spinning animation if (wheelContainer) { tween.stop(wheelContainer, { rotation: true }); } // Reset spinning state isWheelSpinning = false; // Reset AI element selection aiElement = null; // Reset wheel rotation and element rotations if (wheelContainer) { wheelContainer.rotation = 0; } // Reset all element button rotations to keep them upright for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].rotation = 0; } // Clean up battle elements if (playerBattleElement) { playerBattleElement.destroy(); playerBattleElement = null; } if (aiBattleElement) { aiBattleElement.destroy(); aiBattleElement = null; } if (vsText) { vsText.destroy(); vsText = null; } // Reset instruction text instructionText.setText('Choose your element'); instructionText.tint = 0xcccccc; // Show victory arrows again for (var i = 0; i < victoryArrows.length; i++) { tween(victoryArrows[i], { alpha: 1 }, { duration: 300 }); } // Show selection elements and re-enable only unused ones for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setSelected(false); var elementType = elementButtons[i].elementType; var isUsed = usedPlayerElements.indexOf(elementType) !== -1 || usedAIElements.indexOf(elementType) !== -1; elementButtons[i].setDisabled(isUsed); tween(elementButtons[i], { alpha: 1 }, { duration: 300 }); } // Create victory arrow after elements are visible again LK.setTimeout(function () { var result = checkBattleResult(); if (result === 'player') { // Create victory arrow from player's element to AI's element createVictoryArrow(playerElement, aiElement); } else if (result === 'ai') { // Create victory arrow from AI's element to player's element createVictoryArrow(aiElement, playerElement); } }, 400); // Wait for wheel elements to fade in // Reset battle timer battleTimer = 0; } // Game move handler for hover effects game.move = function (x, y, obj) { if (gameState !== 'selection') { return; } var newHoveredButton = null; // Check which button is under the cursor for (var i = 0; i < elementButtons.length; i++) { var button = elementButtons[i]; // Convert cursor position to wheel container space var localPos = wheelContainer.toLocal({ x: x, y: y }); // Calculate distance from cursor to button center var dx = localPos.x - button.x; var dy = localPos.y - button.y; var distance = Math.sqrt(dx * dx + dy * dy); // Use button's actual width/height to determine hit area (button is anchored at center) var hitRadius = 150; // Approximate radius for the button hit area if (distance < hitRadius) { newHoveredButton = button; break; } } // Handle hover state changes if (hoveredButton !== newHoveredButton) { // Handle leave event for previously hovered button if (hoveredButton && !hoveredButton.isSelected && !hoveredButton.isDisabled) { // Stop any existing scale tweens tween.stop(hoveredButton, { scaleX: true, scaleY: true }); // Scale back to normal tween(hoveredButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150 }); } // Handle hover event for new button if (newHoveredButton && !newHoveredButton.isSelected && !newHoveredButton.isDisabled) { // Stop any existing scale tweens tween.stop(newHoveredButton, { scaleX: true, scaleY: true }); // Scale up on hover tween(newHoveredButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150 }); } hoveredButton = newHoveredButton; } }; // Initialize game createElementButtons(); // Game update loop game.update = function () { // Keep elements upright during wheel spinning if (isWheelSpinning && wheelContainer) { for (var i = 0; i < elementButtons.length; i++) { // Counter-rotate each element button to keep it upright elementButtons[i].rotation = -wheelContainer.rotation; // Keep text positioned toward center elementButtons[i].positionTextTowardCenter(0, 0); } } if (gameState === 'battle' && playerBattleElement && aiBattleElement) { battleTimer++; // Show result after 3 seconds if (battleTimer >= 180) { // 3 seconds at 60 FPS showBattleResult(); } } };
===================================================================
--- original.js
+++ change.js
@@ -448,10 +448,10 @@
if (distFromStart < 100 || distFromEnd < 100) {
continue;
}
var segment = arrowContainer.attachAsset('line', {
- width: 5,
- height: segmentWidth,
+ width: segmentWidth,
+ height: 5,
anchorX: 0.5,
anchorY: 0.5
});
segment.x = x;
@@ -956,11 +956,16 @@
var newHoveredButton = null;
// Check which button is under the cursor
for (var i = 0; i < elementButtons.length; i++) {
var button = elementButtons[i];
+ // Convert cursor position to wheel container space
+ var localPos = wheelContainer.toLocal({
+ x: x,
+ y: y
+ });
// Calculate distance from cursor to button center
- var dx = x - button.x;
- var dy = y - button.y;
+ var dx = localPos.x - button.x;
+ var dy = localPos.y - button.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Use button's actual width/height to determine hit area (button is anchored at center)
var hitRadius = 150; // Approximate radius for the button hit area
if (distance < hitRadius) {
@@ -1011,8 +1016,10 @@
if (isWheelSpinning && wheelContainer) {
for (var i = 0; i < elementButtons.length; i++) {
// Counter-rotate each element button to keep it upright
elementButtons[i].rotation = -wheelContainer.rotation;
+ // Keep text positioned toward center
+ elementButtons[i].positionTextTowardCenter(0, 0);
}
}
if (gameState === 'battle' && playerBattleElement && aiBattleElement) {
battleTimer++;
A hand with its fingers symbolizing gas
Make the background darker (blue)
Make the bacgkground color darker(blue)
a triangle pointing down. In-Game asset. 2d. High contrast. No shadows
This place after a draught
This place in very windy conditions
This place but it's raining
This place but there is an electric storm
a popup frame, retro pixel style, rectangular. In-Game asset. 2d. High contrast. No shadows
A version of this frame that symbolizes that this button has boosted / improved power
a minimalistic pixel button, no text on it, just the buton. White.. In-Game asset. 2d. High contrast. No shadows
A win effect that will be over a round button and that will triger for some seconds after a win happens, scaling in x and y as an effect.. In-Game asset. 2d. High contrast. No shadows
Lose
The frame should be ice related too
The frame should be earth related too
The frame should be water related too
The frame should be wind too
A hand with its fingers symbolizing ash
A hand with its fingers symbolizing sun
A hand with its fingers symbolizing moon
A hand with a piece of leather
A hand with a piece of plastic
A hand with a piece of opaque plastic
A hand with its fingers symbolizing salt
Can you make this picture slightly lighter
Can you make this image lighter please? But not a lot lighter, just a little
A frame that symbolizes that the element inside is penalized, unboosted, has a minus to its effect. It should be shown in the frame, not inside! With some VFX effect
One drop of rain. In-Game asset. 2d. High contrast. No shadows
Yellow / Orange colour
wind. In-Game asset. 2d. High contrast. No shadows
A pixel style magician from Magicka who has an arc around him of elements to be casted (fire, water, ice, rock, etc). In-Game asset. 2d. High contrast. No shadows
Tint the wizard to blue
Make the black border of the start twice thicker
A '?' (question mark) symbol inside
A white shield. In-Game asset. 2d. High contrast. No shadows
background
Music
air
Music
storm
Music
rain
Music
draught
Music
rock
Sound effect
paper
Sound effect
scissors
Sound effect
fire
Sound effect
metal
Sound effect
water
Sound effect
airy
Sound effect
lightning
Sound effect
tree
Sound effect
gun
Sound effect
sponge
Sound effect
smoke
Sound effect
gas
Sound effect
ice
Sound effect
sand
Sound effect
oil
Sound effect
plastic
Sound effect
leather
Sound effect
sun
Sound effect
glass
Sound effect
cloth
Sound effect
ash
Sound effect
fungus
Sound effect
moon
Sound effect
salt
Sound effect
select
Sound effect
spinning
Sound effect
win
Sound effect