User prompt
zincirde bazen siyah toplar oluyor bunu istemiyorum
User prompt
fire blast topu patlattıktan sonra zincir arasında boşluk kalıyor
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: 970
User prompt
rotadaki noktalar eşit aralıkta olmalı
User prompt
deliğe girmeden önce zincirin arkası önüne çok yaklaşıyor. arasındaki mesafeyi korumalı
User prompt
toplar deliğe yaklaşınca birbirlerinin üzerine biniyorlar. bunu çözelim. toplar asla üstüste gelmemeli
User prompt
zincirdeki topların arasındaki mesafe vurulmadıkça ve fire ball gelmedikçe hiç değişmemeli oyun sonuna kadar.
User prompt
rota noktaları deliğe doğru birbirine yaklaştığı için, toplar deliğe yaklaştığında yani rota sonunda birbirine giriyor bunu istemiyorum.
User prompt
arka arkaya bir çok top attığımda oyun kasmaya başlıyor
User prompt
topları arka arkaya atınca yine fps düşüyor
User prompt
ses gelmediği gibi, her top attığımda fps düşüyor
User prompt
ses hala gelmiyor
User prompt
ses gelmiyor
User prompt
topu her fırlattığımda topun ucunda ateş efekti ve sesi istiyorum ↪💡 Consider importing and using the following plugins: @upit/tween.v1
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: 842
User prompt
fire ball zincirde değdiği ilk topun sağında ve solunda 3'er topu yok etmeli ve blast yazısı sallanarak ekrana gelmeli belki ekran biraz sallansa (az efektli) güzel olur ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fire ball topları yok ettikten sonra zincir birleşmeli. tıpkı aynı renk topları yok ettikten sonra birleştiği gibi ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
beyaz top zincire eklenmesin. sadece görevini yapıp kaybolsun. bunun yanında oyuna turuncu ateş topu ekleyelim o da tıpkı beyaz top gibi 10 topta bir restgele gelsin. ve değdiği topun sağından ve solundan 3 topu patlatsın. ekranda da blast patlama efekti olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
atıcı bir bütün olarak obüs gibi gözüksün
User prompt
sıradaki top atıcının altında yazsın
User prompt
oyundan siyah topu kaldıralım. ve sadece atıcının topları yanıp sönerek büyüyüp küçülsün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in null' in or related to this line: 'tween(freezeCountdownDisplay, {' Line Number: 663
User prompt
beyaz top zincire girince hiç bir şey olmuyor. dediğim gibi = ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
beyaz top zincirdeki toplara değince zinciri durdurmalı 2 saniye boyunca ve bu 2 saniye ekranda büyükçe yazmalı. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bu özel toplar, vurucu(shooter) atılacak. her 10 topta bir rastgele beyaz top olsun.
/**** * 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', '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; ballGraphics.scaleX = 1.15; ballGraphics.scaleY = 1.15; // Add pulsing effect for white balls 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 }); } }); }; _pulseEffect(); } else if (color === 'fire') { self.isSpecial = true; self.specialType = 'fire_blast'; ballGraphics.alpha = 0.9; ballGraphics.scaleX = 1.2; ballGraphics.scaleY = 1.2; ballGraphics.tint = 0xFF4500; // Add intense pulsing effect for fire balls var _pulseEffect = function pulseEffect() { tween(ballGraphics, { scaleX: 1.4, scaleY: 1.4, tint: 0xFF0000 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1.2, scaleY: 1.2, tint: 0xFF4500 }, { duration: 400, easing: tween.easeInOut, onFinish: _pulseEffect }); } }); }; _pulseEffect(); } else { // 5% chance for special balls on regular colors 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); // Create howitzer base (larger and more prominent) var shooterBase = self.attachAsset('shooter', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 1.8 }); shooterBase.tint = 0x4a4a4a; // Darker military color // Add cannon barrel (longer and thicker for howitzer look) var barrel = self.attachAsset('track', { anchorX: 0, anchorY: 0.5, scaleX: 8, scaleY: 2.5, x: 0, y: 0 }); barrel.tint = 0x2a2a2a; // Very dark barrel color // Add muzzle brake at end of barrel var muzzleBrake = self.attachAsset('track', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 3.0, x: barrel.width * barrel.scaleX * 0.95, y: 0 }); muzzleBrake.tint = 0x1a1a1a; // Almost black for muzzle brake 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 pulsing and shining animation to current ball var _pulseCurrentBall = function pulseCurrentBall() { if (self.currentBall && self.currentBall.parent) { tween(self.currentBall, { scaleX: 1.2, scaleY: 1.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (self.currentBall && self.currentBall.parent) { tween(self.currentBall, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: _pulseCurrentBall }); } } }); } }; _pulseCurrentBall(); // Add shining effect with alpha animation var _shineCurrentBall = function shineCurrentBall() { if (self.currentBall && self.currentBall.parent) { tween(self.currentBall, { alpha: 0.7 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { if (self.currentBall && self.currentBall.parent) { tween(self.currentBall, { alpha: 1.0 }, { duration: 600, easing: tween.easeInOut, onFinish: _shineCurrentBall }); } } }); } }; _shineCurrentBall(); } // Generate next ball var colors = ['red', 'blue', 'green', 'yellow', 'purple']; 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)]; } 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; // Increment shot counter shotCounter++; self.loadBall(); // Create simple fire effect at muzzle (reduced complexity to improve FPS) var fireEffect = game.addChild(LK.getAsset('fire_effect', { anchorX: 0.5, anchorY: 0.5 })); // 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.scaleX = 0.8; fireEffect.scaleY = 0.8; fireEffect.alpha = 0.9; fireEffect.rotation = self.angle; // Animate fire effect - expand and fade out quickly tween(fireEffect, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { fireEffect.destroy(); } }); // 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 ****/ // 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); } } } // Create animated cosmic dust clouds with ellipse shapes only for (var i = 0; i < 12; i++) { var dust = game.addChild(LK.getAsset('hole', { anchorX: 0.5, anchorY: 0.5, scaleX: 2 + Math.random() * 3, scaleY: 1 + Math.random() * 2 })); dust.x = Math.random() * 2048; dust.y = Math.random() * 2732; dust.alpha = 0.03 + Math.random() * 0.05; dust.rotation = Math.random() * Math.PI * 2; // Realistic dust cloud colors var dustColors = [0x4B0082, 0x800080, 0x8B008B, 0x9400D3, 0x1E90FF, 0x00CED1, 0x483D8B]; dust.tint = dustColors[Math.floor(Math.random() * dustColors.length)]; // Add slow rotation animation var rotationSpeed = (Math.random() - 0.5) * 0.001; var dustRotation = dust.rotation; var _dustRotate = function dustRotate() { if (dust && dust.parent) { dustRotation += rotationSpeed; dust.rotation = dustRotation; LK.setTimeout(_dustRotate, 50); } }; _dustRotate(); } // Add some brighter nebula formations with ellipse shapes for (var i = 0; i < 6; i++) { var nebula = game.addChild(LK.getAsset('hole', { anchorX: 0.5, anchorY: 0.5, scaleX: 4 + Math.random() * 5, scaleY: 3 + Math.random() * 4 })); nebula.x = Math.random() * 2048; nebula.y = Math.random() * 2732; nebula.alpha = 0.08 + Math.random() * 0.12; nebula.rotation = Math.random() * Math.PI * 2; // More vibrant nebula colors var nebulaColors = [0xFF1493, 0x00FA9A, 0xFF4500, 0x9370DB, 0x00CED1, 0xFF69B4]; nebula.tint = nebulaColors[Math.floor(Math.random() * nebulaColors.length)]; // Add gentle pulsing effect var pulseDelay = Math.random() * 4000; LK.setTimeout(function () { var _nebulaEffect = function nebulaEffect() { if (nebula && nebula.parent) { tween(nebula, { alpha: nebula.alpha * 0.5, scaleX: nebula.scaleX * 1.1, scaleY: nebula.scaleY * 1.1 }, { duration: 2000 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (nebula && nebula.parent) { tween(nebula, { alpha: 0.08 + Math.random() * 0.12, scaleX: 4 + Math.random() * 5, scaleY: 3 + Math.random() * 4 }, { duration: 2000 + Math.random() * 1000, easing: tween.easeInOut, onFinish: _nebulaEffect }); } } }); } }; _nebulaEffect(); }, pulseDelay); } } // 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.0003; // Further decreased normal chain speed var normalChainSpeed = 0.0003; // Store normal speed 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 // 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--; // 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; } // 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()); } // 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 } 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 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 hasRepositioned = true; break; } } } if (hasRepositioned) { LK.setTimeout(function () { checkMatches(); }, 50); } } // 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 safety check for undefined trackPosition if (ball && ball.trackPosition !== undefined) { // 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 }); } // 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(); // Position hole at the end of the track - near the shooter hole.x = 1024; hole.y = 1200; // Position hole closer to shooter // 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); } }; // 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, 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 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 with pulsing animation 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); // Add pulsing animation to next ball if (!shooter.nextBall.isPulsing) { shooter.nextBall.isPulsing = true; var _pulseNextBall = function pulseNextBall() { if (shooter.nextBall && shooter.nextBall.parent) { tween(shooter.nextBall, { scaleX: 0.9, scaleY: 0.9 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (shooter.nextBall && shooter.nextBall.parent) { tween(shooter.nextBall, { scaleX: 0.8, scaleY: 0.8 }, { duration: 800, easing: tween.easeInOut, onFinish: _pulseNextBall }); } } }); } }; _pulseNextBall(); } } // 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
@@ -270,9 +270,9 @@
ball.y = self.y;
// Increment shot counter
shotCounter++;
self.loadBall();
- // Create fire effect at muzzle
+ // Create simple fire effect at muzzle (reduced complexity to improve FPS)
var fireEffect = game.addChild(LK.getAsset('fire_effect', {
anchorX: 0.5,
anchorY: 0.5
}));
@@ -280,61 +280,32 @@
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.scaleX = 0.5;
- fireEffect.scaleY = 0.5;
+ fireEffect.scaleX = 0.8;
+ fireEffect.scaleY = 0.8;
fireEffect.alpha = 0.9;
fireEffect.rotation = self.angle;
- // Animate fire effect - expand and fade out
+ // Animate fire effect - expand and fade out quickly
tween(fireEffect, {
- scaleX: 2.0,
- scaleY: 2.0,
+ scaleX: 1.5,
+ scaleY: 1.5,
alpha: 0
}, {
- duration: 200,
+ duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
fireEffect.destroy();
}
});
- // Add additional flame particles
- for (var p = 0; p < 3; p++) {
- var particle = game.addChild(LK.getAsset('fire_effect', {
- anchorX: 0.5,
- anchorY: 0.5
- }));
- // Position particles slightly spread around muzzle
- var spread = 20;
- particle.x = barrelEndX + (Math.random() - 0.5) * spread;
- particle.y = barrelEndY + (Math.random() - 0.5) * spread;
- particle.scaleX = 0.3 + Math.random() * 0.3;
- particle.scaleY = 0.3 + Math.random() * 0.3;
- particle.alpha = 0.7;
- particle.tint = p === 0 ? 0xFF4500 : p === 1 ? 0xFF6600 : 0xFFAA00;
- // Animate particles flying outward
- var particleAngle = self.angle + (Math.random() - 0.5) * 0.5;
- var particleSpeed = 3 + Math.random() * 2;
- var targetX = particle.x + Math.cos(particleAngle) * particleSpeed * 20;
- var targetY = particle.y + Math.sin(particleAngle) * particleSpeed * 20;
- tween(particle, {
- x: targetX,
- y: targetY,
- scaleX: 0.1,
- scaleY: 0.1,
- alpha: 0
- }, {
- duration: 300 + Math.random() * 200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- particle.destroy();
- }
- });
- }
// Set cooldown
self.shootCooldown = self.rapidFire ? 10 : 20;
// Play shoot sound immediately
- LK.getSound('shoot').play();
+ try {
+ LK.getSound('shoot').play();
+ } catch (e) {
+ console.log('Sound play error:', e);
+ }
return ball;
};
self.update = function () {
if (self.shootCooldown > 0) {
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