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 optimized fire effect only if under limit
if (activeFireEffects.length < maxFireEffects) {
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.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 150,
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 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);
}
if (fireEffectPool.length < 10) {
// Limit pool size
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);
}
}
}
// 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
// Fire effect optimization
var fireEffectPool = []; // Pool of reusable fire effects
var activeFireEffects = []; // Currently active fire effects
var maxFireEffects = 3; // Maximum concurrent fire effects
// 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) {
// Clean up fire effects when game ends
for (var i = 0; i < activeFireEffects.length; i++) {
if (activeFireEffects[i] && activeFireEffects[i].parent) {
activeFireEffects[i].parent.removeChild(activeFireEffects[i]);
}
}
activeFireEffects = [];
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,34 +270,32 @@
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();
- }
- });
+ // Create optimized fire effect only if under limit
+ if (activeFireEffects.length < maxFireEffects) {
+ 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.5,
+ scaleY: 1.5,
+ alpha: 0
+ }, {
+ duration: 150,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ returnFireEffect(fireEffect);
+ }
+ });
+ }
// Set cooldown
self.shootCooldown = self.rapidFire ? 10 : 20;
// Play shoot sound immediately
try {
@@ -345,8 +343,38 @@
/****
* Game Code
****/
+// Fire effect pool management
+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);
+ }
+ if (fireEffectPool.length < 10) {
+ // Limit pool size
+ 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];
@@ -573,8 +601,12 @@
// 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 = 3; // Maximum concurrent fire effects
// Create vortex track path
function createTrackPath() {
trackPoints = [];
var centerX = 1024;
@@ -1249,9 +1281,18 @@
}
};
// Main game loop
game.update = function () {
- if (gameWon || gameLost) return;
+ if (gameWon || gameLost) {
+ // Clean up fire effects when game ends
+ for (var i = 0; i < activeFireEffects.length; i++) {
+ if (activeFireEffects[i] && activeFireEffects[i].parent) {
+ activeFireEffects[i].parent.removeChild(activeFireEffects[i]);
+ }
+ }
+ activeFireEffects = [];
+ return;
+ }
// Update chain
updateChain();
// Update flying balls
for (var i = flyingBalls.length - 1; i >= 0; i--) {
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