User prompt
Add borders to make the balls follow a path the ro gates
User prompt
Make division max 2 and make multiply max 5
User prompt
Every restart gates should randomized both in position and modifiers
User prompt
Add more variety modifiers to the gates
User prompt
If two gates crashes with each other, make the go opposite directions
User prompt
Make the balls go slower and balls can spread after passing the gate
User prompt
On side of the gates, add physical borders
User prompt
Make the bottom gate as wide as the screen
User prompt
Add more gates
User prompt
Make the gates move side to side but they shouldnt overlap with each other
User prompt
Gates shouldnt collide with each other
User prompt
Make the balls go slower and gates can move side to side, add physical borders to the gates. The collecter cup needs to be as big as the screen from side to side
User prompt
Make the gates side by side and add more gates
User prompt
Gates needs to be bigger and the collective cups needs to have a border
User prompt
The gates needs to be positioned randomly
User prompt
As the balls multiply, show it in real time
Code edit (1 edits merged)
Please save this source code
User prompt
Cup Drop Multiplier
Initial prompt
I have cup in my hand and I empty the cup from top of the screen, Balls should be exiting from that cup in flow. I can select where I can empty the cup from top of the screen. As the balls are going down, they are passing from gates that multiplies or divides the number of the balls. At the bottom of the screen make another cup that collects the balls afterwards. Count all the balls
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Ball class
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGfx = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = ballGfx.width / 2;
self.vx = 0;
self.vy = 0;
self.active = true;
self.update = function () {
if (!self.active) return;
// Simple gravity
self.vy += 1.2;
self.x += self.vx;
self.y += self.vy;
};
// Used to mark as collected or destroyed
self.deactivate = function () {
self.active = false;
};
return self;
});
// Bottom cup class (collector)
var CupBottom = Container.expand(function () {
var self = Container.call(this);
var cupGfx = self.attachAsset('cupBottom', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = cupGfx.width;
self.height = cupGfx.height;
return self;
});
// Top cup class (movable)
var CupTop = Container.expand(function () {
var self = Container.call(this);
var cupGfx = self.attachAsset('cupTop', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = cupGfx.width;
self.height = cupGfx.height;
return self;
});
// Gate class (multiplier or divider)
var Gate = Container.expand(function () {
var self = Container.call(this);
self.type = 'mult'; // 'mult' or 'div'
self.value = 2; // e.g. 2x or /2
self.width = 180;
self.height = 40;
self.gfx = null;
self.label = null;
self.init = function (type, value) {
self.type = type;
self.value = value;
if (type === 'mult') {
self.gfx = self.attachAsset('gateMult', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
self.gfx = self.attachAsset('gateDiv', {
anchorX: 0.5,
anchorY: 0.5
});
}
var txt = '';
if (type === 'mult') {
txt = 'x' + value;
} else {
txt = '÷' + value;
}
self.label = new Text2(txt, {
size: 60,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222b3a
});
/****
* Game Code
****/
// Divider gate
// Multiplier gate
// Ball
// Bottom cup (where balls are collected)
// Top cup (where balls are dropped from)
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var BALL_DROP_COUNT = 10;
var BALL_DROP_INTERVAL = 8; // frames between balls
var GATE_CONFIGS = [{
type: 'mult',
value: 2,
y: 900
}, {
type: 'div',
value: 2,
y: 1400
}, {
type: 'mult',
value: 3,
y: 1900
}];
// Game state
var cupTop, cupBottom;
var balls = [];
var gates = [];
var dropping = false;
var dropTimer = 0;
var ballsToDrop = 0;
var scoreTxt, infoTxt;
var collectedCount = 0;
var gatePassed = {}; // ball.id -> {gateIndex: true}
var ballIdCounter = 0;
var dragNode = null;
// Create top cup
cupTop = new CupTop();
cupTop.x = GAME_WIDTH / 2;
cupTop.y = 250;
game.addChild(cupTop);
// Create bottom cup
cupBottom = new CupBottom();
cupBottom.x = GAME_WIDTH / 2;
cupBottom.y = GAME_HEIGHT - 180;
game.addChild(cupBottom);
// Create gates
for (var i = 0; i < GATE_CONFIGS.length; i++) {
var g = new Gate();
g.init(GATE_CONFIGS[i].type, GATE_CONFIGS[i].value);
g.x = GAME_WIDTH / 2;
g.y = GATE_CONFIGS[i].y;
game.addChild(g);
gates.push(g);
}
// Score text (balls collected)
scoreTxt = new Text2('Balls: 0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Info text (instructions)
infoTxt = new Text2('Drag cup & tap to drop balls!', {
size: 60,
fill: 0xFFFFFF
});
infoTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(infoTxt);
// Position GUI elements
scoreTxt.y = 120;
infoTxt.y = 260;
// Helper: spawn a single ball at cupTop
function spawnBall(x, y, vx, vy) {
var b = new Ball();
b.x = x;
b.y = y;
b.vx = vx || 0;
b.vy = vy || 0;
b.id = ++ballIdCounter;
balls.push(b);
game.addChild(b);
gatePassed[b.id] = {};
return b;
}
// Start dropping balls
function startDrop() {
if (dropping) return;
dropping = true;
ballsToDrop = BALL_DROP_COUNT;
dropTimer = 0;
infoTxt.setText('Balls dropping...');
}
// Handle drag/move of cup
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp cup within screen, avoid top left 100x100
var minX = 150 + dragNode.width / 2;
var maxX = GAME_WIDTH - dragNode.width / 2 - 50;
dragNode.x = Math.max(minX, Math.min(maxX, x));
}
}
// Touch/drag events
game.down = function (x, y, obj) {
// If touch is on cupTop, start drag
var local = cupTop.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -cupTop.width / 2 && local.x < cupTop.width / 2 && local.y > -cupTop.height / 2 && local.y < cupTop.height / 2) {
dragNode = cupTop;
}
};
game.move = function (x, y, obj) {
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
// If not dragging, and not dropping, start drop on tap
if (!dropping) {
startDrop();
}
};
// Main update loop
game.update = function () {
// Handle dropping balls
if (dropping && ballsToDrop > 0) {
dropTimer--;
if (dropTimer <= 0) {
// Drop a ball from cupTop center, with small random vx
var vx = (Math.random() - 0.5) * 6;
var b = spawnBall(cupTop.x, cupTop.y + cupTop.height / 2 + 10, vx, 0);
ballsToDrop--;
dropTimer = BALL_DROP_INTERVAL;
}
}
// Update balls
for (var i = balls.length - 1; i >= 0; i--) {
var b = balls[i];
b.update();
// Check for gate collisions
for (var gidx = 0; gidx < gates.length; gidx++) {
var g = gates[gidx];
// Only process if not already passed
if (!gatePassed[b.id][gidx]) {
// Simple AABB collision
if (b.x + b.radius > g.x - g.width / 2 && b.x - b.radius < g.x + g.width / 2 && b.y + b.radius > g.y - g.height / 2 && b.y - b.radius < g.y + g.height / 2) {
// Mark as passed
gatePassed[b.id][gidx] = true;
// Apply gate effect
if (g.type === 'mult') {
// Multiply: spawn (value-1) new balls at same position
for (var m = 1; m < g.value; m++) {
var nb = spawnBall(b.x, b.y, (Math.random() - 0.5) * 8, b.vy * 0.7);
// Copy gatePassed so new balls don't re-trigger previous gates
for (var k in gatePassed[b.id]) {
gatePassed[nb.id][k] = true;
}
}
} else if (g.type === 'div') {
// Divide: only keep 1/value balls, remove others
// Remove this ball if Math.random() > 1/value
if (Math.random() > 1 / g.value) {
b.deactivate();
}
}
}
}
}
// Remove deactivated balls
if (!b.active) {
b.destroy();
balls.splice(i, 1);
continue;
}
// Check for collection in bottom cup
if (b.y + b.radius > cupBottom.y - cupBottom.height / 2 && b.x > cupBottom.x - cupBottom.width / 2 && b.x < cupBottom.x + cupBottom.width / 2 && b.y < cupBottom.y + cupBottom.height / 2) {
// Collected!
collectedCount++;
scoreTxt.setText('Balls: ' + collectedCount);
b.deactivate();
b.destroy();
balls.splice(i, 1);
continue;
}
// Remove balls that fall off screen
if (b.y - b.radius > GAME_HEIGHT + 100) {
b.deactivate();
b.destroy();
balls.splice(i, 1);
continue;
}
}
// End condition: all balls dropped and none left in play
if (dropping && ballsToDrop === 0 && balls.length === 0) {
dropping = false;
infoTxt.setText('Final: ' + collectedCount + ' balls!\nTap to play again');
// Show game over (will reset game)
LK.setScore(collectedCount);
LK.showGameOver();
}
};
// Reset state on game restart
game.on('reset', function () {
// Remove all balls
for (var i = 0; i < balls.length; i++) {
balls[i].destroy();
}
balls = [];
gatePassed = {};
ballIdCounter = 0;
collectedCount = 0;
dropping = false;
ballsToDrop = 0;
dropTimer = 0;
scoreTxt.setText('Balls: 0');
infoTxt.setText('Drag cup & tap to drop balls!');
// Reset cup positions
cupTop.x = GAME_WIDTH / 2;
cupTop.y = 250;
cupBottom.x = GAME_WIDTH / 2;
cupBottom.y = GAME_HEIGHT - 180;
}); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,325 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Ball class
+var Ball = Container.expand(function () {
+ var self = Container.call(this);
+ var ballGfx = self.attachAsset('ball', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = ballGfx.width / 2;
+ self.vx = 0;
+ self.vy = 0;
+ self.active = true;
+ self.update = function () {
+ if (!self.active) return;
+ // Simple gravity
+ self.vy += 1.2;
+ self.x += self.vx;
+ self.y += self.vy;
+ };
+ // Used to mark as collected or destroyed
+ self.deactivate = function () {
+ self.active = false;
+ };
+ return self;
+});
+// Bottom cup class (collector)
+var CupBottom = Container.expand(function () {
+ var self = Container.call(this);
+ var cupGfx = self.attachAsset('cupBottom', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = cupGfx.width;
+ self.height = cupGfx.height;
+ return self;
+});
+// Top cup class (movable)
+var CupTop = Container.expand(function () {
+ var self = Container.call(this);
+ var cupGfx = self.attachAsset('cupTop', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = cupGfx.width;
+ self.height = cupGfx.height;
+ return self;
+});
+// Gate class (multiplier or divider)
+var Gate = Container.expand(function () {
+ var self = Container.call(this);
+ self.type = 'mult'; // 'mult' or 'div'
+ self.value = 2; // e.g. 2x or /2
+ self.width = 180;
+ self.height = 40;
+ self.gfx = null;
+ self.label = null;
+ self.init = function (type, value) {
+ self.type = type;
+ self.value = value;
+ if (type === 'mult') {
+ self.gfx = self.attachAsset('gateMult', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else {
+ self.gfx = self.attachAsset('gateDiv', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ var txt = '';
+ if (type === 'mult') {
+ txt = 'x' + value;
+ } else {
+ txt = '÷' + value;
+ }
+ self.label = new Text2(txt, {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ self.label.anchor.set(0.5, 0.5);
+ self.addChild(self.label);
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x222b3a
+});
+
+/****
+* Game Code
+****/
+// Divider gate
+// Multiplier gate
+// Ball
+// Bottom cup (where balls are collected)
+// Top cup (where balls are dropped from)
+// Game constants
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var BALL_DROP_COUNT = 10;
+var BALL_DROP_INTERVAL = 8; // frames between balls
+var GATE_CONFIGS = [{
+ type: 'mult',
+ value: 2,
+ y: 900
+}, {
+ type: 'div',
+ value: 2,
+ y: 1400
+}, {
+ type: 'mult',
+ value: 3,
+ y: 1900
+}];
+// Game state
+var cupTop, cupBottom;
+var balls = [];
+var gates = [];
+var dropping = false;
+var dropTimer = 0;
+var ballsToDrop = 0;
+var scoreTxt, infoTxt;
+var collectedCount = 0;
+var gatePassed = {}; // ball.id -> {gateIndex: true}
+var ballIdCounter = 0;
+var dragNode = null;
+// Create top cup
+cupTop = new CupTop();
+cupTop.x = GAME_WIDTH / 2;
+cupTop.y = 250;
+game.addChild(cupTop);
+// Create bottom cup
+cupBottom = new CupBottom();
+cupBottom.x = GAME_WIDTH / 2;
+cupBottom.y = GAME_HEIGHT - 180;
+game.addChild(cupBottom);
+// Create gates
+for (var i = 0; i < GATE_CONFIGS.length; i++) {
+ var g = new Gate();
+ g.init(GATE_CONFIGS[i].type, GATE_CONFIGS[i].value);
+ g.x = GAME_WIDTH / 2;
+ g.y = GATE_CONFIGS[i].y;
+ game.addChild(g);
+ gates.push(g);
+}
+// Score text (balls collected)
+scoreTxt = new Text2('Balls: 0', {
+ size: 120,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Info text (instructions)
+infoTxt = new Text2('Drag cup & tap to drop balls!', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+infoTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(infoTxt);
+// Position GUI elements
+scoreTxt.y = 120;
+infoTxt.y = 260;
+// Helper: spawn a single ball at cupTop
+function spawnBall(x, y, vx, vy) {
+ var b = new Ball();
+ b.x = x;
+ b.y = y;
+ b.vx = vx || 0;
+ b.vy = vy || 0;
+ b.id = ++ballIdCounter;
+ balls.push(b);
+ game.addChild(b);
+ gatePassed[b.id] = {};
+ return b;
+}
+// Start dropping balls
+function startDrop() {
+ if (dropping) return;
+ dropping = true;
+ ballsToDrop = BALL_DROP_COUNT;
+ dropTimer = 0;
+ infoTxt.setText('Balls dropping...');
+}
+// Handle drag/move of cup
+function handleMove(x, y, obj) {
+ if (dragNode) {
+ // Clamp cup within screen, avoid top left 100x100
+ var minX = 150 + dragNode.width / 2;
+ var maxX = GAME_WIDTH - dragNode.width / 2 - 50;
+ dragNode.x = Math.max(minX, Math.min(maxX, x));
+ }
+}
+// Touch/drag events
+game.down = function (x, y, obj) {
+ // If touch is on cupTop, start drag
+ var local = cupTop.toLocal(game.toGlobal({
+ x: x,
+ y: y
+ }));
+ if (local.x > -cupTop.width / 2 && local.x < cupTop.width / 2 && local.y > -cupTop.height / 2 && local.y < cupTop.height / 2) {
+ dragNode = cupTop;
+ }
+};
+game.move = function (x, y, obj) {
+ handleMove(x, y, obj);
+};
+game.up = function (x, y, obj) {
+ dragNode = null;
+ // If not dragging, and not dropping, start drop on tap
+ if (!dropping) {
+ startDrop();
+ }
+};
+// Main update loop
+game.update = function () {
+ // Handle dropping balls
+ if (dropping && ballsToDrop > 0) {
+ dropTimer--;
+ if (dropTimer <= 0) {
+ // Drop a ball from cupTop center, with small random vx
+ var vx = (Math.random() - 0.5) * 6;
+ var b = spawnBall(cupTop.x, cupTop.y + cupTop.height / 2 + 10, vx, 0);
+ ballsToDrop--;
+ dropTimer = BALL_DROP_INTERVAL;
+ }
+ }
+ // Update balls
+ for (var i = balls.length - 1; i >= 0; i--) {
+ var b = balls[i];
+ b.update();
+ // Check for gate collisions
+ for (var gidx = 0; gidx < gates.length; gidx++) {
+ var g = gates[gidx];
+ // Only process if not already passed
+ if (!gatePassed[b.id][gidx]) {
+ // Simple AABB collision
+ if (b.x + b.radius > g.x - g.width / 2 && b.x - b.radius < g.x + g.width / 2 && b.y + b.radius > g.y - g.height / 2 && b.y - b.radius < g.y + g.height / 2) {
+ // Mark as passed
+ gatePassed[b.id][gidx] = true;
+ // Apply gate effect
+ if (g.type === 'mult') {
+ // Multiply: spawn (value-1) new balls at same position
+ for (var m = 1; m < g.value; m++) {
+ var nb = spawnBall(b.x, b.y, (Math.random() - 0.5) * 8, b.vy * 0.7);
+ // Copy gatePassed so new balls don't re-trigger previous gates
+ for (var k in gatePassed[b.id]) {
+ gatePassed[nb.id][k] = true;
+ }
+ }
+ } else if (g.type === 'div') {
+ // Divide: only keep 1/value balls, remove others
+ // Remove this ball if Math.random() > 1/value
+ if (Math.random() > 1 / g.value) {
+ b.deactivate();
+ }
+ }
+ }
+ }
+ }
+ // Remove deactivated balls
+ if (!b.active) {
+ b.destroy();
+ balls.splice(i, 1);
+ continue;
+ }
+ // Check for collection in bottom cup
+ if (b.y + b.radius > cupBottom.y - cupBottom.height / 2 && b.x > cupBottom.x - cupBottom.width / 2 && b.x < cupBottom.x + cupBottom.width / 2 && b.y < cupBottom.y + cupBottom.height / 2) {
+ // Collected!
+ collectedCount++;
+ scoreTxt.setText('Balls: ' + collectedCount);
+ b.deactivate();
+ b.destroy();
+ balls.splice(i, 1);
+ continue;
+ }
+ // Remove balls that fall off screen
+ if (b.y - b.radius > GAME_HEIGHT + 100) {
+ b.deactivate();
+ b.destroy();
+ balls.splice(i, 1);
+ continue;
+ }
+ }
+ // End condition: all balls dropped and none left in play
+ if (dropping && ballsToDrop === 0 && balls.length === 0) {
+ dropping = false;
+ infoTxt.setText('Final: ' + collectedCount + ' balls!\nTap to play again');
+ // Show game over (will reset game)
+ LK.setScore(collectedCount);
+ LK.showGameOver();
+ }
+};
+// Reset state on game restart
+game.on('reset', function () {
+ // Remove all balls
+ for (var i = 0; i < balls.length; i++) {
+ balls[i].destroy();
+ }
+ balls = [];
+ gatePassed = {};
+ ballIdCounter = 0;
+ collectedCount = 0;
+ dropping = false;
+ ballsToDrop = 0;
+ dropTimer = 0;
+ scoreTxt.setText('Balls: 0');
+ infoTxt.setText('Drag cup & tap to drop balls!');
+ // Reset cup positions
+ cupTop.x = GAME_WIDTH / 2;
+ cupTop.y = 250;
+ cupBottom.x = GAME_WIDTH / 2;
+ cupBottom.y = GAME_HEIGHT - 180;
});
\ No newline at end of file