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;
// Add border using a slightly larger box behind
var border = self.attachAsset('cupBottom', {
anchorX: 0.5,
anchorY: 0.5,
width: cupGfx.width + 16,
height: cupGfx.height + 16,
color: 0x222222
});
self.setChildIndex(border, 0);
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;
// Add border using a slightly larger box behind
var border = self.attachAsset('cupTop', {
anchorX: 0.5,
anchorY: 0.5,
width: cupGfx.width + 12,
height: cupGfx.height + 12,
color: 0x222222
});
self.setChildIndex(border, 0);
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
// Randomize gate positions and types
var GATE_COUNT = 3;
var GATE_MIN_Y = 700;
var GATE_MAX_Y = GAME_HEIGHT - 600;
var GATE_SPACING_MIN = 400;
var GATE_SPACING_MAX = 700;
var GATE_TYPES = [{
type: 'mult',
values: [2, 3]
}, {
type: 'div',
values: [2, 3]
}];
var GATE_CONFIGS = [];
var lastY = GATE_MIN_Y - 200;
for (var i = 0; i < GATE_COUNT; i++) {
// Randomly pick type
var typeIdx = Math.floor(Math.random() * GATE_TYPES.length);
var typeObj = GATE_TYPES[typeIdx];
var value = typeObj.values[Math.floor(Math.random() * typeObj.values.length)];
// Randomly space Y
var spacing = GATE_SPACING_MIN + Math.floor(Math.random() * (GATE_SPACING_MAX - GATE_SPACING_MIN));
var y = lastY + spacing;
if (y > GATE_MAX_Y) y = GATE_MAX_Y;
lastY = y;
GATE_CONFIGS.push({
type: typeObj.type,
value: value,
y: y
});
}
// 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
// Show current number of balls in play (real time, not just collected)
scoreTxt.setText('Balls: ' + (collectedCount + balls.length));
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;
// At end, show only collected balls as final score
scoreTxt.setText('Balls: ' + collectedCount);
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
@@ -38,8 +38,17 @@
anchorY: 0.5
});
self.width = cupGfx.width;
self.height = cupGfx.height;
+ // Add border using a slightly larger box behind
+ var border = self.attachAsset('cupBottom', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: cupGfx.width + 16,
+ height: cupGfx.height + 16,
+ color: 0x222222
+ });
+ self.setChildIndex(border, 0);
return self;
});
// Top cup class (movable)
var CupTop = Container.expand(function () {
@@ -49,8 +58,17 @@
anchorY: 0.5
});
self.width = cupGfx.width;
self.height = cupGfx.height;
+ // Add border using a slightly larger box behind
+ var border = self.attachAsset('cupTop', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: cupGfx.width + 12,
+ height: cupGfx.height + 12,
+ color: 0x222222
+ });
+ self.setChildIndex(border, 0);
return self;
});
// Gate class (multiplier or divider)
var Gate = Container.expand(function () {