User prompt
Let's change the route and let it be a chain that moves on the route in the form of a vortex at equal intervals.
User prompt
Let's change the route and let the mill be a chain moving on the route in the form of a vortex at equal intervals.
User prompt
The route intervals must be equal, the balls get into each other as they approach the hole. I don't want this
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'ball.targetX = point1.x + (point2.x - point1.x) * t;' Line Number: 318
User prompt
The balls in the chain are very close to each other. All balls in the chain must be the same size. and should touch each other as an intersection
User prompt
still gap. i dont want it. the balls can touch other balls
User prompt
chain balls have more gaps i dont want it
User prompt
shooter ball should be pulse and shine ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the hole position bottom the shooter
User prompt
shooter place should be center of the screen i mean near center the hole
User prompt
I want a route like in the Zuma game
User prompt
the route can be longer and more simetric
User prompt
i mean near center the hole
User prompt
shooter place should be center of the screen
User prompt
chain still fast. i want slower chain
User prompt
When you destroy the balls of the same color, an opening remains in the chain. the front chain must come back to close the gap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When you bring at least 3 same colored balls together, that is, the color of the ball I throw and the balls in the chain that are the same color (there must be at least 3 same colors next to each other), the chain accelerates. I don't want this. It should be like in the mechanical zuma game
User prompt
When the ball I throw touches any ball in the chain, it does not interfere. is added to the end of the chain. I don't want this. should work like zuma game
User prompt
When I shoot a ball and it reaches the ball chain, instead of being inserted at the correct position (in between two balls where it collides), the ball is added to the end of the chain.
User prompt
When the player creates a match of three or more same-colored balls in the chain, the entire chain should temporarily accelerate for a short duration. The acceleration should apply even if the matched balls are removed. The speed of the chain (e.g., chainSpeed) should increase by a defined multiplier (e.g., ×1.5) for a brief period (e.g., 2 seconds). After this period, the chain should return to its normal speed. This mechanic adds a dynamic sense of tension and reward, encouraging fast and strategic matches. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
chain speed still fast
User prompt
longer route for chain. and slover chain speed like 1px/sec ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
still 1 ball.. i want full locomotive ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
there is only one color ball on the chain. i want more different color balls in the chain. and the speed should be slower ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
slower speed and chain must be include 5 clor balls
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function (color) { var self = Container.call(this); self.color = color; self.ballColors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange']; self.isSpecial = false; self.specialType = null; // 'explosive', 'freeze', 'rapid' var ballGraphics = self.attachAsset('ball_' + color, { anchorX: 0.5, anchorY: 0.5 }); // 5% chance for special balls if (Math.random() < 0.05) { // Start pulsing animation var _pulseEffect = function pulseEffect() { tween(ballGraphics, { scaleX: 1.3, scaleY: 1.3 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1.15, scaleY: 1.15 }, { duration: 600, easing: tween.easeInOut, onFinish: _pulseEffect }); } }); }; self.isSpecial = true; var specials = ['explosive', 'freeze', 'rapid']; self.specialType = specials[Math.floor(Math.random() * specials.length)]; ballGraphics.alpha = 0.9; // Add glow effect for special balls ballGraphics.scaleX = 1.15; ballGraphics.scaleY = 1.15; // Add pulsing effect if (self.specialType === 'explosive') { ballGraphics.tint = 0xFF4500; } else if (self.specialType === 'freeze') { ballGraphics.tint = 0x00FFFF; } else if (self.specialType === 'rapid') { ballGraphics.tint = 0xFFFF00; } _pulseEffect(); } self.trackPosition = 0; self.trackX = 0; self.trackY = 0; self.isMoving = false; return self; }); var ChainBall = Ball.expand(function (color) { var self = Ball.call(this, color); self.chainIndex = 0; self.targetX = 0; self.targetY = 0; self.update = function () { if (self.isMoving) { // Smooth movement towards target position var dx = self.targetX - self.x; var dy = self.targetY - self.y; self.x += dx * 0.3; self.y += dy * 0.3; if (Math.abs(dx) < 1 && Math.abs(dy) < 1) { self.isMoving = false; self.x = self.targetX; self.y = self.targetY; } } }; return self; }); var Shooter = Container.expand(function () { var self = Container.call(this); var shooterGraphics = self.attachAsset('shooter', { anchorX: 0.5, anchorY: 0.5 }); // Add cannon barrel var barrel = self.attachAsset('track', { anchorX: 0, anchorY: 0.5, scaleX: 4, scaleY: 1.5, x: 0, y: 0 }); barrel.tint = 0x333333; self.angle = 0; self.currentBall = null; self.nextBall = null; self.rapidFire = false; self.rapidFireTimer = 0; self.shootCooldown = 0; self.loadBall = function () { if (self.currentBall) { self.currentBall.destroy(); } self.currentBall = self.nextBall; if (self.currentBall) { self.currentBall.x = 0; self.currentBall.y = -40; self.addChild(self.currentBall); // Add glowing effect to current ball tween(self.currentBall, { scaleX: 1.1, scaleY: 1.1 }, { duration: 500, easing: tween.easeInOut }); } // Generate next ball var colors = ['red', 'blue', 'green', 'yellow', 'purple']; var randomColor = colors[Math.floor(Math.random() * colors.length)]; self.nextBall = new Ball(randomColor); }; self.aimAt = function (x, y) { var dx = x - self.x; var dy = y - self.y; self.angle = Math.atan2(dy, dx); self.rotation = self.angle; }; self.shoot = function () { if (self.shootCooldown > 0 || !self.currentBall) return null; var ball = self.currentBall; self.removeChild(ball); // Set ball velocity var speed = 8; ball.vx = Math.cos(self.angle) * speed; ball.vy = Math.sin(self.angle) * speed; ball.x = self.x; ball.y = self.y; self.loadBall(); // Set cooldown self.shootCooldown = self.rapidFire ? 10 : 20; LK.getSound('shoot').play(); return ball; }; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.rapidFire) { self.rapidFireTimer--; if (self.rapidFireTimer <= 0) { self.rapidFire = false; // Remove glow effect tween.stop(self, { tint: true }); self.tint = 0xFFFFFF; } else { // Maintain glow effect if (self.tint === 0xFFFFFF) { tween(self, { tint: 0xFFFF88 }, { duration: 200, easing: tween.easeInOut }); } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game variables var chain = []; var flyingBalls = []; var shooter; var trackPoints = []; var chainSpeed = 0.5; var chainFrozen = false; var freezeTimer = 0; var level = 1; var gameWon = false; var gameLost = false; // Create curved track path function createTrackPath() { trackPoints = []; var centerX = 1024; var centerY = 1366; var radius = 800; var segments = 200; for (var i = 0; i < segments; i++) { var angle = i / segments * Math.PI * 2; var x = centerX + Math.cos(angle) * (radius - i * 2); var y = centerY + Math.sin(angle) * (radius - i * 2) * 0.6; trackPoints.push({ x: x, y: y }); } // Create visual track markers for (var i = 0; i < trackPoints.length; i += 5) { var trackMarker = game.addChild(LK.getAsset('track', { anchorX: 0.5, anchorY: 0.5 })); trackMarker.x = trackPoints[i].x; trackMarker.y = trackPoints[i].y; trackMarker.alpha = 0.3; } } // Create hole at end of track var hole = game.addChild(LK.getAsset('hole', { anchorX: 0.5, anchorY: 0.5 })); // Create shooter shooter = game.addChild(new Shooter()); shooter.x = 1024; shooter.y = 2500; // Initialize first balls shooter.loadBall(); shooter.loadBall(); // Create initial chain function createChain() { chain = []; var chainLength = 15 + level * 5; var colors = ['red', 'blue', 'green', 'yellow', 'purple']; for (var i = 0; i < chainLength; i++) { var color = colors[Math.floor(Math.random() * colors.length)]; var ball = game.addChild(new ChainBall(color)); ball.chainIndex = i; chain.push(ball); } } // Position ball on track function positionBallOnTrack(ball, trackPosition) { if (trackPosition >= trackPoints.length) { ball.x = trackPoints[trackPoints.length - 1].x; ball.y = trackPoints[trackPoints.length - 1].y; return; } var pointIndex = Math.floor(trackPosition); var nextIndex = Math.min(pointIndex + 1, trackPoints.length - 1); var t = trackPosition - pointIndex; var point1 = trackPoints[pointIndex]; var point2 = trackPoints[nextIndex]; ball.targetX = point1.x + (point2.x - point1.x) * t; ball.targetY = point1.y + (point2.y - point1.y) * t; ball.isMoving = true; } // Update chain positions function updateChain() { if (chainFrozen) { freezeTimer--; if (freezeTimer <= 0) { chainFrozen = false; // Remove ice tint from all chain balls for (var i = 0; i < chain.length; i++) { var chainBall = chain[i]; tween(chainBall, { tint: 0xFFFFFF }, { duration: 300 }); } } return; } for (var i = 0; i < chain.length; i++) { var ball = chain[i]; var spacing = 55; // Initialize trackPosition if not set if (ball.trackPosition === undefined) { ball.trackPosition = i * spacing / 10; } // Move chain forward ball.trackPosition += chainSpeed; positionBallOnTrack(ball, ball.trackPosition); // Check if reached hole if (ball.trackPosition >= trackPoints.length - 1) { gameLost = true; LK.showGameOver(); return; } } } // Check for matches function checkMatches() { var matches = []; var currentColor = null; var currentMatch = []; for (var i = 0; i < chain.length; i++) { var ball = chain[i]; if (ball.color === currentColor) { currentMatch.push(ball); } else { if (currentMatch.length >= 3) { matches.push(currentMatch.slice()); } currentColor = ball.color; currentMatch = [ball]; } } // Check last group if (currentMatch.length >= 3) { matches.push(currentMatch.slice()); } // Remove matches for (var m = 0; m < matches.length; m++) { var match = matches[m]; var score = match.length * 10; // Check for special balls for (var b = 0; b < match.length; b++) { var ball = match[b]; if (ball.isSpecial) { handleSpecialBall(ball); } } // Remove matched balls for (var b = 0; b < match.length; b++) { var ball = match[b]; var index = chain.indexOf(ball); if (index > -1) { chain.splice(index, 1); ball.destroy(); } } LK.setScore(LK.getScore() + score); LK.getSound('match').play(); // Pull chain back chainSpeed = Math.max(0.5, chainSpeed - 0.1); } // Check win condition if (chain.length === 0) { gameWon = true; level++; LK.showYouWin(); } } // Handle special ball effects function handleSpecialBall(ball) { if (ball.specialType === 'explosive') { var _shakeEffect = function shakeEffect() { if (shakeTimer < shakeDuration) { game.x = originalX + (Math.random() - 0.5) * shakeIntensity; game.y = originalY + (Math.random() - 0.5) * shakeIntensity; shakeTimer += 16; LK.setTimeout(_shakeEffect, 16); } else { game.x = originalX; game.y = originalY; } }; // Remove nearby balls var explosionRadius = 3; var ballIndex = chain.indexOf(ball); var toRemove = []; for (var i = Math.max(0, ballIndex - explosionRadius); i < Math.min(chain.length, ballIndex + explosionRadius + 1); i++) { if (chain[i] !== ball) { toRemove.push(chain[i]); } } for (var i = 0; i < toRemove.length; i++) { var index = chain.indexOf(toRemove[i]); if (index > -1) { chain.splice(index, 1); toRemove[i].destroy(); } } LK.effects.flashScreen(0xff8000, 300); // Add screen shake effect var originalX = game.x; var originalY = game.y; var shakeIntensity = 10; var shakeDuration = 300; var shakeTimer = 0; _shakeEffect(); } else if (ball.specialType === 'freeze') { chainFrozen = true; freezeTimer = 180; // 3 seconds at 60fps LK.effects.flashScreen(0x00ffff, 500); // Add ice tint to all chain balls for (var i = 0; i < chain.length; i++) { var chainBall = chain[i]; tween(chainBall, { tint: 0x88DDFF }, { duration: 300 }); } } else if (ball.specialType === 'rapid') { shooter.rapidFire = true; shooter.rapidFireTimer = 300; // 5 seconds at 60fps LK.effects.flashScreen(0xffff00, 200); } LK.getSound('powerup').play(); } // Insert ball into chain function insertBallIntoChain(ball, insertIndex) { var chainBall = new ChainBall(ball.color); chainBall.isSpecial = ball.isSpecial; chainBall.specialType = ball.specialType; chainBall.x = ball.x; chainBall.y = ball.y; chainBall.scaleX = 0.1; chainBall.scaleY = 0.1; game.addChild(chainBall); // Animate ball insertion tween(chainBall, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); chain.splice(insertIndex, 0, chainBall); // Update chain indices for (var i = 0; i < chain.length; i++) { chain[i].chainIndex = i; } checkMatches(); } // Initialize game createTrackPath(); createChain(); // Position hole at end of track hole.x = trackPoints[trackPoints.length - 1].x; hole.y = trackPoints[trackPoints.length - 1].y; // Score display var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Level display var levelTxt = new Text2('Level: 1', { size: 50, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); levelTxt.x = 120; levelTxt.y = 20; LK.gui.top.addChild(levelTxt); // Next ball preview var nextBallTxt = new Text2('Next:', { size: 40, fill: 0xFFFFFF }); nextBallTxt.anchor.set(1, 0); LK.gui.topRight.addChild(nextBallTxt); // Game input game.down = function (x, y, obj) { shooter.aimAt(x, y); var ball = shooter.shoot(); if (ball) { flyingBalls.push(ball); game.addChild(ball); } }; // Main game loop game.update = function () { if (gameWon || gameLost) return; // Update chain updateChain(); // Update flying balls for (var i = flyingBalls.length - 1; i >= 0; i--) { var ball = flyingBalls[i]; ball.x += ball.vx; ball.y += ball.vy; // Check collision with chain var inserted = false; for (var j = 0; j < chain.length; j++) { var chainBall = chain[j]; if (ball.intersects(chainBall)) { insertBallIntoChain(ball, j); ball.destroy(); flyingBalls.splice(i, 1); inserted = true; break; } } // Remove if off screen if (!inserted && (ball.x < -100 || ball.x > 2148 || ball.y < -100 || ball.y > 2832)) { ball.destroy(); flyingBalls.splice(i, 1); } } // Update shooter shooter.update(); // Update UI scoreTxt.setText('Score: ' + LK.getScore()); levelTxt.setText('Level: ' + level); // Show next ball preview if (shooter.nextBall) { if (shooter.nextBall.parent) { shooter.nextBall.parent.removeChild(shooter.nextBall); } shooter.nextBall.x = -50; shooter.nextBall.y = 60; shooter.nextBall.scaleX = 0.8; shooter.nextBall.scaleY = 0.8; LK.gui.topRight.addChild(shooter.nextBall); } // Increase chain speed over time chainSpeed += 0.001; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Ball = Container.expand(function (color) {
var self = Container.call(this);
self.color = color;
self.ballColors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange'];
self.isSpecial = false;
self.specialType = null; // 'explosive', 'freeze', 'rapid'
var ballGraphics = self.attachAsset('ball_' + color, {
anchorX: 0.5,
anchorY: 0.5
});
// 5% chance for special balls
if (Math.random() < 0.05) {
// Start pulsing animation
var _pulseEffect = function pulseEffect() {
tween(ballGraphics, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: _pulseEffect
});
}
});
};
self.isSpecial = true;
var specials = ['explosive', 'freeze', 'rapid'];
self.specialType = specials[Math.floor(Math.random() * specials.length)];
ballGraphics.alpha = 0.9;
// Add glow effect for special balls
ballGraphics.scaleX = 1.15;
ballGraphics.scaleY = 1.15;
// Add pulsing effect
if (self.specialType === 'explosive') {
ballGraphics.tint = 0xFF4500;
} else if (self.specialType === 'freeze') {
ballGraphics.tint = 0x00FFFF;
} else if (self.specialType === 'rapid') {
ballGraphics.tint = 0xFFFF00;
}
_pulseEffect();
}
self.trackPosition = 0;
self.trackX = 0;
self.trackY = 0;
self.isMoving = false;
return self;
});
var ChainBall = Ball.expand(function (color) {
var self = Ball.call(this, color);
self.chainIndex = 0;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
if (self.isMoving) {
// Smooth movement towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
self.x += dx * 0.3;
self.y += dy * 0.3;
if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {
self.isMoving = false;
self.x = self.targetX;
self.y = self.targetY;
}
}
};
return self;
});
var Shooter = Container.expand(function () {
var self = Container.call(this);
var shooterGraphics = self.attachAsset('shooter', {
anchorX: 0.5,
anchorY: 0.5
});
// Add cannon barrel
var barrel = self.attachAsset('track', {
anchorX: 0,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5,
x: 0,
y: 0
});
barrel.tint = 0x333333;
self.angle = 0;
self.currentBall = null;
self.nextBall = null;
self.rapidFire = false;
self.rapidFireTimer = 0;
self.shootCooldown = 0;
self.loadBall = function () {
if (self.currentBall) {
self.currentBall.destroy();
}
self.currentBall = self.nextBall;
if (self.currentBall) {
self.currentBall.x = 0;
self.currentBall.y = -40;
self.addChild(self.currentBall);
// Add glowing effect to current ball
tween(self.currentBall, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.easeInOut
});
}
// Generate next ball
var colors = ['red', 'blue', 'green', 'yellow', 'purple'];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
self.nextBall = new Ball(randomColor);
};
self.aimAt = function (x, y) {
var dx = x - self.x;
var dy = y - self.y;
self.angle = Math.atan2(dy, dx);
self.rotation = self.angle;
};
self.shoot = function () {
if (self.shootCooldown > 0 || !self.currentBall) return null;
var ball = self.currentBall;
self.removeChild(ball);
// Set ball velocity
var speed = 8;
ball.vx = Math.cos(self.angle) * speed;
ball.vy = Math.sin(self.angle) * speed;
ball.x = self.x;
ball.y = self.y;
self.loadBall();
// Set cooldown
self.shootCooldown = self.rapidFire ? 10 : 20;
LK.getSound('shoot').play();
return ball;
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.rapidFire) {
self.rapidFireTimer--;
if (self.rapidFireTimer <= 0) {
self.rapidFire = false;
// Remove glow effect
tween.stop(self, {
tint: true
});
self.tint = 0xFFFFFF;
} else {
// Maintain glow effect
if (self.tint === 0xFFFFFF) {
tween(self, {
tint: 0xFFFF88
}, {
duration: 200,
easing: tween.easeInOut
});
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
var chain = [];
var flyingBalls = [];
var shooter;
var trackPoints = [];
var chainSpeed = 0.5;
var chainFrozen = false;
var freezeTimer = 0;
var level = 1;
var gameWon = false;
var gameLost = false;
// Create curved track path
function createTrackPath() {
trackPoints = [];
var centerX = 1024;
var centerY = 1366;
var radius = 800;
var segments = 200;
for (var i = 0; i < segments; i++) {
var angle = i / segments * Math.PI * 2;
var x = centerX + Math.cos(angle) * (radius - i * 2);
var y = centerY + Math.sin(angle) * (radius - i * 2) * 0.6;
trackPoints.push({
x: x,
y: y
});
}
// Create visual track markers
for (var i = 0; i < trackPoints.length; i += 5) {
var trackMarker = game.addChild(LK.getAsset('track', {
anchorX: 0.5,
anchorY: 0.5
}));
trackMarker.x = trackPoints[i].x;
trackMarker.y = trackPoints[i].y;
trackMarker.alpha = 0.3;
}
}
// Create hole at end of track
var hole = game.addChild(LK.getAsset('hole', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create shooter
shooter = game.addChild(new Shooter());
shooter.x = 1024;
shooter.y = 2500;
// Initialize first balls
shooter.loadBall();
shooter.loadBall();
// Create initial chain
function createChain() {
chain = [];
var chainLength = 15 + level * 5;
var colors = ['red', 'blue', 'green', 'yellow', 'purple'];
for (var i = 0; i < chainLength; i++) {
var color = colors[Math.floor(Math.random() * colors.length)];
var ball = game.addChild(new ChainBall(color));
ball.chainIndex = i;
chain.push(ball);
}
}
// Position ball on track
function positionBallOnTrack(ball, trackPosition) {
if (trackPosition >= trackPoints.length) {
ball.x = trackPoints[trackPoints.length - 1].x;
ball.y = trackPoints[trackPoints.length - 1].y;
return;
}
var pointIndex = Math.floor(trackPosition);
var nextIndex = Math.min(pointIndex + 1, trackPoints.length - 1);
var t = trackPosition - pointIndex;
var point1 = trackPoints[pointIndex];
var point2 = trackPoints[nextIndex];
ball.targetX = point1.x + (point2.x - point1.x) * t;
ball.targetY = point1.y + (point2.y - point1.y) * t;
ball.isMoving = true;
}
// Update chain positions
function updateChain() {
if (chainFrozen) {
freezeTimer--;
if (freezeTimer <= 0) {
chainFrozen = false;
// Remove ice tint from all chain balls
for (var i = 0; i < chain.length; i++) {
var chainBall = chain[i];
tween(chainBall, {
tint: 0xFFFFFF
}, {
duration: 300
});
}
}
return;
}
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
var spacing = 55;
// Initialize trackPosition if not set
if (ball.trackPosition === undefined) {
ball.trackPosition = i * spacing / 10;
}
// Move chain forward
ball.trackPosition += chainSpeed;
positionBallOnTrack(ball, ball.trackPosition);
// Check if reached hole
if (ball.trackPosition >= trackPoints.length - 1) {
gameLost = true;
LK.showGameOver();
return;
}
}
}
// Check for matches
function checkMatches() {
var matches = [];
var currentColor = null;
var currentMatch = [];
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
if (ball.color === currentColor) {
currentMatch.push(ball);
} else {
if (currentMatch.length >= 3) {
matches.push(currentMatch.slice());
}
currentColor = ball.color;
currentMatch = [ball];
}
}
// Check last group
if (currentMatch.length >= 3) {
matches.push(currentMatch.slice());
}
// Remove matches
for (var m = 0; m < matches.length; m++) {
var match = matches[m];
var score = match.length * 10;
// Check for special balls
for (var b = 0; b < match.length; b++) {
var ball = match[b];
if (ball.isSpecial) {
handleSpecialBall(ball);
}
}
// Remove matched balls
for (var b = 0; b < match.length; b++) {
var ball = match[b];
var index = chain.indexOf(ball);
if (index > -1) {
chain.splice(index, 1);
ball.destroy();
}
}
LK.setScore(LK.getScore() + score);
LK.getSound('match').play();
// Pull chain back
chainSpeed = Math.max(0.5, chainSpeed - 0.1);
}
// Check win condition
if (chain.length === 0) {
gameWon = true;
level++;
LK.showYouWin();
}
}
// Handle special ball effects
function handleSpecialBall(ball) {
if (ball.specialType === 'explosive') {
var _shakeEffect = function shakeEffect() {
if (shakeTimer < shakeDuration) {
game.x = originalX + (Math.random() - 0.5) * shakeIntensity;
game.y = originalY + (Math.random() - 0.5) * shakeIntensity;
shakeTimer += 16;
LK.setTimeout(_shakeEffect, 16);
} else {
game.x = originalX;
game.y = originalY;
}
};
// Remove nearby balls
var explosionRadius = 3;
var ballIndex = chain.indexOf(ball);
var toRemove = [];
for (var i = Math.max(0, ballIndex - explosionRadius); i < Math.min(chain.length, ballIndex + explosionRadius + 1); i++) {
if (chain[i] !== ball) {
toRemove.push(chain[i]);
}
}
for (var i = 0; i < toRemove.length; i++) {
var index = chain.indexOf(toRemove[i]);
if (index > -1) {
chain.splice(index, 1);
toRemove[i].destroy();
}
}
LK.effects.flashScreen(0xff8000, 300);
// Add screen shake effect
var originalX = game.x;
var originalY = game.y;
var shakeIntensity = 10;
var shakeDuration = 300;
var shakeTimer = 0;
_shakeEffect();
} else if (ball.specialType === 'freeze') {
chainFrozen = true;
freezeTimer = 180; // 3 seconds at 60fps
LK.effects.flashScreen(0x00ffff, 500);
// Add ice tint to all chain balls
for (var i = 0; i < chain.length; i++) {
var chainBall = chain[i];
tween(chainBall, {
tint: 0x88DDFF
}, {
duration: 300
});
}
} else if (ball.specialType === 'rapid') {
shooter.rapidFire = true;
shooter.rapidFireTimer = 300; // 5 seconds at 60fps
LK.effects.flashScreen(0xffff00, 200);
}
LK.getSound('powerup').play();
}
// Insert ball into chain
function insertBallIntoChain(ball, insertIndex) {
var chainBall = new ChainBall(ball.color);
chainBall.isSpecial = ball.isSpecial;
chainBall.specialType = ball.specialType;
chainBall.x = ball.x;
chainBall.y = ball.y;
chainBall.scaleX = 0.1;
chainBall.scaleY = 0.1;
game.addChild(chainBall);
// Animate ball insertion
tween(chainBall, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
chain.splice(insertIndex, 0, chainBall);
// Update chain indices
for (var i = 0; i < chain.length; i++) {
chain[i].chainIndex = i;
}
checkMatches();
}
// Initialize game
createTrackPath();
createChain();
// Position hole at end of track
hole.x = trackPoints[trackPoints.length - 1].x;
hole.y = trackPoints[trackPoints.length - 1].y;
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Level display
var levelTxt = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
levelTxt.x = 120;
levelTxt.y = 20;
LK.gui.top.addChild(levelTxt);
// Next ball preview
var nextBallTxt = new Text2('Next:', {
size: 40,
fill: 0xFFFFFF
});
nextBallTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(nextBallTxt);
// Game input
game.down = function (x, y, obj) {
shooter.aimAt(x, y);
var ball = shooter.shoot();
if (ball) {
flyingBalls.push(ball);
game.addChild(ball);
}
};
// Main game loop
game.update = function () {
if (gameWon || gameLost) return;
// Update chain
updateChain();
// Update flying balls
for (var i = flyingBalls.length - 1; i >= 0; i--) {
var ball = flyingBalls[i];
ball.x += ball.vx;
ball.y += ball.vy;
// Check collision with chain
var inserted = false;
for (var j = 0; j < chain.length; j++) {
var chainBall = chain[j];
if (ball.intersects(chainBall)) {
insertBallIntoChain(ball, j);
ball.destroy();
flyingBalls.splice(i, 1);
inserted = true;
break;
}
}
// Remove if off screen
if (!inserted && (ball.x < -100 || ball.x > 2148 || ball.y < -100 || ball.y > 2832)) {
ball.destroy();
flyingBalls.splice(i, 1);
}
}
// Update shooter
shooter.update();
// Update UI
scoreTxt.setText('Score: ' + LK.getScore());
levelTxt.setText('Level: ' + level);
// Show next ball preview
if (shooter.nextBall) {
if (shooter.nextBall.parent) {
shooter.nextBall.parent.removeChild(shooter.nextBall);
}
shooter.nextBall.x = -50;
shooter.nextBall.y = 60;
shooter.nextBall.scaleX = 0.8;
shooter.nextBall.scaleY = 0.8;
LK.gui.topRight.addChild(shooter.nextBall);
}
// Increase chain speed over time
chainSpeed += 0.001;
};
8 ball billard with fire. In-Game asset. 2d. High contrast. No shadows
green neon ball. In-Game asset. 2d. High contrast. No shadows
blach hole gif. In-Game asset. 2d. High contrast. No shadows
space shooter cannon. In-Game asset. 2d. High contrast. No shadows
fire effect. In-Game asset. 2d. High contrast. No shadows
space track point. In-Game asset. 2d. High contrast. No shadows
aim . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
ice. In-Game asset. 2d. High contrast. No shadows
flying superman
laser beam. In-Game asset. 2d. High contrast. No shadows
green goblin. In-Game asset. 2d. High contrast. No shadows
rocket. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
shoot
Sound effect
match
Sound effect
powerup
Sound effect
Gameplay
Music
gameover
Sound effect
frozen
Sound effect
celebration
Sound effect
white_shoot
Sound effect
fire_flying
Sound effect
superman_flying
Sound effect
superman_laser
Sound effect
villain_flying
Sound effect
villain_laser
Sound effect