User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 199
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 198
Code edit (1 edits merged)
Please save this source code
User prompt
Chain Bot Bouncer
Initial prompt
The player controls a robot character. The robot can only move horizontally (left and right). The robot can fire a chain (grappling hook-like weapon) in any direction, based on mouse position (360° aiming). The firing is triggered with the left mouse button. A line indicator will show the direction in which the robot is aiming.There are always 2 bouncing balls: one red and one green. Balls will: Continuously bounce off all surfaces, including: Screen edges Obstacles The player character Each other Balls shrink each time they collide with a chain. When a chain hits a ball, the ball reduces in size but doesn’t disappear immediately.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Ball class: bounces, shrinks on hit, rebounds off everything var Ball = Container.expand(function () { var self = Container.call(this); // Ball type: 'red' or 'green' self.type = 'red'; self.radius = 90; // initial radius self.minRadius = 40; // minimum radius after shrinking self.shrinkAmount = 18; // how much to shrink per hit // Attach asset self.asset = null; self.setType = function (type) { self.type = type; if (self.asset) self.removeChild(self.asset); var assetId = type === 'red' ? 'ballRed' : 'ballGreen'; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5, width: self.radius * 2, height: self.radius * 2 }); }; // Set initial type self.setType(self.type); // Physics self.vx = 0; self.vy = 0; self.bounce = 0.98; // energy loss on bounce self.gravity = 1.2; // For collision detection self.getRadius = function () { return self.radius; }; // Shrink ball self.shrink = function () { if (self.radius > self.minRadius) { self.radius -= self.shrinkAmount; if (self.radius < self.minRadius) self.radius = self.minRadius; // Animate shrink tween(self.asset, { width: self.radius * 2, height: self.radius * 2 }, { duration: 180, easing: tween.easeOut }); } }; // Update per frame self.update = function () { // Move self.x += self.vx; self.y += self.vy; // Gravity self.vy += self.gravity; // Bounce off walls if (self.x - self.radius < 0) { self.x = self.radius; self.vx = -self.vx * self.bounce; } if (self.x + self.radius > 2048) { self.x = 2048 - self.radius; self.vx = -self.vx * self.bounce; } // Bounce off floor/ceiling if (self.y - self.radius < 0) { self.y = self.radius; self.vy = -self.vy * self.bounce; } if (self.y + self.radius > 2732) { self.y = 2732 - self.radius; self.vy = -self.vy * self.bounce; } }; return self; }); // Chain class: fires in direction, stops at collision or edge var Chain = Container.expand(function () { var self = Container.call(this); // Chain is a series of segments self.segments = []; self.segmentLength = 64; self.maxSegments = 32; self.dirX = 0; self.dirY = 0; self.originX = 0; self.originY = 0; self.active = true; // For collision self.getTip = function () { if (self.segments.length === 0) return { x: self.originX, y: self.originY }; var last = self.segments[self.segments.length - 1]; return { x: last.x, y: last.y }; }; // Initialize chain self.fire = function (originX, originY, dirX, dirY) { self.originX = originX; self.originY = originY; self.dirX = dirX; self.dirY = dirY; self.segments = []; self.active = true; // Remove old children while (self.children.length) self.removeChild(self.children[0]); // Add first segment var seg = LK.getAsset('chain', { anchorX: 0.5, anchorY: 0.5 }); seg.x = originX; seg.y = originY; self.addChild(seg); self.segments.push(seg); }; // Update per frame self.update = function () { if (!self.active) return; // Add new segment in direction var last = self.segments[self.segments.length - 1]; var nx = last.x + self.dirX * self.segmentLength; var ny = last.y + self.dirY * self.segmentLength; // Stop if out of bounds if (nx < 0 || nx > 2048 || ny < 0 || ny > 2732) { self.active = false; return; } // Add new segment var seg = LK.getAsset('chain', { anchorX: 0.5, anchorY: 0.5 }); seg.x = nx; seg.y = ny; self.addChild(seg); self.segments.push(seg); // Limit length if (self.segments.length > self.maxSegments) { self.active = false; } }; // Remove all segments self.clear = function () { while (self.children.length) self.removeChild(self.children[0]); self.segments = []; self.active = false; }; return self; }); // Robot class: moves left/right, fires chain var Robot = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('robot', { anchorX: 0.5, anchorY: 0.5 }); self.width = self.asset.width; self.height = self.asset.height; // For movement self.speed = 0; self.maxSpeed = 32; self.targetX = 1024; // For collision self.getBounds = function () { // Return the bounding box of the robot based on its current position and size return { left: self.x - self.width / 2, right: self.x + self.width / 2, top: self.y - self.height / 2, bottom: self.y + self.height / 2 }; }; // Update per frame self.update = function () { // Move towards targetX var dx = self.targetX - self.x; if (Math.abs(dx) > 8) { self.speed = Math.max(-self.maxSpeed, Math.min(self.maxSpeed, dx * 0.25)); self.x += self.speed; } else { self.x = self.targetX; self.speed = 0; } // Clamp to screen if (self.x < self.width / 2) self.x = self.width / 2; if (self.x > 2048 - self.width / 2) self.x = 2048 - self.width / 2; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Aiming line: white box (thin, will be scaled) // Chain: yellow box (thin) // Ball: green // Ball: red // Robot: blue box // --- Game variables --- var robot = new Robot(); var balls = []; var chain = new Chain(); var aimLine = null; var isAiming = false; var aimStart = { x: 0, y: 0 }; var aimEnd = { x: 0, y: 0 }; var canFire = true; var fireCooldown = 18; // frames between shots var fireTimer = 0; var score = 0; var scoreTxt = null; // --- Add robot --- robot.x = 1024; robot.y = 2732 - 120; game.addChild(robot); // --- Add balls --- var ball1 = new Ball(); ball1.setType('red'); ball1.radius = 90; ball1.asset.width = ball1.radius * 2; ball1.asset.height = ball1.radius * 2; ball1.x = 600; ball1.y = 800; ball1.vx = 18; ball1.vy = -22; balls.push(ball1); game.addChild(ball1); var ball2 = new Ball(); ball2.setType('green'); ball2.radius = 90; ball2.asset.width = ball2.radius * 2; ball2.asset.height = ball2.radius * 2; ball2.x = 1448; ball2.y = 900; ball2.vx = -16; ball2.vy = -18; balls.push(ball2); game.addChild(ball2); // --- Add chain (hidden at start) --- game.addChild(chain); // --- Score text --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Aiming line --- function updateAimLine() { if (!aimLine) { aimLine = LK.getAsset('aimLine', { anchorX: 0, anchorY: 0.5 }); aimLine.alpha = 0.5; game.addChild(aimLine); } var dx = aimEnd.x - aimStart.x; var dy = aimEnd.y - aimStart.y; var len = Math.sqrt(dx * dx + dy * dy); if (len < 80) len = 80; // minimum length aimLine.x = aimStart.x; aimLine.y = aimStart.y; aimLine.width = len; aimLine.height = 16; aimLine.rotation = Math.atan2(dy, dx); aimLine.visible = true; } function hideAimLine() { if (aimLine) aimLine.visible = false; } // --- Input handling --- game.down = function (x, y, obj) { // Only allow aiming if touch is in lower 1/3 of screen if (y > 2732 - 600) { isAiming = true; aimStart.x = robot.x; aimStart.y = robot.y - robot.height / 2; aimEnd.x = x; aimEnd.y = y; updateAimLine(); } }; game.move = function (x, y, obj) { if (isAiming) { // Update aim direction aimEnd.x = x; aimEnd.y = y; updateAimLine(); } else { // Move robot left/right only robot.targetX = x; } }; game.up = function (x, y, obj) { if (isAiming && canFire) { // Fire chain in direction var dx = aimEnd.x - aimStart.x; var dy = aimEnd.y - aimStart.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 80) { var dirX = dx / len; var dirY = dy / len; chain.clear(); chain.fire(aimStart.x, aimStart.y, dirX, dirY); canFire = false; fireTimer = fireCooldown; } } isAiming = false; hideAimLine(); }; // --- Ball-ball collision --- function ballsCollide(b1, b2) { var dx = b1.x - b2.x; var dy = b1.y - b2.y; var dist = Math.sqrt(dx * dx + dy * dy); return dist < b1.radius + b2.radius; } function resolveBallCollision(b1, b2) { var dx = b1.x - b2.x; var dy = b1.y - b2.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) return; var overlap = b1.radius + b2.radius - dist; if (overlap > 0) { // Push balls apart var nx = dx / dist; var ny = dy / dist; b1.x += nx * (overlap / 2); b1.y += ny * (overlap / 2); b2.x -= nx * (overlap / 2); b2.y -= ny * (overlap / 2); // Exchange velocities (elastic) var tx = nx; var ty = ny; var v1 = b1.vx * tx + b1.vy * ty; var v2 = b2.vx * tx + b2.vy * ty; var m1 = b1.radius; var m2 = b2.radius; var newV1 = (v1 * (m1 - m2) + 2 * m2 * v2) / (m1 + m2); var newV2 = (v2 * (m2 - m1) + 2 * m1 * v1) / (m1 + m2); b1.vx += (newV1 - v1) * tx; b1.vy += (newV1 - v1) * ty; b2.vx += (newV2 - v2) * tx; b2.vy += (newV2 - v2) * ty; } } // --- Ball-robot collision --- function ballHitsRobot(ball, robot) { var bounds = robot.getBounds(); // Closest point on robot to ball center var cx = Math.max(bounds.left, Math.min(ball.x, bounds.right)); var cy = Math.max(bounds.top, Math.min(ball.y, bounds.bottom)); var dx = ball.x - cx; var dy = ball.y - cy; var dist = Math.sqrt(dx * dx + dy * dy); return dist < ball.radius; } function resolveBallRobotCollision(ball, robot) { var bounds = robot.getBounds(); var cx = Math.max(bounds.left, Math.min(ball.x, bounds.right)); var cy = Math.max(bounds.top, Math.min(ball.y, bounds.bottom)); var dx = ball.x - cx; var dy = ball.y - cy; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) return; var overlap = ball.radius - dist; if (overlap > 0) { // Push ball out var nx = dx / dist; var ny = dy / dist; ball.x += nx * overlap; ball.y += ny * overlap; // Reflect velocity var dot = ball.vx * nx + ball.vy * ny; ball.vx -= 2 * dot * nx; ball.vy -= 2 * dot * ny; ball.vx *= 0.9; ball.vy *= 0.9; } } // --- Chain-ball collision --- function chainHitsBall(chain, ball) { // Check each segment for (var i = 0; i < chain.segments.length; ++i) { var seg = chain.segments[i]; var dx = seg.x - ball.x; var dy = seg.y - ball.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < ball.radius) { return true; } } return false; } // --- Chain stops at first collision with ball or wall --- function updateChainCollisions() { if (!chain.active) return; for (var i = 0; i < balls.length; ++i) { if (chainHitsBall(chain, balls[i])) { balls[i].shrink(); score += 1; scoreTxt.setText(score); // Flash ball LK.effects.flashObject(balls[i], 0xffff00, 200); chain.active = false; break; } } } // --- Game update loop --- game.update = function () { // Update robot robot.update(); // Update balls for (var i = 0; i < balls.length; ++i) { balls[i].update(); } // Ball-ball collision if (balls.length >= 2) { if (ballsCollide(balls[0], balls[1])) { resolveBallCollision(balls[0], balls[1]); } } // Ball-robot collision for (var i = 0; i < balls.length; ++i) { if (ballHitsRobot(balls[i], robot)) { resolveBallRobotCollision(balls[i], robot); // Game over LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Update chain if (chain.active) { chain.update(); updateChainCollisions(); } // Fire cooldown if (!canFire) { fireTimer--; if (fireTimer <= 0) { canFire = true; } } };
===================================================================
--- original.js
+++ change.js