User prompt
mevcut top görseli kendi etrafında dönsün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
zincirin anlık hızı score yazısının altında yazsın biraz küçük olsun
User prompt
skor alınca puanlar efektli bir şekilde, score yazısına uçsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ateş efekti şu anki asset ile uyumlu olsun tam ucundan çıkıyormuş gibi olsun. assetin 200x200 piksel
User prompt
shooter'ın ateş efektini hafifçe yukarıya taşıyalım. ve efekti 90 derece sağa çevirelim
User prompt
shooter'ın ateş efektini biraz daha yukarıya taşıyalım
User prompt
shooter'ın ateş efektini biraz daha yukarıya taşıyalım
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'trackPosition')' in or related to this line: 'ball.trackPosition -= gapSize;' Line Number: 918
User prompt
frozen sesi için ayrı bir ses asset ekle
User prompt
Please fix the bug: 'TypeError: Cannot set properties of null (setting 'whiteOverlay')' in or related to this line: 'freezeCountdownDisplay.whiteOverlay = whiteOverlay;' Line Number: 1099
User prompt
beyaz top frozen topu atılınca ekranın ortasında çıkan ve 2 saniye geri sayan yazı ekranın ortasında değil, ekranın altında biraz daha küçük yazıyla yazsın. ve oyun komple şeffaf beyaz efekt olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
frozen yazısı ekranın altında yazsın.
User prompt
oyunun en başına arayüz ekleyelim. oyuna başla diye ve oyun ekranına gameplay sesini kapatmak için buton ekle,
User prompt
fırlatılan her topun arkasına roket efekti ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
oyundaki tüm topların boyutunu %15 arttır
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'trackPosition')' in or related to this line: 'ball.trackPosition -= gapSize;' Line Number: 870
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'trackPosition')' in or related to this line: 'ball.trackPosition -= gapSize;' Line Number: 870
User prompt
frozen ball efekti kırmızı değil beyaz olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fire ball görüntüsü efeklerin üzerinde olsun, arkasında kalmasın. rengi daha açık olsun tıpkı bir göktaşı gibi. frozen ball efekti ise beyaz olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
alev topu ve buz topu efektleri daha fazla olsun ve daha büyük olsu ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fire ball giderken arkasında alevli animasyon olsun. frozen ball giderken arkasında beyaz buz efekti olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fire ball asset dosyasındaki resim gibi olsun
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'trackPosition')' in or related to this line: 'ball.trackPosition -= gapSize;' Line Number: 869
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'trackPosition')' in or related to this line: 'ball.trackPosition -= gapSize;' Line Number: 860
User prompt
oyunda game over sesi olsun. oyun gameplay müziği çalmıyor
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Ball = Container.expand(function (color) { var self = Container.call(this); // Safety check to prevent black balls if (color === 'black') { color = 'red'; // Default to red if black is passed } self.color = color; self.ballColors = ['red', 'blue', 'green', 'yellow', 'pink']; self.isSpecial = false; self.specialType = null; // 'explosive', 'freeze', 'rapid', 'white_freeze', 'black_destroyer' var ballGraphics = self.attachAsset('ball_' + color, { anchorX: 0.5, anchorY: 0.5 }); // Check for special ball types based on color if (color === 'white') { self.isSpecial = true; self.specialType = 'white_freeze'; ballGraphics.alpha = 0.9; } else if (color === 'fire') { self.isSpecial = true; self.specialType = 'fire_blast'; ballGraphics.alpha = 0.9; ballGraphics.tint = 0xFF4500; } else { // 5% chance for special balls on regular colors if (Math.random() < 0.05) { 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 if (self.specialType === 'explosive') { ballGraphics.tint = 0xFF4500; } else if (self.specialType === 'freeze') { ballGraphics.tint = 0x00FFFF; } else if (self.specialType === 'rapid') { ballGraphics.tint = 0xFFFF00; } } } 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); // Simple shooter image asset only var shooterGraphics = self.attachAsset('shooter', { anchorX: 0.5, anchorY: 0.5 }); 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 = -20; // Move ball closer to barrel self.currentBall.scaleX = 1.25; // 25% larger self.currentBall.scaleY = 1.25; // 25% larger self.addChild(self.currentBall); } // Generate next ball var colors = ['red', 'blue', 'green', 'yellow', 'pink']; var randomColor; // Check if it's time for a special ball (every 10 shots) if (shotCounter > 0 && shotCounter % 10 === 0) { // Randomly choose between white freeze ball or fire blast ball if (Math.random() < 0.5) { randomColor = 'white'; // White freeze ball } else { randomColor = 'fire'; // Fire blast ball } } else { randomColor = colors[Math.floor(Math.random() * colors.length)]; } // Safety check to ensure we never create black balls if (randomColor === 'black' || !randomColor) { randomColor = colors[Math.floor(Math.random() * colors.length)]; // Default to valid colors } 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); // Reset ball scale to normal size when firing ball.scaleX = 1.0; ball.scaleY = 1.0; // 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; // Increment shot counter shotCounter++; self.loadBall(); // Create optimized fire effect only if under limit and not in rapid fire if (activeFireEffects.length < maxFireEffects && !self.rapidFire) { var fireEffect = getFireEffect(); game.addChild(fireEffect); activeFireEffects.push(fireEffect); // Position fire effect at the end of the barrel var barrelEndX = self.x + Math.cos(self.angle) * 120; var barrelEndY = self.y + Math.sin(self.angle) * 120; fireEffect.x = barrelEndX; fireEffect.y = barrelEndY; fireEffect.rotation = self.angle; // Animate fire effect - expand and fade out quickly tween(fireEffect, { scaleX: 1.2, scaleY: 1.2, alpha: 0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { returnFireEffect(fireEffect); } }); } // Set cooldown self.shootCooldown = self.rapidFire ? 10 : 20; // Play shoot sound immediately try { LK.getSound('shoot').play(); } catch (e) { console.log('Sound play error:', e); } 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: 0x0a0a1a }); /**** * Game Code ****/ // Fire effect pool management function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function getFireEffect() { var fireEffect; if (fireEffectPool.length > 0) { fireEffect = fireEffectPool.pop(); fireEffect.alpha = 0.9; fireEffect.scaleX = 0.8; fireEffect.scaleY = 0.8; tween.stop(fireEffect); // Stop any ongoing animations } else { fireEffect = LK.getAsset('fire_effect', { anchorX: 0.5, anchorY: 0.5 }); } return fireEffect; } function returnFireEffect(fireEffect) { if (fireEffect && fireEffect.parent) { fireEffect.parent.removeChild(fireEffect); } var index = activeFireEffects.indexOf(fireEffect); if (index > -1) { activeFireEffects.splice(index, 1); } // Reset fire effect properties to prevent animation conflicts fireEffect.alpha = 0.9; fireEffect.scaleX = 0.8; fireEffect.scaleY = 0.8; fireEffect.rotation = 0; tween.stop(fireEffect); // Stop any ongoing animations if (fireEffectPool.length < maxPoolSize) { // Limit pool size to prevent memory buildup fireEffectPool.push(fireEffect); } } // Create dynamic space background with shooting stars function createSpaceBackground() { // Create complex starfield with realistic star colors and sizes (no colored squares) var starColors = [0xFFFFFF, 0xFFE4B5, 0xFFB347, 0x87CEEB, 0xF0F8FF, 0xFFF8DC]; var starSizes = [0.5, 0.8, 1.2, 1.8, 2.5, 3.2]; for (var layer = 0; layer < 5; layer++) { var numStars = layer === 0 ? 200 : layer === 1 ? 150 : layer === 2 ? 100 : layer === 3 ? 60 : 30; var baseAlpha = layer === 0 ? 0.2 : layer === 1 ? 0.4 : layer === 2 ? 0.6 : layer === 3 ? 0.8 : 1.0; for (var i = 0; i < numStars; i++) { var starSize = starSizes[Math.floor(Math.random() * starSizes.length)]; var star = game.addChild(LK.getAsset('track', { anchorX: 0.5, anchorY: 0.5, scaleX: starSize * 0.1, scaleY: starSize * 0.1 })); star.x = Math.random() * 2048; star.y = Math.random() * 2732; star.alpha = baseAlpha + Math.random() * 0.3; star.tint = starColors[Math.floor(Math.random() * starColors.length)]; // Add realistic twinkling based on star size and distance if (layer >= 2 && Math.random() < 0.4) { var twinkleDelay = Math.random() * 3000; LK.setTimeout(function () { var _twinkleEffect = function twinkleEffect() { if (star && star.parent) { tween(star, { alpha: star.alpha * 0.2 }, { duration: 1000 + Math.random() * 800, easing: tween.easeInOut, onFinish: function onFinish() { if (star && star.parent) { tween(star, { alpha: baseAlpha + Math.random() * 0.3 }, { duration: 1000 + Math.random() * 800, easing: tween.easeInOut, onFinish: _twinkleEffect }); } } }); } }; _twinkleEffect(); }, twinkleDelay); } } } // Cosmic dust clouds removed - only keep the game hole // Nebula formations removed - only keep the game hole } // Initialize space background createSpaceBackground(); // Create shooting star function function createShootingStar() { var shootingStar = game.addChild(LK.getAsset('track', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.1 })); // Random starting position from top or sides var startSide = Math.floor(Math.random() * 3); // 0 = top, 1 = left, 2 = right if (startSide === 0) { shootingStar.x = Math.random() * 2048; shootingStar.y = -50; } else if (startSide === 1) { shootingStar.x = -50; shootingStar.y = Math.random() * 1500; } else { shootingStar.x = 2098; shootingStar.y = Math.random() * 1500; } // Set shooting star properties shootingStar.alpha = 0.8; shootingStar.tint = 0xFFFFFF; shootingStar.rotation = Math.random() * Math.PI * 2; // Create trail effect with multiple small stars var trailStars = []; for (var i = 0; i < 5; i++) { var trailStar = game.addChild(LK.getAsset('track', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1 - i * 0.015, scaleY: 0.05 - i * 0.008 })); trailStar.x = shootingStar.x; trailStar.y = shootingStar.y; trailStar.alpha = 0.6 - i * 0.1; trailStar.tint = 0xFFFFFF; trailStar.rotation = shootingStar.rotation; trailStars.push(trailStar); } // Calculate movement direction var targetX = Math.random() * 2048; var targetY = 2732 + 200; var deltaX = targetX - shootingStar.x; var deltaY = targetY - shootingStar.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); var speed = 15 + Math.random() * 10; var vx = deltaX / distance * speed; var vy = deltaY / distance * speed; // Animate shooting star var _moveShootingStar = function moveShootingStar() { if (shootingStar && shootingStar.parent) { shootingStar.x += vx; shootingStar.y += vy; // Update trail positions for (var i = trailStars.length - 1; i > 0; i--) { if (trailStars[i] && trailStars[i].parent) { trailStars[i].x = trailStars[i - 1].x; trailStars[i].y = trailStars[i - 1].y; } } if (trailStars[0] && trailStars[0].parent) { trailStars[0].x = shootingStar.x; trailStars[0].y = shootingStar.y; } // Check if off screen if (shootingStar.x < -100 || shootingStar.x > 2148 || shootingStar.y > 2832) { shootingStar.destroy(); for (var i = 0; i < trailStars.length; i++) { if (trailStars[i] && trailStars[i].parent) { trailStars[i].destroy(); } } return; } LK.setTimeout(_moveShootingStar, 16); } }; _moveShootingStar(); } // Start shooting star timer (every 10 seconds) var shootingStarTimer = LK.setInterval(createShootingStar, 10000); // Game variables var chain = []; var flyingBalls = []; var shooter; var trackPoints = []; var chainSpeed = 0.004; // Increased initial chain speed for faster start var normalChainSpeed = 0.004; // Store normal speed - increased from 0.0003 var fastChainSpeed = 0.002; // Fast chain speed - slower than before var veryFastChainSpeed = 0.006; // Very fast chain speed - slower than before var speedLevel = 0; // 0 = normal, 1 = fast, 2 = very fast var chainFrozen = false; var freezeTimer = 0; var freezeCountdownDisplay = null; var level = 1; var gameWon = false; var gameLost = false; // Score multiplier system var scoreMultipliers = [1.0, 1.5, 2.0]; // normal, fast, very fast var pointsDisplays = []; // Array to track active point displays var shotCounter = 0; // Counter to track shots fired // Fire effect optimization var fireEffectPool = []; // Pool of reusable fire effects var activeFireEffects = []; // Currently active fire effects var maxFireEffects = 2; // Reduced maximum concurrent fire effects var maxPoolSize = 3; // Limit pool size to prevent memory buildup // 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 var targetSpacing = 7.0; // Target distance between consecutive points var currentDistance = 0; // Generate initial spiral path points (more densely packed) var tempPoints = []; var densityMultiplier = 3; // Create 3x more points initially for smoother curves for (var i = 0; i < segments * densityMultiplier; i++) { var progress = i / (segments * densityMultiplier); // 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)); tempPoints.push({ x: x, y: y }); } // Now resample the path to ensure equal spacing trackPoints.push(tempPoints[0]); // Add first point currentDistance = 0; for (var i = 1; i < tempPoints.length; i++) { var prevPoint = tempPoints[i - 1]; var currPoint = tempPoints[i]; var segmentLength = Math.sqrt(Math.pow(currPoint.x - prevPoint.x, 2) + Math.pow(currPoint.y - prevPoint.y, 2)); currentDistance += segmentLength; // Add point when we've traveled the target spacing distance if (currentDistance >= targetSpacing) { // Interpolate to get exact position at target spacing var excess = currentDistance - targetSpacing; var ratio = excess / segmentLength; var adjustedX = currPoint.x - (currPoint.x - prevPoint.x) * ratio; var adjustedY = currPoint.y - (currPoint.y - prevPoint.y) * ratio; trackPoints.push({ x: adjustedX, y: adjustedY }); currentDistance = excess; // Carry over the excess distance } } // 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(); // Helper function to get safe color that won't create 3+ consecutive function getSafeColor(colors, lastColors) { var availableColors = []; // Find colors that won't create 3 consecutive for (var c = 0; c < colors.length; c++) { var testColor = colors[c]; var wouldCreate3 = false; // Check if this color would create 3 consecutive if (lastColors.length >= 2 && lastColors[lastColors.length - 1] === testColor && lastColors[lastColors.length - 2] === testColor) { wouldCreate3 = true; } if (!wouldCreate3) { availableColors.push(testColor); } } // If all colors would create 3 consecutive (shouldn't happen), return any color except the last one if (availableColors.length === 0) { for (var c = 0; c < colors.length; c++) { if (lastColors.length === 0 || colors[c] !== lastColors[lastColors.length - 1]) { availableColors.push(colors[c]); } } } // Return random color from available safe colors return availableColors[Math.floor(Math.random() * availableColors.length)]; } // Create initial chain function createChain() { chain = []; var chainLength = 15 + level * 5; var colors = ['red', 'blue', 'green', 'yellow', 'pink']; var ballSpacing = 60; // Space between balls - balls touch each other (increased for bigger balls) var trackSpacing = 6.0; // Increased track position spacing to prevent overlap var lastColors = []; // Track last few colors to prevent 3+ consecutive // Ensure better color distribution by cycling through colors for (var i = 0; i < chainLength; i++) { var color; // Use safe color selection to prevent 3+ consecutive if (i < 2) { // For first two balls, use any color if (i % 8 < 5) { // First 5 of every 8 balls use sequential colors var colorIndex = i % colors.length; color = colors[colorIndex]; } else { // Last 3 of every 8 balls use random colors var colorIndex = Math.floor(Math.random() * colors.length); color = colors[colorIndex]; } } else { // For subsequent balls, ensure no 3+ consecutive color = getSafeColor(colors, lastColors); } // Safety check to ensure we never create black balls if (color === 'black' || !color) { color = colors[i % colors.length]; // Default to cycling through valid colors } 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); // Update lastColors array (keep only last 2 colors for checking) lastColors.push(color); if (lastColors.length > 2) { lastColors.shift(); // Remove oldest color, keep only last 2 } } } // 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--; // Update freeze countdown display if (freezeCountdownDisplay) { var secondsLeft = Math.ceil(freezeTimer / 60); freezeCountdownDisplay.setText('FROZEN: ' + secondsLeft); // Add pulsing effect each second if (freezeTimer % 60 === 0) { tween(freezeCountdownDisplay, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { if (freezeCountdownDisplay) { tween(freezeCountdownDisplay, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeIn }); } } }); } } if (freezeTimer <= 0) { chainFrozen = false; // Remove countdown display if (freezeCountdownDisplay) { freezeCountdownDisplay.destroy(); freezeCountdownDisplay = null; } // 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; } // Detect gaps in the chain by checking distances between consecutive balls var hasGap = false; var gapStartIndex = -1; var gapEndIndex = -1; var trackSpacing = 7.0; // Standard spacing between balls var maxAllowedGap = trackSpacing * 2; // Gap threshold for (var i = 0; i < chain.length - 1; i++) { var currentBall = chain[i]; var nextBall = chain[i + 1]; var gapDistance = nextBall.trackPosition - currentBall.trackPosition; if (gapDistance > maxAllowedGap) { hasGap = true; gapStartIndex = i; gapEndIndex = i + 1; break; } } if (hasGap) { // Gap detected - back part waits completely, front part moves forward to close gap for (var i = 0; i < chain.length; i++) { var ball = chain[i]; if (i <= gapStartIndex) { // Front part (before gap) - move forward normally to close gap ball.trackPosition += chainSpeed; // Check if reached hole (vortex center) if (ball.trackPosition >= trackPoints.length - 1) { gameLost = true; LK.getSound('gameover').play(); LK.showGameOver(); return; } } else { // Back part (after gap) - wait completely, don't move at all // Don't move the back part at all } } } else { // No gap - move all balls forward normally together 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.getSound('gameover').play(); LK.showGameOver(); return; } } } // Maintain equal spacing between balls for vortex movement with collision avoidance 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 enforce forward spacing when gap is closing or normal movement var currentGap = ball.trackPosition - previousBall.trackPosition; if (currentGap < trackSpacing * 0.8) { // Gap is almost closed, enforce proper spacing ball.trackPosition = Math.max(ball.trackPosition, expectedPosition); } else if (currentGap > maxAllowedGap) { // Large gap detected, allow back part to move forward freely // Don't enforce spacing yet } else { // Normal spacing enforcement ball.trackPosition = Math.max(ball.trackPosition, expectedPosition); } } positionBallOnTrack(ball, ball.trackPosition); } // Additional collision avoidance pass to prevent balls from overlapping for (var i = 0; i < chain.length; i++) { var ball = chain[i]; for (var j = i + 1; j < chain.length; j++) { var otherBall = chain[j]; var dx = ball.x - otherBall.x; var dy = ball.y - otherBall.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = 60; // Minimum distance between ball centers (increased for 20% larger balls) if (distance < minDistance && distance > 0) { // Calculate separation needed var separation = minDistance - distance; var separationX = dx / distance * separation * 0.5; var separationY = dy / distance * separation * 0.5; // Move balls apart by adjusting their track positions var trackDelta = separation / trackSpacing; if (i > 0) { // Move current ball back ball.trackPosition -= trackDelta * 0.5; // Reposition on track positionBallOnTrack(ball, ball.trackPosition); } if (j < chain.length - 1) { // Move other ball forward otherBall.trackPosition += trackDelta * 0.5; // Reposition on track positionBallOnTrack(otherBall, otherBall.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()); } // Remove matches for (var m = 0; m < matches.length; m++) { var match = matches[m]; var baseScore = match.length * 10; var multiplier = scoreMultipliers[speedLevel]; var score = Math.floor(baseScore * multiplier); // Calculate display position (center of the match) var displayX = 0; var displayY = 0; for (var b = 0; b < match.length; b++) { displayX += match[b].x; displayY += match[b].y; } displayX /= match.length; displayY /= match.length; // Display flashing points displayPoints(score, displayX, displayY); // 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 = 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(); } } // 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 } // Always perform an additional check for consecutive same-color balls after any gap closure // This ensures that balls of the same color that become adjacent are immediately detected var foundConsecutiveColors = false; for (var i = 0; i < chain.length - 1; i++) { var currentBall = chain[i]; var nextBall = chain[i + 1]; if (currentBall.color === nextBall.color) { // Found consecutive same-color balls, check for a group of 3 or more var consecutiveCount = 1; var groupStart = i; // Count consecutive balls of the same color starting from current position for (var j = i + 1; j < chain.length && chain[j].color === currentBall.color; j++) { consecutiveCount++; } // If we have 3 or more consecutive balls of the same color, mark for immediate removal if (consecutiveCount >= 3) { foundConsecutiveColors = true; break; } } } // If consecutive same-color balls were found, immediately check matches again if (foundConsecutiveColors) { LK.setTimeout(function () { checkMatches(); }, 10); // Very short timeout for immediate response } // Check win condition if (chain.length === 0) { gameWon = true; level++; LK.showYouWin(); } } // Display flashing points function displayPoints(points, x, y) { var pointsText = new Text2('+' + points, { size: 80, fill: 0xFFFF00 }); pointsText.anchor.set(0.5, 0.5); pointsText.x = x; pointsText.y = y; pointsText.alpha = 1.0; pointsText.scaleX = 0.5; pointsText.scaleY = 0.5; game.addChild(pointsText); pointsDisplays.push(pointsText); // Animate the points display tween(pointsText, { scaleX: 1.2, scaleY: 1.2, y: y - 100 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { tween(pointsText, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { pointsText.destroy(); var index = pointsDisplays.indexOf(pointsText); if (index > -1) { pointsDisplays.splice(index, 1); } } }); } }); } // 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); } else if (ball.specialType === 'white_freeze') { chainFrozen = true; freezeTimer = 120; // 2 seconds at 60fps LK.effects.flashScreen(0xffffff, 500); // Create freeze countdown display if (freezeCountdownDisplay) { freezeCountdownDisplay.destroy(); } freezeCountdownDisplay = new Text2('FROZEN: 2', { size: 150, fill: 0x00FFFF }); freezeCountdownDisplay.anchor.set(0.5, 0.5); LK.gui.center.addChild(freezeCountdownDisplay); // Add pulsing animation to the countdown display tween(freezeCountdownDisplay, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(freezeCountdownDisplay, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeInOut }); } }); // 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 === 'fire_blast') { // Fire blast effect - explode 3 balls on each side var ballIndex = chain.indexOf(ball); var blastRadius = 3; var toRemove = []; // Get 3 balls to the left and 3 balls to the right for (var i = Math.max(0, ballIndex - blastRadius); i < Math.min(chain.length, ballIndex + blastRadius + 1); i++) { if (chain[i] !== ball) { toRemove.push(chain[i]); } } // Store the first index of the blast to know where the gap starts var firstBlastIndex = Math.max(0, ballIndex - blastRadius); var trackSpacing = 7.0; // Track spacing to prevent overlap var gapSize = toRemove.length * trackSpacing; // Calculate gap size based on track spacing // Remove blasted balls for (var i = 0; i < toRemove.length; i++) { var index = chain.indexOf(toRemove[i]); if (index > -1) { chain.splice(index, 1); toRemove[i].destroy(); } } // Close the gap by moving all balls after the removed section forward for (var i = firstBlastIndex; i < chain.length; i++) { var ball = chain[i]; // Add comprehensive safety check for ball existence and trackPosition if (ball && _typeof(ball) === 'object' && ball.trackPosition !== undefined) { // Move the ball's track position forward to close the gap ball.trackPosition -= gapSize; } else if (ball && _typeof(ball) === 'object' && ball.trackPosition === undefined) { // Initialize trackPosition if undefined ball.trackPosition = i * 7.0; // Use index-based positioning ball.trackPosition -= gapSize; } else if (!ball || _typeof(ball) !== 'object') { // Skip invalid ball entries continue; } } // Comprehensive re-spacing to ensure no gaps remain // Start from the beginning and ensure each ball has proper spacing for (var i = 0; i < chain.length; i++) { var ball = chain[i]; if (i === 0) { // First ball keeps its current position as reference continue; } var previousBall = chain[i - 1]; var expectedPosition = previousBall.trackPosition + trackSpacing; // Always enforce proper spacing, moving balls forward to close any gaps ball.trackPosition = expectedPosition; // Position the ball immediately to detect matches faster positionBallOnTrack(ball, ball.trackPosition); // Animate the ball to its new position smoothly tween(ball, { x: ball.targetX, y: ball.targetY }, { duration: 200, // Faster animation for quicker match detection easing: tween.easeOut }); } // Immediately check for any consecutive same-color balls after repositioning var foundImmediateMatch = false; for (var i = 0; i < chain.length - 2; i++) { if (chain[i].color === chain[i + 1].color && chain[i + 1].color === chain[i + 2].color) { foundImmediateMatch = true; break; } } if (foundImmediateMatch) { // Trigger immediate match check LK.setTimeout(function () { checkMatches(); }, 5); // Very fast response for fire blast } // Create blast explosion effect LK.effects.flashScreen(0xFF4500, 500); // Add screen shake effect var originalX = game.x; var originalY = game.y; var shakeIntensity = 15; var shakeDuration = 400; var shakeTimer = 0; 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; } }; _shakeEffect(); // Create blast text effect with swinging animation var blastText = new Text2('BLAST!', { size: 120, fill: 0xFF4500 }); blastText.anchor.set(0.5, 0.5); blastText.x = ball.x; blastText.y = ball.y; blastText.scaleX = 0.5; blastText.scaleY = 0.5; blastText.rotation = -0.3; // Start with slight rotation game.addChild(blastText); // Animate blast text with swinging motion tween(blastText, { scaleX: 2.0, scaleY: 2.0, alpha: 0.8, rotation: 0.3 // Swing to the other side }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(blastText, { alpha: 0, scaleX: 1.5, scaleY: 1.5, rotation: -0.2 // Swing back slightly }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { blastText.destroy(); } }); } }); // Check for new matches after gap closure LK.setTimeout(function () { checkMatches(); }, 250); // Allow time for animations to settle } 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(); // Start gameplay music LK.playMusic('Gameplay'); // Position hole at the end of the track - near the shooter hole.x = 1024; hole.y = 1200; // Position hole closer to shooter // Add breathing and rotation effects to the hole var _holeBreathingEffect = function holeBreathingEffect() { if (hole && hole.parent) { // Breathing effect - scale up and down tween(hole, { scaleX: 1.2, scaleY: 1.2 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { if (hole && hole.parent) { tween(hole, { scaleX: 1.0, scaleY: 1.0 }, { duration: 1500, easing: tween.easeInOut, onFinish: _holeBreathingEffect }); } } }); } }; // Start breathing effect _holeBreathingEffect(); // Continuous rotation effect var _holeRotationEffect = function holeRotationEffect() { if (hole && hole.parent) { hole.rotation += 0.02; // Rotate around its own axis LK.setTimeout(_holeRotationEffect, 16); // 60fps rotation } }; // Start rotation effect _holeRotationEffect(); // 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('NORMAL', { 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) { speedLevel = (speedLevel + 1) % 3; // Cycle through 0, 1, 2 if (speedLevel === 0) { accelerateBtn.setText('NORMAL'); accelerateBtn.fill = 0xFFFFFF; } else if (speedLevel === 1) { accelerateBtn.setText('FAST'); accelerateBtn.fill = 0xFFFF00; } else { accelerateBtn.setText('VERY FAST'); accelerateBtn.fill = 0xFF4444; } }; // Game input game.down = function (x, y, obj) { shooter.aimAt(x, y); var ball = shooter.shoot(); if (ball) { flyingBalls.push(ball); game.addChild(ball); } }; // Mouse move handler to make shooter follow mouse game.move = function (x, y, obj) { shooter.aimAt(x, y); }; // Main game loop game.update = function () { if (gameWon || gameLost) { // Clean up fire effects when game ends for (var i = 0; i < activeFireEffects.length; i++) { if (activeFireEffects[i] && activeFireEffects[i].parent) { tween.stop(activeFireEffects[i]); // Stop animations activeFireEffects[i].parent.removeChild(activeFireEffects[i]); } } activeFireEffects = []; // Clean up flying balls for (var i = 0; i < flyingBalls.length; i++) { flyingBalls[i].destroy(); } flyingBalls = []; return; } // Update chain updateChain(); // Update flying balls - limit processing if too many var maxFlyingBalls = 5; // Prevent too many balls in flight if (flyingBalls.length > maxFlyingBalls) { // Remove oldest balls if too many in flight var oldestBall = flyingBalls.shift(); oldestBall.destroy(); } 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 - optimized detection var inserted = false; var collisionIndex = -1; var ballRadius = 30; // Approximate ball radius (increased for 20% larger balls) // Only check balls within reasonable distance for (var j = 0; j < chain.length; j++) { var chainBall = chain[j]; // Quick distance check before expensive intersects call var dx = ball.x - chainBall.x; var dy = ball.y - chainBall.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < ballRadius * 2 && ball.intersects(chainBall)) { collisionIndex = j; break; } } // If collision detected, handle special balls or insert into chain if (collisionIndex !== -1) { // Check if the flying ball is a white ball - trigger freeze effect and disappear if (ball.color === 'white' && ball.isSpecial && ball.specialType === 'white_freeze') { handleSpecialBall(ball); ball.destroy(); flyingBalls.splice(i, 1); inserted = true; } else if (ball.color === 'fire' && ball.isSpecial && ball.specialType === 'fire_blast') { // Fire ball - trigger blast effect on the first ball it hits var hitBall = chain[collisionIndex]; // Temporarily set the hit ball as the fire ball for the blast effect hitBall.isSpecial = true; hitBall.specialType = 'fire_blast'; handleSpecialBall(hitBall); ball.destroy(); flyingBalls.splice(i, 1); inserted = true; } else { // Regular ball - insert into chain with collision avoidance var insertIndex = collisionIndex + 1; var trackSpacing = 7.0; // Increased spacing to prevent overlap // Create more space by pushing balls further back var pushBackDistance = trackSpacing * 1.5; // Extra space to prevent overlap // Adjust track positions for all balls after insertion point for (var k = insertIndex; k < chain.length; k++) { chain[k].trackPosition += pushBackDistance; // 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 with extra spacing for (var k = insertIndex + 1; k < chain.length; k++) { var expectedPosition = chain[k - 1].trackPosition + trackSpacing; // Enforce minimum spacing to prevent overlap with buffer chain[k].trackPosition = Math.max(chain[k].trackPosition, expectedPosition + 1.0); } // Additional pass to ensure no overlapping after insertion for (var k = 0; k < chain.length - 1; k++) { var currentBall = chain[k]; var nextBall = chain[k + 1]; var dx = currentBall.x - nextBall.x; var dy = currentBall.y - nextBall.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 60) { // Push next ball further back nextBall.trackPosition += (60 - distance) / trackSpacing; positionBallOnTrack(nextBall, nextBall.trackPosition); } } 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 with consistent size 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 (slower increase) normalChainSpeed += 0.00003; // Update other speeds to maintain ratios fastChainSpeed = normalChainSpeed * 6.67; // Maintain same ratio as before veryFastChainSpeed = normalChainSpeed * 20; // Maintain same ratio as before if (speedLevel === 0) { chainSpeed = normalChainSpeed; } else if (speedLevel === 1) { chainSpeed = fastChainSpeed; } else { chainSpeed = veryFastChainSpeed; } };
===================================================================
--- original.js
+++ change.js
@@ -214,8 +214,16 @@
/****
* Game Code
****/
// Fire effect pool management
+function _typeof(o) {
+ "@babel/helpers - typeof";
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
+ return typeof o;
+ } : function (o) {
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
+ }, _typeof(o);
+}
function getFireEffect() {
var fireEffect;
if (fireEffectPool.length > 0) {
fireEffect = fireEffectPool.pop();
@@ -1064,16 +1072,19 @@
}
// Close the gap by moving all balls after the removed section forward
for (var i = firstBlastIndex; i < chain.length; i++) {
var ball = chain[i];
- // Add safety check for undefined ball and trackPosition
- if (ball && ball.trackPosition !== undefined) {
+ // Add comprehensive safety check for ball existence and trackPosition
+ if (ball && _typeof(ball) === 'object' && ball.trackPosition !== undefined) {
// Move the ball's track position forward to close the gap
ball.trackPosition -= gapSize;
- } else if (ball && ball.trackPosition === undefined) {
+ } else if (ball && _typeof(ball) === 'object' && ball.trackPosition === undefined) {
// Initialize trackPosition if undefined
ball.trackPosition = i * 7.0; // Use index-based positioning
ball.trackPosition -= gapSize;
+ } else if (!ball || _typeof(ball) !== 'object') {
+ // Skip invalid ball entries
+ continue;
}
}
// Comprehensive re-spacing to ensure no gaps remain
// Start from the beginning and ensure each ball has proper spacing
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