User prompt
oyunda bazen siyah top çıkıyor. bunu istemiyorum. ancak oyuna bir kaç özel top ekleyelim. bunlardan birincisi beyaz top olsun. atıldığında tüm zinciri 2 saniye boyunca durdursun. ve sayım ekranda çıksın. siyah top ekleyelim. bu da atıldığında zincire değerse, yanındaki 5 topu yok etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
toplar, rotanın sonuna doğru birbirine giriyor. bunu istemiyorum
User prompt
zincirin hızı oyun boyunca sadece normal,hızlı ve en hızlı tuşuna basınca değişsin.
User prompt
oyunun normal hızını biraz daha yavaş yapalım. hızlı olan kısmını da yavaşlatalım. en hızlı modu da yavaşlatalım
User prompt
arka plan dinamik uzay görüntüsü olsun. arka plandaki renkli kareleri istemiyorum. 10 saniyede bir arka planda yıldız kaysın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
daha gerçekçi uzay olsun.
User prompt
oyunun arka planı uzay olsun.
User prompt
normal speed can be decrease
User prompt
The score system should be 1x for normal, 1.5x for fast and 2x for very fast. The points received will flash on the screen during the reading period. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the normal game speed can be faster
User prompt
normal, fast and very fast speed increase
User prompt
The acceleration button works, but let's modify it. There are 3 levels of speed in the game: normal, fast and very fast. And let these work on a single button. If I press it once, it's fast. If I press it again, it's very fast. If I press it again, it goes back to normal.
User prompt
First, if I put 3 balls of the same color together, they should disappear. Then, when the gap between them is closed, the balls of the same color should touch each other and then disappear. Yes, these things happened, but what I wanted was the disappearance animation in order. First, when the balls of the same color come together, there will be an explosion effect, then when the gap closes, the balls of the same color that come together will disappear. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
First, if I put 3 balls of the same color together, they should disappear. Then, when the gap between them is closed, the balls of the same color should touch each other and then disappear.
User prompt
Yes, it disappears when you hit balls of the same color. However, when the gap in the chain is closed and the same colors appear side by side in front and behind, the balls should disappear. this happened. However, the balls should disappear when they touch each other.
User prompt
Yes, it disappears when you hit balls of the same color. However, when the gap in the chain is closed and the same colors appear side by side in front and behind, the balls should disappear.
User prompt
when i press the accelerate nothing happen. chain will not faster
User prompt
Add a clickable button to the game. When you press this button, the chain accelerates. Press again and it will return to its previous speed.
User prompt
the balls overlapping when comes near tyhe hole
User prompt
The balls are still overlapping each other as they move towards the hole.
User prompt
the hole position shoulde be near the shooter
User prompt
The route should not contact the shooter
User prompt
The route does not currently go to the hole. let's fix this. The end of the route must end at the hole. but there should be a longer route
User prompt
The route may be slightly longer. but the balls are still intertwined. In this case, there should be equal space between them and the balls should touch each other but not be intertwined.
User prompt
the route follows a single path towards the hole in a swirling pattern
/****
* 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 acceleratedChainSpeed = 0.002; // Faster chain speed when accelerating
var isAccelerating = false;
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 holeX = 1024;
var holeY = 1200; // Hole position - closer to shooter
var segments = 1500; // Longer track for better gameplay
// Create single swirling path towards the hole - starts from outside and spirals inward in one continuous motion
for (var i = 0; i < segments; i++) {
var progress = i / segments;
// Single spiral angle - creates one continuous swirl towards center
var spiralAngle = progress * Math.PI * 6; // 3 full rotations for longer swirling path
// Radius decreases linearly for smooth inward movement
var baseRadius = 1000 * (1 - progress); // Linear decrease for steady approach to center
// Add gentle wave motion for swirling effect
var waveMotion = Math.sin(progress * Math.PI * 12) * (60 * (1 - progress)); // Gentle swirling motion
var currentRadius = baseRadius + waveMotion;
// Ensure minimum radius for playability at center
currentRadius = Math.max(currentRadius, 40);
// Calculate position on spiral path - interpolate towards hole position
var spiralX = centerX + Math.cos(spiralAngle) * currentRadius;
var spiralY = centerY + Math.sin(spiralAngle) * currentRadius;
// Gradually move towards hole position in final segment
var holeProgress = Math.max(0, (progress - 0.9) / 0.1); // Last 10% of track moves to hole
var x = spiralX + (holeX - spiralX) * holeProgress;
var y = spiralY + (holeY - spiralY) * holeProgress;
// Ensure the path stays within screen bounds with padding
x = Math.max(150, Math.min(1898, x));
y = Math.max(300, Math.min(2600, 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 = 5.0; // Increased track position spacing to prevent overlap
// 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 * 7.0; // Use consistent spacing to prevent overlap
// 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;
}
// Calculate position with anti-overlap adjustment near the hole
var baseX = point1.x + (point2.x - point1.x) * t;
var baseY = point1.y + (point2.y - point1.y) * t;
// Apply spacing adjustment to prevent overlap near hole
var progressToHole = trackPosition / trackPoints.length;
if (progressToHole > 0.8) {
// Near the hole (last 20% of track)
// Add slight offset based on ball's chain position to prevent stacking
var offsetAngle = ball.chainIndex * 0.3; // Small angular offset per ball
var offsetRadius = 15 * (progressToHole - 0.8) * 5; // Increase offset near hole
baseX += Math.cos(offsetAngle) * offsetRadius;
baseY += Math.sin(offsetAngle) * offsetRadius;
}
ball.targetX = baseX;
ball.targetY = baseY;
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 = 7.0; // Increased spacing to prevent overlap, especially near hole
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;
// Enforce minimum spacing to prevent overlap
ball.trackPosition = Math.max(ball.trackPosition, expectedPosition);
}
positionBallOnTrack(ball, ball.trackPosition);
}
}
// Check for matches
function checkMatches() {
var matches = [];
var currentColor = null;
var currentMatch = [];
// First, ensure all balls are positioned correctly on the track
for (var i = 0; i < chain.length; i++) {
var ball = chain[i];
positionBallOnTrack(ball, ball.trackPosition);
}
// Check for consecutive balls of the same color
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());
}
// Process matches with explosion effects
var totalMatches = matches.length;
var processedMatches = 0;
for (var m = 0; m < matches.length; m++) {
var match = matches[m];
var score = match.length * 10;
// Check for special balls before explosion
for (var b = 0; b < match.length; b++) {
var ball = match[b];
if (ball.isSpecial) {
handleSpecialBall(ball);
}
}
// Create explosion effect first
createExplosionEffect(match, function () {
processedMatches++;
// When all explosions are done, proceed with removal and gap closure
if (processedMatches === totalMatches) {
// Now remove all matched balls and close gaps
for (var matchIndex = 0; matchIndex < matches.length; matchIndex++) {
var currentMatch = matches[matchIndex];
var firstMatchIndex = chain.indexOf(currentMatch[0]);
var trackSpacing = 7.0; // Increased spacing to prevent overlap
var gapSize = currentMatch.length * trackSpacing; // Calculate gap size based on track spacing
// Remove matched balls
for (var b = 0; b < currentMatch.length; b++) {
var ball = currentMatch[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;
// Enforce minimum spacing to prevent overlap
currentBall.trackPosition = Math.max(currentBall.trackPosition, expectedPosition);
// Position the ball immediately to detect matches faster
positionBallOnTrack(currentBall, currentBall.trackPosition);
// Animate the ball to its new position smoothly
tween(currentBall, {
x: currentBall.targetX,
y: currentBall.targetY
}, {
duration: 200,
// Faster animation for quicker match detection
easing: tween.easeOut,
onFinish: function onFinish() {
// Check for new matches after gap closure animation completes
LK.setTimeout(function () {
checkMatches();
}, 50);
}
});
}
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);
}
});
}
// Handle case when no initial matches found but balls might touch after repositioning
if (matches.length === 0) {
// Check if balls of the same color are touching after repositioning
var hasRepositioned = false;
for (var i = 1; i < chain.length; i++) {
var prevBall = chain[i - 1];
var currBall = chain[i];
if (prevBall.color === currBall.color) {
// Check if these balls are close enough to be considered touching
var distance = Math.sqrt(Math.pow(currBall.x - prevBall.x, 2) + Math.pow(currBall.y - prevBall.y, 2));
if (distance < 60) {
// Balls are touching - create explosion effect then remove
createExplosionEffect([prevBall, currBall], function () {
// Remove the touching balls
var index1 = chain.indexOf(prevBall);
var index2 = chain.indexOf(currBall);
if (index1 > -1) {
chain.splice(index1, 1);
prevBall.destroy();
}
if (index2 > -1) {
var newIndex = chain.indexOf(currBall);
if (newIndex > -1) {
chain.splice(newIndex, 1);
currBall.destroy();
}
}
// Re-check for matches after removal
LK.setTimeout(function () {
checkMatches();
}, 100);
});
hasRepositioned = true;
break;
}
}
}
}
// Check win condition
if (chain.length === 0) {
gameWon = true;
level++;
LK.showYouWin();
}
}
// Create explosion effect for matched balls
function createExplosionEffect(balls, callback) {
var explosionCount = 0;
var totalExplosions = balls.length;
// Create explosion animation for each ball
for (var i = 0; i < balls.length; i++) {
var ball = balls[i];
// Scale up effect
tween(ball, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
explosionCount++;
if (explosionCount === totalExplosions) {
// All explosions complete, call callback
if (callback) callback();
}
}
});
// Add flash effect
tween(ball, {
tint: 0xFFFFFF
}, {
duration: 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(ball, {
tint: 0xFF4444
}, {
duration: 100,
easing: tween.easeInOut
});
}
});
}
}
// 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 the end of the track - near the shooter
hole.x = 1024;
hole.y = 1200; // Position hole closer to shooter
// 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);
// Create accelerate button
var accelerateBtn = new Text2('ACCELERATE', {
size: 50,
fill: 0xFFFFFF
});
accelerateBtn.anchor.set(1, 1);
accelerateBtn.x = -20;
accelerateBtn.y = -20;
LK.gui.bottomRight.addChild(accelerateBtn);
// Button press handler
accelerateBtn.down = function (x, y, obj) {
isAccelerating = !isAccelerating;
if (isAccelerating) {
accelerateBtn.setText('SLOW DOWN');
accelerateBtn.fill = 0xFF4444;
} else {
accelerateBtn.setText('ACCELERATE');
accelerateBtn.fill = 0xFFFFFF;
}
};
// 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 = 7.0; // Increased spacing to prevent overlap
// 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;
// Enforce minimum spacing to prevent overlap
chain[k].trackPosition = Math.max(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;
// Update accelerated speed to maintain ratio
acceleratedChainSpeed = normalChainSpeed * 4; // 4x faster when accelerating
if (isAccelerating) {
chainSpeed = acceleratedChainSpeed;
} else {
chainSpeed = normalChainSpeed;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -405,100 +405,165 @@
// Check last group
if (currentMatch.length >= 3) {
matches.push(currentMatch.slice());
}
- // Remove matches
+ // Process matches with explosion effects
+ var totalMatches = matches.length;
+ var processedMatches = 0;
for (var m = 0; m < matches.length; m++) {
var match = matches[m];
var score = match.length * 10;
- // Check for special balls
+ // Check for special balls before explosion
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 = 7.0; // Increased spacing to prevent overlap
- 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();
+ // Create explosion effect first
+ createExplosionEffect(match, function () {
+ processedMatches++;
+ // When all explosions are done, proceed with removal and gap closure
+ if (processedMatches === totalMatches) {
+ // Now remove all matched balls and close gaps
+ for (var matchIndex = 0; matchIndex < matches.length; matchIndex++) {
+ var currentMatch = matches[matchIndex];
+ var firstMatchIndex = chain.indexOf(currentMatch[0]);
+ var trackSpacing = 7.0; // Increased spacing to prevent overlap
+ var gapSize = currentMatch.length * trackSpacing; // Calculate gap size based on track spacing
+ // Remove matched balls
+ for (var b = 0; b < currentMatch.length; b++) {
+ var ball = currentMatch[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;
+ // Enforce minimum spacing to prevent overlap
+ currentBall.trackPosition = Math.max(currentBall.trackPosition, expectedPosition);
+ // Position the ball immediately to detect matches faster
+ positionBallOnTrack(currentBall, currentBall.trackPosition);
+ // Animate the ball to its new position smoothly
+ tween(currentBall, {
+ x: currentBall.targetX,
+ y: currentBall.targetY
+ }, {
+ duration: 200,
+ // Faster animation for quicker match detection
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // Check for new matches after gap closure animation completes
+ LK.setTimeout(function () {
+ checkMatches();
+ }, 50);
+ }
+ });
+ }
+ 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);
}
- }
- // 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;
- // Enforce minimum spacing to prevent overlap
- currentBall.trackPosition = Math.max(currentBall.trackPosition, expectedPosition);
- // Position the ball immediately to detect matches faster
- positionBallOnTrack(currentBall, currentBall.trackPosition);
- // Animate the ball to its new position smoothly
- tween(currentBall, {
- x: currentBall.targetX,
- y: currentBall.targetY
- }, {
- duration: 200,
- // Faster animation for quicker match detection
- 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);
+ });
}
- // Always check for new matches after gap closure, regardless of previous matches
- // This ensures balls disappear when they touch each other after gap closure
- if (matches.length > 0) {
- // After removing matches and closing gaps, check for new matches that may have formed
- // Use a timeout to allow animations to settle before checking
- LK.setTimeout(function () {
- checkMatches();
- }, 50); // Reduced timeout for faster response
- } else {
- // Even if no matches were found initially, check again after any repositioning
- // This handles cases where balls of the same color touch after repositioning
+ // Handle case when no initial matches found but balls might touch after repositioning
+ if (matches.length === 0) {
+ // Check if balls of the same color are touching after repositioning
var hasRepositioned = false;
for (var i = 1; i < chain.length; i++) {
var prevBall = chain[i - 1];
var currBall = chain[i];
if (prevBall.color === currBall.color) {
// Check if these balls are close enough to be considered touching
var distance = Math.sqrt(Math.pow(currBall.x - prevBall.x, 2) + Math.pow(currBall.y - prevBall.y, 2));
if (distance < 60) {
- // Balls are touching
+ // Balls are touching - create explosion effect then remove
+ createExplosionEffect([prevBall, currBall], function () {
+ // Remove the touching balls
+ var index1 = chain.indexOf(prevBall);
+ var index2 = chain.indexOf(currBall);
+ if (index1 > -1) {
+ chain.splice(index1, 1);
+ prevBall.destroy();
+ }
+ if (index2 > -1) {
+ var newIndex = chain.indexOf(currBall);
+ if (newIndex > -1) {
+ chain.splice(newIndex, 1);
+ currBall.destroy();
+ }
+ }
+ // Re-check for matches after removal
+ LK.setTimeout(function () {
+ checkMatches();
+ }, 100);
+ });
hasRepositioned = true;
break;
}
}
}
- if (hasRepositioned) {
- LK.setTimeout(function () {
- checkMatches();
- }, 50);
- }
}
// Check win condition
if (chain.length === 0) {
gameWon = true;
level++;
LK.showYouWin();
}
}
+// Create explosion effect for matched balls
+function createExplosionEffect(balls, callback) {
+ var explosionCount = 0;
+ var totalExplosions = balls.length;
+ // Create explosion animation for each ball
+ for (var i = 0; i < balls.length; i++) {
+ var ball = balls[i];
+ // Scale up effect
+ tween(ball, {
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 0.3
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ explosionCount++;
+ if (explosionCount === totalExplosions) {
+ // All explosions complete, call callback
+ if (callback) callback();
+ }
+ }
+ });
+ // Add flash effect
+ tween(ball, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 100,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(ball, {
+ tint: 0xFF4444
+ }, {
+ duration: 100,
+ easing: tween.easeInOut
+ });
+ }
+ });
+ }
+}
// Handle special ball effects
function handleSpecialBall(ball) {
if (ball.specialType === 'explosive') {
var _shakeEffect = function shakeEffect() {
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