User prompt
Move the WASD controls for the square to the right of the grid screen instead of on the bottom.
User prompt
A bit more less.
User prompt
A bit more.
User prompt
That is too big, shrink the grid screen, but not all the way back please.
User prompt
Make the grid screen a bit bigger.
User prompt
Make it so when a brown crystal is added to the pot, the square your able to have 2 downward movements and 1 leftward movements.
User prompt
Make it so when a brown crystal is added to the pot, the square in the grid is able to move down 2 squares, and left 1 square.
User prompt
Change the brown crystals color to actually be brown.
User prompt
Move the grid screen to the right so it's alligned with the alchemy lab screen.
User prompt
Update the hitboxes for the crystals when interacted with my cursor.
User prompt
Move the Alcehmy Lab screen down until the bottom of the screen is touching the bottom of this screen.
User prompt
Move the Alchemy Lab screen down.
User prompt
Rename the Kitchen to an Alchemy Lab.
User prompt
Have it so both screens can be shown at the same time, instead of switching screens.
User prompt
Okay, then make it so I can only move my suqare on this grid when a certian crystal is placed in the pot, like for instance, the brown crystal allows my square to move 2 squares down, and 1 square to the left. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Have it to where you can click and drag the crystals and put them into the pot. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Update the crystal colors. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Some crystals should be brown, red, teal, or purple.
User prompt
Make the shelf and crystals 2 times bigger than they were before. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The shelves and crystals should be higher up, away from the pot.
User prompt
Make 2 shelves, one above another, above the table, stocked with diamond shaped crystals of various colors.
User prompt
The water should show up in the rim of the pot, not the rest of it.
User prompt
Have the pot look like it's holding water.
User prompt
Update the collision detection of the spoon when it hits the pots walls.
User prompt
The hitbox of the spoon and pot should be the outline of the design.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Crystal = Container.expand(function () {
var self = Container.call(this);
var crystal = self.attachAsset('crystal', {
anchorX: 0.5,
anchorY: 0.5
});
crystal.rotation = Math.PI / 4; // 45 degrees to make diamond shape
// Create larger invisible hitbox for better touch interaction
var hitbox = self.attachAsset('crystal', {
anchorX: 0.5,
anchorY: 0.5,
width: 180,
height: 180
});
hitbox.alpha = 0; // Make invisible
hitbox.interactive = true; // Ensure it can receive touch events
self.sparkleTimer = 0;
self.isDragging = false;
self.originalX = 0;
self.originalY = 0;
self.isInPot = false;
self.lastIsInPot = false;
self.down = function (x, y, obj) {
self.isDragging = true;
draggedCrystal = self;
self.originalX = self.x;
self.originalY = self.y;
// Bring crystal to front and scale it up slightly
tween(self, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.9
}, {
duration: 200,
easing: tween.easeOut
});
// Add visual feedback on touch
tween(crystal, {
tint: 0xFFFFFF
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
self.isDragging = false;
draggedCrystal = null;
// Restore original tint when releasing
tween(crystal, {
tint: crystal.originalTint || 0xFFFFFF
}, {
duration: 100,
easing: tween.easeOut
});
// Check if crystal is dropped in pot
if (self.isInPot) {
// Get crystal color from tint
var crystalColor = self.children[0].tint;
// Add to crystals in pot tracking
crystalsInPot.push(crystalColor);
// Update available movements based on crystal color
if (crystalColor === 0x8B4513) {
// Brown crystal
availableMovements.push({
type: 'brown',
downSteps: 2,
leftSteps: 1
});
} else if (crystalColor === 0xff0000) {
// Red crystal
availableMovements.push({
type: 'red',
upSteps: 1,
rightSteps: 3
});
} else if (crystalColor === 0x008080) {
// Teal crystal
availableMovements.push({
type: 'teal',
leftSteps: 2,
upSteps: 2
});
} else if (crystalColor === 0x800080) {
// Purple crystal
availableMovements.push({
type: 'purple',
rightSteps: 1,
downSteps: 1
});
}
// Crystal successfully added to pot - destroy it with effect
tween(self, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
// Remove from crystals array
for (var i = crystals.length - 1; i >= 0; i--) {
if (crystals[i] === self) {
crystals.splice(i, 1);
break;
}
}
}
});
} else {
// Return to original position if not dropped in pot
tween(self, {
x: self.originalX,
y: self.originalY,
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 400,
easing: tween.easeOut
});
}
};
self.update = function () {
// Check if crystal is in pot
var potCenterX = 2048 / 2;
var potCenterY = 2150;
var potOuterRadius = 300;
var potHeightRadius = 250;
self.lastIsInPot = self.isInPot;
// Check if crystal is inside pot area
var normalizedX = (self.x - potCenterX) / (potOuterRadius - 60);
var normalizedY = (self.y - potCenterY) / (potHeightRadius - 60);
var ellipticalDistance = Math.sqrt(normalizedX * normalizedX + normalizedY * normalizedY);
self.isInPot = ellipticalDistance <= 1.0;
// Visual feedback when entering pot
if (!self.lastIsInPot && self.isInPot && self.isDragging) {
// Just entered pot - add glow effect
tween(crystal, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut
});
} else if (self.lastIsInPot && !self.isInPot && self.isDragging) {
// Just left pot - restore original color
tween(crystal, {
tint: crystal.originalTint || 0xFFFFFF
}, {
duration: 200,
easing: tween.easeOut
});
}
self.sparkleTimer++;
if (self.sparkleTimer >= 120) {
// Sparkle every 2 seconds
self.sparkleTimer = 0;
tween(crystal, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.7
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(crystal, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
};
return self;
});
var GridCell = Container.expand(function () {
var self = Container.call(this);
var border = self.attachAsset('gridBorder', {
anchorX: 0.5,
anchorY: 0.5
});
var cell = self.attachAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerBorder = self.attachAsset('playerBorder', {
anchorX: 0.5,
anchorY: 0.5
});
var playerInner = self.attachAsset('playerInner', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 5; // Center position (0-indexed)
self.gridY = 5; // Center position (0-indexed)
self.isFlashing = false;
self.flashTimer = 0;
self.update = function () {
// Handle flashing animation
self.flashTimer++;
if (self.flashTimer >= 30) {
// Flash every 30 frames (0.5 seconds at 60fps)
self.flashTimer = 0;
self.isFlashing = !self.isFlashing;
playerBorder.alpha = self.isFlashing ? 0.3 : 1.0;
playerInner.alpha = self.isFlashing ? 0.3 : 1.0;
}
};
self.moveToGridPosition = function () {
var cellSize = 164;
var gridStartX = 2048 / 2 - 11 * cellSize / 2 + cellSize / 2;
var gridStartY = 2732 / 2 - 11 * cellSize / 2 + cellSize / 2;
self.x = gridStartX + self.gridX * cellSize;
self.y = gridStartY + self.gridY * cellSize;
};
return self;
});
var Pot = Container.expand(function () {
var self = Container.call(this);
var potBase = self.attachAsset('pot', {
anchorX: 0.5,
anchorY: 0.5
});
var water = self.attachAsset('water', {
anchorX: 0.5,
anchorY: 0.5,
width: 680,
// Match rim width (700 - 20 for border effect)
height: 120 // Much thinner to fit only in rim area
});
water.y = -200; // Position at same level as rim
water.alpha = 0.8; // Make water semi-transparent
var rim = self.attachAsset('potRim', {
anchorX: 0.5,
anchorY: 0.5
});
rim.y = -200;
return self;
});
var Shelf = Container.expand(function () {
var self = Container.call(this);
var shelfBoard = self.attachAsset('shelf', {
anchorX: 0.5,
anchorY: 0.5
});
var leftSupport = self.attachAsset('shelfSupport', {
anchorX: 0.5,
anchorY: 0
});
leftSupport.x = -700;
leftSupport.y = 40;
var rightSupport = self.attachAsset('shelfSupport', {
anchorX: 0.5,
anchorY: 0
});
rightSupport.x = 700;
rightSupport.y = 40;
return self;
});
var Spoon = Container.expand(function () {
var self = Container.call(this);
var handle = self.attachAsset('spoonHandle', {
anchorX: 0.5,
anchorY: 1.0
});
var bowl = self.attachAsset('spoonBowl', {
anchorX: 0.5,
anchorY: 0.5
});
bowl.y = -360;
self.isDragging = false;
self.isInPot = false;
self.lastIsInPot = false;
self.isCollidingWithPot = false;
self.lastIsCollidingWithPot = false;
self.isStirring = false;
self.stirAngle = 0;
self.originalBowlTint = bowl.tint;
self.down = function (x, y, obj) {
self.isDragging = true;
draggedSpoon = self;
// Flip spoon upside down when dragging starts
tween(self, {
rotation: Math.PI
}, {
duration: 200,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
self.isDragging = false;
self.isStirring = false;
draggedSpoon = null;
// Flip spoon back to normal when drag ends
tween(self, {
rotation: 0
}, {
duration: 200,
easing: tween.easeOut
});
};
self.update = function () {
// Check if spoon bowl is in pot
var potCenterX = 2048 / 2;
var potCenterY = 2150;
var bowlWorldX = self.x;
var bowlWorldY = self.y - 360; // Bowl offset
var handleWorldX = self.x;
var handleWorldY = self.y;
// Update collision detection state
self.lastIsCollidingWithPot = self.isCollidingWithPot;
// Collision detection - check both spoon bowl and handle against pot outline
var potOuterRadius = 300; // Pot ellipse outer boundary (width/2 = 600/2)
var potHeightRadius = 250; // Pot ellipse height boundary (height/2 = 500/2)
var potLineThickness = 10; // Thickness of the pot outline
// Check bowl collision with pot outline
var bowlNormalizedX = (bowlWorldX - potCenterX) / potOuterRadius;
var bowlNormalizedY = (bowlWorldY - potCenterY) / potHeightRadius;
var bowlEllipticalDistance = Math.sqrt(bowlNormalizedX * bowlNormalizedX + bowlNormalizedY * bowlNormalizedY);
// Account for bowl size (60 pixel radius = 120/2)
var bowlRadiusFactor = 60 / Math.min(potOuterRadius, potHeightRadius);
var bowlInnerBoundary = Math.max(0, 1.0 - potLineThickness / Math.min(potOuterRadius, potHeightRadius) - bowlRadiusFactor);
var bowlOuterBoundary = 1.0 + bowlRadiusFactor;
var bowlCollidingWithPot = bowlEllipticalDistance >= bowlInnerBoundary && bowlEllipticalDistance <= bowlOuterBoundary;
// Check handle collision with pot outline (sample points along handle)
var handleCollidingWithPot = false;
for (var i = 0; i <= 10; i++) {
var handleSampleY = handleWorldY - i * 36; // Sample along 360 pixel handle length
var handleNormalizedX = (handleWorldX - potCenterX) / potOuterRadius;
var handleNormalizedY = (handleSampleY - potCenterY) / potHeightRadius;
var handleEllipticalDistance = Math.sqrt(handleNormalizedX * handleNormalizedX + handleNormalizedY * handleNormalizedY);
// Account for handle width (20 pixel radius = 40/2)
var handleRadiusFactor = 20 / Math.min(potOuterRadius, potHeightRadius);
var handleInnerBoundary = Math.max(0, 1.0 - potLineThickness / Math.min(potOuterRadius, potHeightRadius) - handleRadiusFactor);
var handleOuterBoundary = 1.0 + handleRadiusFactor;
if (handleEllipticalDistance >= handleInnerBoundary && handleEllipticalDistance <= handleOuterBoundary) {
handleCollidingWithPot = true;
break;
}
}
self.isCollidingWithPot = bowlCollidingWithPot || handleCollidingWithPot;
// Update pot state - check if bowl is inside the pot ellipse
self.lastIsInPot = self.isInPot;
var inPotNormalizedX = (bowlWorldX - potCenterX) / (potOuterRadius - 60); // Account for bowl size
var inPotNormalizedY = (bowlWorldY - potCenterY) / (potHeightRadius - 60); // Account for bowl size
var inPotEllipticalDistance = Math.sqrt(inPotNormalizedX * inPotNormalizedX + inPotNormalizedY * inPotNormalizedY);
self.isInPot = inPotEllipticalDistance <= 1.0; // Inside pot for stirring
// Handle collision feedback
if (!self.lastIsCollidingWithPot && self.isCollidingWithPot) {
// Just started colliding with pot edge
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
// Visual feedback when entering/leaving pot
if (!self.lastIsInPot && self.isInPot) {
// Just entered pot - tint spoon darker
tween(bowl, {
tint: 0x4A2C17
}, {
duration: 300
});
tween(handle, {
tint: 0x4A2C17
}, {
duration: 300
});
} else if (self.lastIsInPot && !self.isInPot) {
// Just left pot - restore original color
tween(bowl, {
tint: 0x654321
}, {
duration: 300
});
tween(handle, {
tint: 0x654321
}, {
duration: 300
});
}
// Handle depth when in pot
if (self.isInPot) {
// Make bowl appear to dip into pot using elliptical distance
var depthFactor = Math.max(0, 1 - inPotEllipticalDistance);
bowl.y = -360 + depthFactor * 60; // Bowl sinks up to 60 pixels
// Adjust handle visibility based on depth
handle.alpha = Math.max(0.3, 1 - depthFactor * 0.7);
} else {
// Restore normal position when outside pot
bowl.y = -360;
handle.alpha = 1.0;
}
};
return self;
});
var Table = Container.expand(function () {
var self = Container.call(this);
var tabletop = self.attachAsset('table', {
anchorX: 0.5,
anchorY: 0.5
});
var leg1 = self.attachAsset('tableLeg1', {
anchorX: 0.5,
anchorY: 0
});
leg1.x = -500;
leg1.y = 40;
var leg2 = self.attachAsset('tableLeg2', {
anchorX: 0.5,
anchorY: 0
});
leg2.x = 500;
leg2.y = 40;
var leg3 = self.attachAsset('tableLeg3', {
anchorX: 0.5,
anchorY: 0
});
leg3.x = -500;
leg3.y = 40;
var leg4 = self.attachAsset('tableLeg4', {
anchorX: 0.5,
anchorY: 0
});
leg4.x = 500;
leg4.y = 40;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
var gridSize = 11;
var cellSize = 164;
var gridCells = [];
var player;
// Game state management
var gridScreen;
var cursorScreen;
// Crystal movement tracking
var crystalsInPot = [];
var availableMovements = [];
// Create screen containers positioned side by side
gridScreen = new Container();
cursorScreen = new Container();
// Position grid screen on the right half aligned with alchemy lab screen
gridScreen.x = 512; // Shift right by quarter screen width to match cursor screen
gridScreen.scaleX = 0.5; // Scale down to fit in half screen
gridScreen.scaleY = 0.5;
// Position cursor screen on the right half
cursorScreen.x = 512; // Shift right by quarter screen width
cursorScreen.y = 1366; // Move down to touch bottom of screen
cursorScreen.scaleX = 0.5; // Scale down to fit in half screen
cursorScreen.scaleY = 0.5;
game.addChild(gridScreen);
game.addChild(cursorScreen);
// Create the grid
var gridStartX = 2048 / 2 - gridSize * cellSize / 2 + cellSize / 2;
var gridStartY = 2732 / 2 - gridSize * cellSize / 2 + cellSize / 2;
for (var row = 0; row < gridSize; row++) {
gridCells[row] = [];
for (var col = 0; col < gridSize; col++) {
var cell = new GridCell();
cell.x = gridStartX + col * cellSize;
cell.y = gridStartY + row * cellSize;
gridCells[row][col] = cell;
gridScreen.addChild(cell);
}
}
// Add text labels to specific grid cells
var voidLabel = new Text2('Void', {
size: 40,
fill: 0xFFFFFF
});
voidLabel.anchor.set(0.5, 0.5);
voidLabel.x = gridStartX + 5 * cellSize; // Center column (5)
voidLabel.y = gridStartY + 5 * cellSize; // Center row (5)
gridScreen.addChild(voidLabel);
var earthLabel = new Text2('Earth', {
size: 40,
fill: 0xFFFFFF
});
earthLabel.anchor.set(0.5, 0.5);
earthLabel.x = gridStartX + 3 * cellSize; // 2 squares left from center (5-2=3)
earthLabel.y = gridStartY + 7 * cellSize; // 2 squares down from center (5+2=7)
gridScreen.addChild(earthLabel);
// Create player
player = gridScreen.addChild(new Player());
player.moveToGridPosition();
// Input handling for WASD keys
var keyStates = {
w: false,
a: false,
s: false,
d: false
};
var lastKeyStates = {
w: false,
a: false,
s: false,
d: false
};
// Simulate keyboard input through touch controls
var controlButtons = [];
var buttonSize = 120;
var buttonSpacing = 140;
// Create virtual WASD buttons
var wButton = gridScreen.addChild(LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
width: buttonSize,
height: buttonSize
}));
wButton.x = 2048 - 200;
wButton.y = 2732 - 400;
var aButton = gridScreen.addChild(LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
width: buttonSize,
height: buttonSize
}));
aButton.x = 2048 - 340;
aButton.y = 2732 - 260;
var sButton = gridScreen.addChild(LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
width: buttonSize,
height: buttonSize
}));
sButton.x = 2048 - 200;
sButton.y = 2732 - 260;
var dButton = gridScreen.addChild(LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
width: buttonSize,
height: buttonSize
}));
dButton.x = 2048 - 60;
dButton.y = 2732 - 260;
// Add labels to buttons
var wLabel = new Text2('W', {
size: 60,
fill: 0xFFFFFF
});
wLabel.anchor.set(0.5, 0.5);
wLabel.x = wButton.x;
wLabel.y = wButton.y;
gridScreen.addChild(wLabel);
// Add movement status display
var movementStatusText = new Text2('No movements available\nPlace crystals in pot!', {
size: 40,
fill: 0xFFFFFF
});
movementStatusText.anchor.set(0.5, 0.5);
movementStatusText.x = 300;
movementStatusText.y = 300;
gridScreen.addChild(movementStatusText);
var aLabel = new Text2('A', {
size: 60,
fill: 0xFFFFFF
});
aLabel.anchor.set(0.5, 0.5);
aLabel.x = aButton.x;
aLabel.y = aButton.y;
gridScreen.addChild(aLabel);
var sLabel = new Text2('S', {
size: 60,
fill: 0xFFFFFF
});
sLabel.anchor.set(0.5, 0.5);
sLabel.x = sButton.x;
sLabel.y = sButton.y;
gridScreen.addChild(sLabel);
var dLabel = new Text2('D', {
size: 60,
fill: 0xFFFFFF
});
dLabel.anchor.set(0.5, 0.5);
dLabel.x = dButton.x;
dLabel.y = dButton.y;
gridScreen.addChild(dLabel);
// Button event handlers
wButton.down = function () {
keyStates.w = true;
};
wButton.up = function () {
keyStates.w = false;
};
aButton.down = function () {
keyStates.a = true;
};
aButton.up = function () {
keyStates.a = false;
};
sButton.down = function () {
keyStates.s = true;
};
sButton.up = function () {
keyStates.s = false;
};
dButton.down = function () {
keyStates.d = true;
};
dButton.up = function () {
keyStates.d = false;
};
// Create white background for cursor screen
var whiteBackground = cursorScreen.addChild(LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0,
width: 2048,
height: 2732
}));
whiteBackground.tint = 0xFFFFFF;
whiteBackground.x = 0;
whiteBackground.y = 0;
// Create cursor screen content
var cursorTitle = new Text2('Alchemy Lab', {
size: 80,
fill: 0x000000
});
cursorTitle.anchor.set(0.5, 0.5);
cursorTitle.x = 2048 / 2;
cursorTitle.y = 400;
cursorScreen.addChild(cursorTitle);
// Create table
var table = cursorScreen.addChild(new Table());
table.x = 2048 / 2;
table.y = 2400;
// Create pot
var pot = cursorScreen.addChild(new Pot());
pot.x = 2048 / 2;
pot.y = 2150;
// Create spoon
var spoon = cursorScreen.addChild(new Spoon());
spoon.x = 2048 / 2 + 300;
spoon.y = 2360; // Position on table surface (table.y - table.height/2 = 2400 - 40)
var draggedSpoon = null;
var draggedCrystal = null;
// Create shelves above the table
var topShelf = cursorScreen.addChild(new Shelf());
topShelf.x = 2048 / 2;
topShelf.y = 1200; // Much higher up, away from pot
var bottomShelf = cursorScreen.addChild(new Shelf());
bottomShelf.x = 2048 / 2;
bottomShelf.y = 1400; // Higher up, maintaining spacing from top shelf
// Create crystals for top shelf
var crystalColors = [0x8B4513, 0xff0000, 0x008080, 0x800080, 0x4B0082, 0x654321]; // brown, red, teal, purple, indigo, dark brown
var crystals = [];
// Top shelf crystals
for (var i = 0; i < 6; i++) {
var crystal = cursorScreen.addChild(new Crystal());
crystal.x = topShelf.x - 500 + i * 200;
crystal.y = topShelf.y - 60;
var crystalColor = crystalColors[i % crystalColors.length];
crystal.children[0].tint = crystalColor;
crystal.children[0].originalTint = crystalColor;
crystal.originalX = crystal.x;
crystal.originalY = crystal.y;
crystals.push(crystal);
}
// Bottom shelf crystals
for (var i = 0; i < 6; i++) {
var crystal = cursorScreen.addChild(new Crystal());
crystal.x = bottomShelf.x - 500 + i * 200;
crystal.y = bottomShelf.y - 60;
var crystalColor = crystalColors[(i + 3) % crystalColors.length];
crystal.children[0].tint = crystalColor;
crystal.children[0].originalTint = crystalColor;
crystal.originalX = crystal.x;
crystal.originalY = crystal.y;
crystals.push(crystal);
}
// Create title for dual screen view
var dualScreenTitle = new Text2('Grid & Kitchen View', {
size: 60,
fill: 0xFFFFFF
});
dualScreenTitle.anchor.set(0.5, 0.5);
dualScreenTitle.x = 2048 / 2;
dualScreenTitle.y = 150;
game.addChild(dualScreenTitle);
// Cursor screen interaction
cursorScreen.move = function (x, y, obj) {
// Handle crystal dragging - convert coordinates for scaled/positioned screen
var localPos = cursorScreen.toLocal({
x: x,
y: y
});
if (draggedCrystal) {
draggedCrystal.x = localPos.x;
draggedCrystal.y = localPos.y;
}
if (draggedSpoon) {
var potCenterX = 2048 / 2;
var potCenterY = 2150;
var potOuterRadius = 300; // Pot ellipse outer boundary (width/2 = 600/2)
var potHeightRadius = 250; // Pot ellipse height boundary (height/2 = 500/2)
var potWallThickness = 20; // Thickness of pot wall for collision
// Position spoon hanging from cursor when dragging (bowl at cursor position)
var proposedX = x;
var proposedY = y + 360; // Offset so bowl hangs at cursor position
// Function to check if spoon outline intersects with pot wall
var checkSpoonWallCollision = function checkSpoonWallCollision(spoonX, spoonY) {
// Check bowl collision with pot wall
var bowlX = spoonX;
var bowlY = spoonY - 360;
var bowlNormalizedX = (bowlX - potCenterX) / potOuterRadius;
var bowlNormalizedY = (bowlY - potCenterY) / potHeightRadius;
var bowlEllipticalDistance = Math.sqrt(bowlNormalizedX * bowlNormalizedX + bowlNormalizedY * bowlNormalizedY);
// Bowl radius factor for collision detection
var bowlRadius = 60; // Half of bowl width (120/2)
var bowlRadiusFactor = bowlRadius / Math.min(potOuterRadius, potHeightRadius);
// Define pot wall boundaries - spoon can't pass through this zone
var wallInnerBoundary = 1.0 - potWallThickness / Math.min(potOuterRadius, potHeightRadius);
var wallOuterBoundary = 1.0 + potWallThickness / Math.min(potOuterRadius, potHeightRadius);
// Check if bowl would intersect with pot wall
var bowlCollision = bowlEllipticalDistance + bowlRadiusFactor >= wallInnerBoundary && bowlEllipticalDistance - bowlRadiusFactor <= wallOuterBoundary;
if (bowlCollision) {
return true;
}
// Check handle collision with pot wall (sample multiple points along handle)
for (var i = 0; i <= 10; i++) {
var handleSampleY = spoonY - i * 36; // Sample along 360 pixel handle length
var handleNormalizedX = (spoonX - potCenterX) / potOuterRadius;
var handleNormalizedY = (handleSampleY - potCenterY) / potHeightRadius;
var handleEllipticalDistance = Math.sqrt(handleNormalizedX * handleNormalizedX + handleNormalizedY * handleNormalizedY);
// Handle radius factor for collision detection
var handleRadius = 20; // Half of handle width (40/2)
var handleRadiusFactor = handleRadius / Math.min(potOuterRadius, potHeightRadius);
// Check if this handle segment would intersect with pot wall
var handleCollision = handleEllipticalDistance + handleRadiusFactor >= wallInnerBoundary && handleEllipticalDistance - handleRadiusFactor <= wallOuterBoundary;
if (handleCollision) {
return true;
}
}
return false;
};
// Check current position and proposed new position
var currentlyCollidingWithWall = checkSpoonWallCollision(draggedSpoon.x, draggedSpoon.y);
var wouldCollideWithWall = checkSpoonWallCollision(proposedX, proposedY);
// Collision resolution logic
if (!currentlyCollidingWithWall && wouldCollideWithWall) {
// Moving from free space into pot wall - block the movement
return; // Don't update spoon position
} else if (currentlyCollidingWithWall && wouldCollideWithWall) {
// Currently stuck in wall and trying to move to another wall position
// Try to push spoon away from pot center to resolve collision
var dirX = proposedX - potCenterX;
var dirY = proposedY - 360 - potCenterY; // Use bowl position for direction calculation
var dirLength = Math.sqrt(dirX * dirX + dirY * dirY);
if (dirLength > 0) {
// Normalize direction vector
dirX /= dirLength;
dirY /= dirLength;
// Push spoon to safe distance outside pot wall
var safeDistance = potOuterRadius + 80; // Add safety margin
proposedX = potCenterX + dirX * safeDistance;
proposedY = potCenterY + dirY * safeDistance + 360; // Add back bowl offset
}
}
// Update spoon position with validated coordinates
draggedSpoon.x = proposedX;
draggedSpoon.y = proposedY;
// Enhanced stirring mechanics - only when spoon is in pot
// Manual stirring when in pot and moving
if (draggedSpoon.isInPot && draggedSpoon.isDragging) {
// Calculate angle for stirring effect but keep the flipped orientation
var angle = Math.atan2(y - potCenterY, x - potCenterX);
draggedSpoon.rotation = Math.PI + angle + Math.PI / 4;
// Create stirring particles effect using tween
if (LK.ticks % 10 === 0) {
// Every 10 frames
// Animate pot slightly to show stirring effect
tween(pot, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pot, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
// Create water ripple effect during stirring
if (LK.ticks % 15 === 0) {
// Get water element from pot (second child after potBase)
var potWater = pot.children[1];
if (potWater) {
tween(potWater, {
scaleX: 1.1,
scaleY: 0.95
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(potWater, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
}
}
}
};
// Initialize screen visibility - both screens always visible
gridScreen.visible = true;
cursorScreen.visible = true;
function movePlayer(direction) {
// Check if we have any available movements
if (availableMovements.length === 0) {
return; // No movement allowed without crystals in pot
}
var newX = player.gridX;
var newY = player.gridY;
var movementUsed = null;
// Try to find a movement that matches the direction
for (var i = 0; i < availableMovements.length; i++) {
var movement = availableMovements[i];
var tempX = player.gridX;
var tempY = player.gridY;
switch (direction) {
case 'w':
// Up movement
if (movement.upSteps) {
tempY = Math.max(0, player.gridY - movement.upSteps);
if (movement.leftSteps) {
tempX = Math.max(0, player.gridX - movement.leftSteps);
} else if (movement.rightSteps) {
tempX = Math.min(gridSize - 1, player.gridX + movement.rightSteps);
}
movementUsed = i;
}
break;
case 's':
// Down movement
if (movement.downSteps) {
tempY = Math.min(gridSize - 1, player.gridY + movement.downSteps);
if (movement.leftSteps) {
tempX = Math.max(0, player.gridX - movement.leftSteps);
} else if (movement.rightSteps) {
tempX = Math.min(gridSize - 1, player.gridX + movement.rightSteps);
}
movementUsed = i;
}
break;
case 'a':
// Left movement
if (movement.leftSteps && !movement.upSteps && !movement.downSteps) {
tempX = Math.max(0, player.gridX - movement.leftSteps);
movementUsed = i;
}
break;
case 'd':
// Right movement
if (movement.rightSteps && !movement.upSteps && !movement.downSteps) {
tempX = Math.min(gridSize - 1, player.gridX + movement.rightSteps);
movementUsed = i;
}
break;
}
// If we found a valid movement, apply it
if (movementUsed !== null && (tempX !== player.gridX || tempY !== player.gridY)) {
newX = tempX;
newY = tempY;
// Remove the used movement
availableMovements.splice(movementUsed, 1);
break;
}
}
// Only move if position changed
if (newX !== player.gridX || newY !== player.gridY) {
player.gridX = newX;
player.gridY = newY;
player.moveToGridPosition();
}
}
game.update = function () {
// Update movement status display
var statusText = '';
if (availableMovements.length === 0) {
statusText = 'No movements available\nPlace crystals in pot!';
} else {
statusText = 'Available movements: ' + availableMovements.length + '\n';
for (var i = 0; i < availableMovements.length; i++) {
var mov = availableMovements[i];
statusText += mov.type + ' crystal: ';
if (mov.upSteps) statusText += mov.upSteps + ' up ';
if (mov.downSteps) statusText += mov.downSteps + ' down ';
if (mov.leftSteps) statusText += mov.leftSteps + ' left ';
if (mov.rightSteps) statusText += mov.rightSteps + ' right ';
statusText += '\n';
}
}
movementStatusText.setText(statusText);
// Handle grid controls
// Check for key press transitions (just pressed)
if (!lastKeyStates.w && keyStates.w) {
movePlayer('w');
}
if (!lastKeyStates.a && keyStates.a) {
movePlayer('a');
}
if (!lastKeyStates.s && keyStates.s) {
movePlayer('s');
}
if (!lastKeyStates.d && keyStates.d) {
movePlayer('d');
}
// Update last key states
lastKeyStates.w = keyStates.w;
lastKeyStates.a = keyStates.a;
lastKeyStates.s = keyStates.s;
lastKeyStates.d = keyStates.d;
}; ===================================================================
--- original.js
+++ change.js
@@ -477,10 +477,10 @@
var availableMovements = [];
// Create screen containers positioned side by side
gridScreen = new Container();
cursorScreen = new Container();
-// Position grid screen on the left half
-gridScreen.x = -512; // Shift left by quarter screen width
+// Position grid screen on the right half aligned with alchemy lab screen
+gridScreen.x = 512; // Shift right by quarter screen width to match cursor screen
gridScreen.scaleX = 0.5; // Scale down to fit in half screen
gridScreen.scaleY = 0.5;
// Position cursor screen on the right half
cursorScreen.x = 512; // Shift right by quarter screen width