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
});
// Start pulsing and shining animation
animateShooterBall();
}
// 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.0005; // Much slower chain speed
var normalChainSpeed = 0.0005; // Store normal speed
var chainFrozen = false;
var freezeTimer = 0;
var level = 1;
var gameWon = false;
var gameLost = false;
// Create vortex track path
function createTrackPath() {
trackPoints = [];
var centerX = 1024;
var centerY = 1366;
var segments = 1000; // Optimal length for vortex gameplay
// Create dramatic vortex track - starts from outside and spirals inward like a whirlpool
for (var i = 0; i < segments; i++) {
var progress = i / segments;
// Vortex angle - creates tight spiral inward motion
var vortexAngle = progress * Math.PI * 20; // 10 full rotations for dramatic vortex effect
// Radius decreases exponentially for vortex effect - starts very wide, narrows quickly
var baseRadius = 950 * Math.pow(1 - progress, 0.8); // Exponential decay for vortex
// Add vortex distortion - creates the characteristic vortex pull effect
var vortexPull = Math.sin(progress * Math.PI * 40) * (30 * (1 - progress)); // Decreasing distortion
var currentRadius = baseRadius + vortexPull;
// Ensure minimum radius for playability at center
currentRadius = Math.max(currentRadius, 80);
// Calculate position on vortex spiral
var x = centerX + Math.cos(vortexAngle) * currentRadius;
var y = centerY + Math.sin(vortexAngle) * currentRadius;
// Add vortex turbulence - creates swirling effect
var turbulence = Math.sin(progress * Math.PI * 60) * (20 * (1 - progress));
x += Math.cos(vortexAngle + Math.PI / 2) * turbulence;
y += Math.sin(vortexAngle + Math.PI / 2) * turbulence;
// Ensure the path stays within screen bounds with padding
x = Math.max(150, Math.min(1898, x));
y = Math.max(300, Math.min(2400, y));
trackPoints.push({
x: x,
y: y
});
}
// Create visual track markers with vortex effect
for (var i = 0; i < trackPoints.length; i += 6) {
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 + i / trackPoints.length * 0.3; // Fade in towards center
// Scale markers smaller as they approach center for vortex effect
var scaleProgress = i / trackPoints.length;
trackMarker.scaleX = 0.5 + (1 - scaleProgress) * 0.5;
trackMarker.scaleY = 0.5 + (1 - scaleProgress) * 0.5;
}
}
// 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; // Center of screen horizontally (2048/2 = 1024)
shooter.y = 1366; // Position near the center hole
// 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'];
var ballSpacing = 50; // Space between balls - balls touch each other
var trackSpacing = 3.0; // Increased track position spacing for vortex movement
// Ensure better color distribution by cycling through colors
for (var i = 0; i < chainLength; i++) {
// Use a mix of sequential and random distribution
var colorIndex;
if (i % 8 < 5) {
// First 5 of every 8 balls use sequential colors
colorIndex = i % colors.length;
} else {
// Last 3 of every 8 balls use random colors
colorIndex = Math.floor(Math.random() * colors.length);
}
var color = colors[colorIndex];
var ball = game.addChild(new ChainBall(color));
ball.chainIndex = i;
// Initialize track position with consistent spacing for vortex
ball.trackPosition = i * trackSpacing;
// Position ball immediately on track
positionBallOnTrack(ball, ball.trackPosition);
chain.push(ball);
}
}
// Position ball on track
function positionBallOnTrack(ball, trackPosition) {
if (trackPosition >= trackPoints.length || trackPoints.length === 0) {
if (trackPoints.length > 0) {
ball.x = trackPoints[trackPoints.length - 1].x;
ball.y = trackPoints[trackPoints.length - 1].y;
} else {
ball.x = 1024;
ball.y = 1366;
}
return;
}
var pointIndex = Math.floor(Math.max(0, trackPosition));
var nextIndex = Math.min(pointIndex + 1, trackPoints.length - 1);
var t = trackPosition - pointIndex;
var point1 = trackPoints[pointIndex];
var point2 = trackPoints[nextIndex];
// Add safety check for undefined points
if (!point1 || !point2) {
ball.x = 1024;
ball.y = 1366;
ball.isMoving = false;
return;
}
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;
}
// Move all balls forward and maintain equal spacing for vortex
var trackSpacing = 3.0; // Consistent spacing between balls for vortex movement
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
// Move chain forward in vortex pattern
ball.trackPosition += chainSpeed;
// Check if reached hole (vortex center)
if (ball.trackPosition >= trackPoints.length - 1) {
gameLost = true;
LK.showGameOver();
return;
}
}
// Maintain equal spacing between balls for vortex movement
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
// Ensure proper spacing from previous ball
if (i > 0) {
var previousBall = chain[i - 1];
var expectedPosition = previousBall.trackPosition + trackSpacing;
// Only adjust if ball is too close to previous ball
if (ball.trackPosition < expectedPosition) {
ball.trackPosition = expectedPosition;
}
}
positionBallOnTrack(ball, ball.trackPosition);
}
}
// 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);
}
}
// Store the first index of the match to know where the gap starts
var firstMatchIndex = chain.indexOf(match[0]);
var trackSpacing = 3.0; // Consistent spacing between balls for vortex
var gapSize = match.length * trackSpacing; // Calculate gap size based on track spacing
// 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();
}
}
// Close the gap by moving all balls after the removed section forward
for (var i = firstMatchIndex; i < chain.length; i++) {
var ball = chain[i];
// Move the ball's track position forward to close the gap
ball.trackPosition -= gapSize;
}
// Re-space all balls to maintain equal intervals after gap closing
for (var i = 1; i < chain.length; i++) {
var previousBall = chain[i - 1];
var currentBall = chain[i];
var expectedPosition = previousBall.trackPosition + trackSpacing;
if (currentBall.trackPosition < expectedPosition) {
currentBall.trackPosition = expectedPosition;
}
// Animate the ball to its new position smoothly
tween(currentBall, {
x: currentBall.targetX,
y: currentBall.targetY
}, {
duration: 300,
easing: tween.easeOut
});
}
LK.setScore(LK.getScore() + score);
LK.getSound('match').play();
// Pull chain back slightly when balls are removed
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 below the shooter
hole.x = 1024;
hole.y = 1500; // Below shooter position
// Add pulsing and shining animation to shooter ball
function animateShooterBall() {
if (shooter.currentBall) {
// Pulsing effect
tween(shooter.currentBall, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(shooter.currentBall, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: animateShooterBall
});
}
});
// Shining effect with alpha animation
tween(shooter.currentBall, {
alpha: 0.7
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(shooter.currentBall, {
alpha: 1.0
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
}
}
// 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;
var collisionIndex = -1;
for (var j = 0; j < chain.length; j++) {
var chainBall = chain[j];
if (ball.intersects(chainBall)) {
collisionIndex = j;
break;
}
}
// If collision detected, insert at collision position
if (collisionIndex !== -1) {
// Insert after the collided ball
var insertIndex = collisionIndex + 1;
var trackSpacing = 3.0; // Consistent spacing between balls for vortex
// Adjust track positions for all balls after insertion point
for (var k = insertIndex; k < chain.length; k++) {
chain[k].trackPosition += trackSpacing; // Move balls back to make space
}
insertBallIntoChain(ball, insertIndex);
// Set the inserted ball's track position with proper spacing
if (insertIndex < chain.length) {
chain[insertIndex].trackPosition = chain[collisionIndex].trackPosition + trackSpacing;
positionBallOnTrack(chain[insertIndex], chain[insertIndex].trackPosition);
}
// Re-space all balls after insertion to maintain equal intervals
for (var k = insertIndex + 1; k < chain.length; k++) {
var expectedPosition = chain[k - 1].trackPosition + trackSpacing;
if (chain[k].trackPosition < expectedPosition) {
chain[k].trackPosition = expectedPosition;
}
}
ball.destroy();
flyingBalls.splice(i, 1);
inserted = true;
}
// 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 (much slower increase)
normalChainSpeed += 0.00002;
chainSpeed = normalChainSpeed;
}; ===================================================================
--- original.js
+++ change.js
@@ -201,47 +201,54 @@
var freezeTimer = 0;
var level = 1;
var gameWon = false;
var gameLost = false;
-// Create curved track path
+// Create vortex track path
function createTrackPath() {
trackPoints = [];
var centerX = 1024;
var centerY = 1366;
var segments = 1000; // Optimal length for vortex gameplay
- // Create vortex pattern - tight spiral moving inward with equal intervals
+ // Create dramatic vortex track - starts from outside and spirals inward like a whirlpool
for (var i = 0; i < segments; i++) {
var progress = i / segments;
- // Vortex angle - creates tight spiral with multiple rotations
- var vortexAngle = progress * Math.PI * 20; // 10 full rotations inward
- // Radius decreases linearly for equal spacing
- var radius = 800 - progress * 700; // Linear decrease for equal intervals
- // Ensure minimum radius
- radius = Math.max(radius, 50);
- // Create vortex effect with tighter spiral
- var vortexRadius = radius * (1 - progress * 0.3); // Additional inward pull
- // Calculate position on vortex spiral with equal angular spacing
- var x = centerX + Math.cos(vortexAngle) * vortexRadius;
- var y = centerY + Math.sin(vortexAngle) * vortexRadius;
- // Ensure the path stays within screen bounds
- x = Math.max(100, Math.min(1948, x));
- y = Math.max(200, Math.min(2500, y));
+ // Vortex angle - creates tight spiral inward motion
+ var vortexAngle = progress * Math.PI * 20; // 10 full rotations for dramatic vortex effect
+ // Radius decreases exponentially for vortex effect - starts very wide, narrows quickly
+ var baseRadius = 950 * Math.pow(1 - progress, 0.8); // Exponential decay for vortex
+ // Add vortex distortion - creates the characteristic vortex pull effect
+ var vortexPull = Math.sin(progress * Math.PI * 40) * (30 * (1 - progress)); // Decreasing distortion
+ var currentRadius = baseRadius + vortexPull;
+ // Ensure minimum radius for playability at center
+ currentRadius = Math.max(currentRadius, 80);
+ // Calculate position on vortex spiral
+ var x = centerX + Math.cos(vortexAngle) * currentRadius;
+ var y = centerY + Math.sin(vortexAngle) * currentRadius;
+ // Add vortex turbulence - creates swirling effect
+ var turbulence = Math.sin(progress * Math.PI * 60) * (20 * (1 - progress));
+ x += Math.cos(vortexAngle + Math.PI / 2) * turbulence;
+ y += Math.sin(vortexAngle + Math.PI / 2) * turbulence;
+ // Ensure the path stays within screen bounds with padding
+ x = Math.max(150, Math.min(1898, x));
+ y = Math.max(300, Math.min(2400, y));
trackPoints.push({
x: x,
y: y
});
}
- // Create visual track markers with equal spacing
- for (var i = 0; i < trackPoints.length; i += 10) {
+ // Create visual track markers with vortex effect
+ for (var i = 0; i < trackPoints.length; i += 6) {
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;
- trackMarker.scaleX = 0.8;
- trackMarker.scaleY = 0.8;
+ trackMarker.alpha = 0.3 + i / trackPoints.length * 0.3; // Fade in towards center
+ // Scale markers smaller as they approach center for vortex effect
+ var scaleProgress = i / trackPoints.length;
+ trackMarker.scaleX = 0.5 + (1 - scaleProgress) * 0.5;
+ trackMarker.scaleY = 0.5 + (1 - scaleProgress) * 0.5;
}
}
// Create hole at end of track
var hole = game.addChild(LK.getAsset('hole', {
@@ -260,9 +267,9 @@
chain = [];
var chainLength = 15 + level * 5;
var colors = ['red', 'blue', 'green', 'yellow', 'purple'];
var ballSpacing = 50; // Space between balls - balls touch each other
- var trackSpacing = 2.5; // Track position spacing to maintain equal intervals
+ var trackSpacing = 3.0; // Increased track position spacing for vortex movement
// Ensure better color distribution by cycling through colors
for (var i = 0; i < chainLength; i++) {
// Use a mix of sequential and random distribution
var colorIndex;
@@ -275,9 +282,9 @@
}
var color = colors[colorIndex];
var ball = game.addChild(new ChainBall(color));
ball.chainIndex = i;
- // Initialize track position with consistent spacing
+ // Initialize track position with consistent spacing for vortex
ball.trackPosition = i * trackSpacing;
// Position ball immediately on track
positionBallOnTrack(ball, ball.trackPosition);
chain.push(ball);
@@ -328,32 +335,32 @@
}
}
return;
}
- // Move all balls forward with equal intervals on vortex
- var trackSpacing = 3.0; // Increased spacing for vortex pattern
+ // Move all balls forward and maintain equal spacing for vortex
+ var trackSpacing = 3.0; // Consistent spacing between balls for vortex movement
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
- // Move chain forward along vortex
+ // Move chain forward in vortex pattern
ball.trackPosition += chainSpeed;
- // Check if reached center hole
+ // Check if reached hole (vortex center)
if (ball.trackPosition >= trackPoints.length - 1) {
gameLost = true;
LK.showGameOver();
return;
}
}
- // Maintain strict equal spacing between balls on vortex
+ // Maintain equal spacing between balls for vortex movement
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
- // Calculate expected position based on equal intervals
- if (i === 0) {
- // Lead ball sets the pace
- } else {
+ // Ensure proper spacing from previous ball
+ if (i > 0) {
var previousBall = chain[i - 1];
var expectedPosition = previousBall.trackPosition + trackSpacing;
- // Maintain exact spacing for vortex pattern
- ball.trackPosition = expectedPosition;
+ // Only adjust if ball is too close to previous ball
+ if (ball.trackPosition < expectedPosition) {
+ ball.trackPosition = expectedPosition;
+ }
}
positionBallOnTrack(ball, ball.trackPosition);
}
}
@@ -390,9 +397,9 @@
}
}
// Store the first index of the match to know where the gap starts
var firstMatchIndex = chain.indexOf(match[0]);
- var trackSpacing = 2.5; // Consistent spacing between balls
+ var trackSpacing = 3.0; // Consistent spacing between balls for vortex
var gapSize = match.length * trackSpacing; // Calculate gap size based on track spacing
// Remove matched balls
for (var b = 0; b < match.length; b++) {
var ball = match[b];
@@ -522,11 +529,11 @@
}
// Initialize game
createTrackPath();
createChain();
-// Position hole at center of vortex
+// Position hole below the shooter
hole.x = 1024;
-hole.y = 1366; // Center position where vortex ends
+hole.y = 1500; // Below shooter position
// Add pulsing and shining animation to shooter ball
function animateShooterBall() {
if (shooter.currentBall) {
// Pulsing effect
@@ -619,9 +626,9 @@
// If collision detected, insert at collision position
if (collisionIndex !== -1) {
// Insert after the collided ball
var insertIndex = collisionIndex + 1;
- var trackSpacing = 2.5; // Consistent spacing between balls
+ var trackSpacing = 3.0; // Consistent spacing between balls for vortex
// Adjust track positions for all balls after insertion point
for (var k = insertIndex; k < chain.length; k++) {
chain[k].trackPosition += trackSpacing; // Move balls back to make space
}
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