User prompt
add combos and make the trail bigger, make the time limit 150 sec. and make it at the bottom make it say tap the cubes to get points, ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a trail behind the player when they moce, and addd the enemys back ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
remove the menu and make the volume slider at the bottom left, witht he slider going up. so start the game instantly after 2 sec ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
i still cant click them! and where it says health, make it say, tap or swipe into the cubes for points
User prompt
make the buttons bigger and clickable eith the mouse
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var musicVolume = storage.get('musicVolume', 1.0);' Line Number: 332 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make the play and settings button accutally be able to play and to go to settings, so i can click them, in settings there should be music volume ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the buttons work, and make background music, and so the cube i move has a deley so if i click somewhere it goes there smoothly ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var localPos = self.toLocal(obj.parent.toGlobal(obj.position));' Line Number: 82
User prompt
can you add sounds effects and particles, and a menu when you ttart the game with play and setting for enemy stuff, make the enemys try to run away tho ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make it so i have to drag and like run into them to kill them
Code edit (1 edits merged)
Please save this source code
User prompt
Zombie Siege Defense
Initial prompt
make a zombie wave shooter, take minimum 1.5 min
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var FastZombie = Container.expand(function () {
	var self = Container.call(this);
	var zombieGraphics = self.attachAsset('fastZombie', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.health = 1;
	self.maxHealth = 1;
	self.speed = 3;
	self.points = 15;
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		if (player) {
			self.lastX = self.x;
			self.lastY = self.y;
			var dx = player.x - self.x;
			var dy = player.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance > 0) {
				// Chase player
				self.x += dx / distance * self.speed * zombieSpeedMultiplier;
				self.y += dy / distance * self.speed * zombieSpeedMultiplier;
			}
		}
	};
	return self;
});
var Menu = Container.expand(function () {
	var self = Container.call(this);
	self.interactive = true;
	var playButton = self.attachAsset('menuButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: -100,
		scaleX: 1.5,
		scaleY: 1.5
	});
	var playText = new Text2('PLAY', {
		size: 60,
		fill: 0xFFFFFF
	});
	playText.anchor.set(0.5, 0.5);
	playText.y = -100;
	self.addChild(playText);
	var settingsButton = self.attachAsset('settingButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 50,
		scaleX: 1.8,
		scaleY: 1.8
	});
	var settingsText = new Text2('SETTINGS', {
		size: 40,
		fill: 0xFFFFFF
	});
	settingsText.anchor.set(0.5, 0.5);
	settingsText.y = 50;
	self.addChild(settingsText);
	self.down = function (x, y, obj) {
		// Use the x,y parameters directly instead of obj.parent.toGlobal
		var localPos = self.toLocal({
			x: x,
			y: y
		});
		if (localPos.y > -175 && localPos.y < -25) {
			LK.getSound('menuClick').play();
			startGame();
		} else if (localPos.y > -22 && localPos.y < 122) {
			LK.getSound('menuClick').play();
			showSettings();
		}
	};
	return self;
});
var Particle = Container.expand(function () {
	var self = Container.call(this);
	var particleGraphics = self.attachAsset('particle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.vx = 0;
	self.vy = 0;
	self.life = 60;
	self.maxLife = 60;
	self.update = function () {
		self.x += self.vx;
		self.y += self.vy;
		self.life--;
		self.alpha = self.life / self.maxLife;
		if (self.life <= 0) {
			self.destroy();
		}
	};
	return self;
});
var Player = Container.expand(function () {
	var self = Container.call(this);
	var playerGraphics = self.attachAsset('player', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.health = 100;
	self.maxHealth = 100;
	self.lastCollidedZombies = [];
	return self;
});
var SettingsMenu = Container.expand(function () {
	var self = Container.call(this);
	self.interactive = true;
	var titleText = new Text2('SETTINGS', {
		size: 80,
		fill: 0xFFFFFF
	});
	titleText.anchor.set(0.5, 0.5);
	titleText.y = -300;
	self.addChild(titleText);
	var musicVolumeText = new Text2('Music Volume: ' + Math.round(musicVolume * 100) + '%', {
		size: 50,
		fill: 0xFFFFFF
	});
	musicVolumeText.anchor.set(0.5, 0.5);
	musicVolumeText.y = -200;
	self.addChild(musicVolumeText);
	var volumeUpButton = self.attachAsset('settingButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -200,
		y: -150,
		scaleX: 1.4,
		scaleY: 1.4
	});
	var volumeUpText = new Text2('+', {
		size: 60,
		fill: 0xFFFFFF
	});
	volumeUpText.anchor.set(0.5, 0.5);
	volumeUpText.x = -200;
	volumeUpText.y = -150;
	self.addChild(volumeUpText);
	var volumeDownButton = self.attachAsset('settingButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 200,
		y: -150,
		scaleX: 1.4,
		scaleY: 1.4
	});
	var volumeDownText = new Text2('-', {
		size: 60,
		fill: 0xFFFFFF
	});
	volumeDownText.anchor.set(0.5, 0.5);
	volumeDownText.x = 200;
	volumeDownText.y = -150;
	self.addChild(volumeDownText);
	var zombieSpeedText = new Text2('Zombie Speed: ' + zombieSpeedMultiplier, {
		size: 50,
		fill: 0xFFFFFF
	});
	zombieSpeedText.anchor.set(0.5, 0.5);
	zombieSpeedText.y = -50;
	self.addChild(zombieSpeedText);
	var speedUpButton = self.attachAsset('settingButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: -200,
		y: 0,
		scaleX: 1.4,
		scaleY: 1.4
	});
	var speedUpText = new Text2('+', {
		size: 60,
		fill: 0xFFFFFF
	});
	speedUpText.anchor.set(0.5, 0.5);
	speedUpText.x = -200;
	speedUpText.y = 0;
	self.addChild(speedUpText);
	var speedDownButton = self.attachAsset('settingButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 200,
		y: 0,
		scaleX: 1.4,
		scaleY: 1.4
	});
	var speedDownText = new Text2('-', {
		size: 60,
		fill: 0xFFFFFF
	});
	speedDownText.anchor.set(0.5, 0.5);
	speedDownText.x = 200;
	speedDownText.y = 0;
	self.addChild(speedDownText);
	var backButton = self.attachAsset('menuButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 200,
		scaleX: 1.5,
		scaleY: 1.5
	});
	var backText = new Text2('BACK', {
		size: 60,
		fill: 0xFFFFFF
	});
	backText.anchor.set(0.5, 0.5);
	backText.y = 200;
	self.addChild(backText);
	self.down = function (x, y, obj) {
		// Use the x,y parameters directly instead of obj.parent.toGlobal
		var localPos = self.toLocal({
			x: x,
			y: y
		});
		if (localPos.x > -410 && localPos.x < 10 && localPos.y > -206 && localPos.y < -94) {
			// Volume up
			musicVolume = Math.min(1, musicVolume + 0.1);
			musicVolumeText.setText('Music Volume: ' + Math.round(musicVolume * 100) + '%');
			storage.musicVolume = musicVolume;
			LK.getSound('menuClick').play();
		} else if (localPos.x > -10 && localPos.x < 410 && localPos.y > -206 && localPos.y < -94) {
			// Volume down
			musicVolume = Math.max(0, musicVolume - 0.1);
			musicVolumeText.setText('Music Volume: ' + Math.round(musicVolume * 100) + '%');
			storage.musicVolume = musicVolume;
			LK.getSound('menuClick').play();
		} else if (localPos.x > -410 && localPos.x < 10 && localPos.y > -56 && localPos.y < 56) {
			// Speed up
			zombieSpeedMultiplier = Math.min(3, zombieSpeedMultiplier + 0.2);
			zombieSpeedText.setText('Zombie Speed: ' + zombieSpeedMultiplier.toFixed(1));
			LK.getSound('menuClick').play();
		} else if (localPos.x > -10 && localPos.x < 410 && localPos.y > -56 && localPos.y < 56) {
			// Speed down
			zombieSpeedMultiplier = Math.max(0.2, zombieSpeedMultiplier - 0.2);
			zombieSpeedText.setText('Zombie Speed: ' + zombieSpeedMultiplier.toFixed(1));
			LK.getSound('menuClick').play();
		} else if (localPos.y > 125 && localPos.y < 275) {
			// Back
			LK.getSound('menuClick').play();
			showMenu();
		}
	};
	return self;
});
var TankZombie = Container.expand(function () {
	var self = Container.call(this);
	var zombieGraphics = self.attachAsset('tankZombie', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.health = 3;
	self.maxHealth = 3;
	self.speed = 1;
	self.points = 25;
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		if (player) {
			self.lastX = self.x;
			self.lastY = self.y;
			var dx = player.x - self.x;
			var dy = player.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance > 0) {
				// Chase player
				self.x += dx / distance * self.speed * zombieSpeedMultiplier;
				self.y += dy / distance * self.speed * zombieSpeedMultiplier;
			}
		}
	};
	return self;
});
var TrailParticle = Container.expand(function () {
	var self = Container.call(this);
	var trailGraphics = self.attachAsset('particle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.life = 30;
	self.maxLife = 30;
	self.update = function () {
		self.life--;
		self.alpha = self.life / self.maxLife;
		self.scaleX = self.alpha * trailSize;
		self.scaleY = self.alpha * trailSize;
		if (self.life <= 0) {
			self.destroy();
		}
	};
	return self;
});
var Zombie = Container.expand(function () {
	var self = Container.call(this);
	var zombieGraphics = self.attachAsset('zombie', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.health = 1;
	self.maxHealth = 1;
	self.speed = 1.5;
	self.points = 10;
	self.lastX = 0;
	self.lastY = 0;
	self.update = function () {
		if (player) {
			self.lastX = self.x;
			self.lastY = self.y;
			var dx = player.x - self.x;
			var dy = player.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance > 0) {
				// Chase player
				self.x += dx / distance * self.speed * zombieSpeedMultiplier;
				self.y += dy / distance * self.speed * zombieSpeedMultiplier;
			}
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x2F4F2F
});
/**** 
* Game Code
****/ 
// Game state variables
var gameState = 'playing'; // Always playing now
var particles = [];
var zombieSpeedMultiplier = 1.0;
var musicVolume = storage.musicVolume || 1.0;
// Game variables
var player;
var zombies = [];
var trailParticles = [];
var playerLastX = 0;
var playerLastY = 0;
var trailTimer = 0;
var currentWave = 1;
var zombiesSpawned = 0;
var zombiesKilled = 0;
var gameTime = 0;
var waveTime = 0;
var spawnTimer = 0;
var dragNode = null;
var killStreak = 0;
var killStreakTimer = 0;
var combo = 0;
var comboTimer = 0;
var maxCombo = 0;
var trailSize = 1.5; // Make trail bigger
// Wave configuration
var waveConfigs = [{
	zombieCount: 8,
	spawnDelay: 90,
	zombieTypes: ['zombie']
}, {
	zombieCount: 12,
	spawnDelay: 75,
	zombieTypes: ['zombie', 'fastZombie']
}, {
	zombieCount: 16,
	spawnDelay: 60,
	zombieTypes: ['zombie', 'fastZombie']
}, {
	zombieCount: 20,
	spawnDelay: 50,
	zombieTypes: ['zombie', 'fastZombie', 'tankZombie']
}, {
	zombieCount: 25,
	spawnDelay: 45,
	zombieTypes: ['zombie', 'fastZombie', 'tankZombie']
}, {
	zombieCount: 30,
	spawnDelay: 40,
	zombieTypes: ['zombie', 'fastZombie', 'tankZombie']
}, {
	zombieCount: 35,
	spawnDelay: 35,
	zombieTypes: ['zombie', 'fastZombie', 'tankZombie']
}, {
	zombieCount: 40,
	spawnDelay: 30,
	zombieTypes: ['zombie', 'fastZombie', 'tankZombie']
}];
// UI Elements
var scoreText = new Text2('Score: 0', {
	size: 60,
	fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 20;
LK.gui.topLeft.addChild(scoreText);
var waveText = new Text2('Wave: 1', {
	size: 60,
	fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var timerText = new Text2('Time: 90', {
	size: 60,
	fill: 0xFFFFFF
});
timerText.anchor.set(1, 0);
timerText.x = -20;
timerText.y = 20;
LK.gui.topRight.addChild(timerText);
var instructionText = new Text2('Tap the cubes to get points', {
	size: 50,
	fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 1);
instructionText.y = -20;
LK.gui.bottom.addChild(instructionText);
var comboText = new Text2('Combo: 0', {
	size: 60,
	fill: 0xFFD700
});
comboText.anchor.set(1, 0);
comboText.x = -20;
comboText.y = 100;
LK.gui.topRight.addChild(comboText);
// Initialize game function
function initializeGame() {
	// Initialize player
	if (!player) {
		player = game.addChild(new Player());
		player.x = 1024;
		player.y = 1366;
		playerLastX = player.x;
		playerLastY = player.y;
	}
	// Start background music
	LK.playMusic('backgroundMusic', {
		loop: true,
		volume: musicVolume
	});
}
function createParticles(x, y, count, color) {
	for (var i = 0; i < count; i++) {
		var particle = new Particle();
		particle.x = x;
		particle.y = y;
		particle.vx = (Math.random() - 0.5) * 10;
		particle.vy = (Math.random() - 0.5) * 10;
		if (color) {
			tween(particle, {
				tint: color
			}, {
				duration: 0
			});
		}
		particles.push(particle);
		game.addChild(particle);
	}
}
// Create volume slider at bottom left
var volumeSliderBg = LK.getAsset('settingButton', {
	anchorX: 0,
	anchorY: 1,
	x: 20,
	y: 0,
	scaleX: 0.5,
	scaleY: 2
});
LK.gui.bottomLeft.addChild(volumeSliderBg);
var volumeSliderHandle = LK.getAsset('player', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 0.6,
	scaleY: 0.6
});
volumeSliderBg.addChild(volumeSliderHandle);
var volumeText = new Text2(Math.round(musicVolume * 100) + '%', {
	size: 30,
	fill: 0xFFFFFF
});
volumeText.anchor.set(0.5, 0.5);
volumeText.x = 75;
volumeText.y = 0;
volumeSliderBg.addChild(volumeText);
// Position handle based on volume (0 = bottom, 1 = top)
volumeSliderHandle.x = 75;
volumeSliderHandle.y = -20 - musicVolume * 120;
// Make slider interactive
volumeSliderBg.interactive = true;
volumeSliderBg.down = function (x, y, obj) {
	var localPos = volumeSliderBg.toLocal({
		x: x,
		y: y
	});
	// Calculate volume based on Y position (inverted since 0,0 is top-left)
	var newVolume = Math.max(0, Math.min(1, (-localPos.y + 20) / 120));
	musicVolume = newVolume;
	storage.musicVolume = musicVolume;
	// Update handle position
	tween(volumeSliderHandle, {
		y: -20 - musicVolume * 120
	}, {
		duration: 200
	});
	volumeText.setText(Math.round(musicVolume * 100) + '%');
	LK.getSound('menuClick').play();
};
// Start game after 2 seconds
LK.setTimeout(function () {
	initializeGame();
}, 2000);
// Spawn zombie function
function spawnZombie() {
	var config = waveConfigs[Math.min(currentWave - 1, waveConfigs.length - 1)];
	var zombieTypes = config.zombieTypes;
	var randomType = zombieTypes[Math.floor(Math.random() * zombieTypes.length)];
	var zombie;
	if (randomType === 'fastZombie') {
		zombie = new FastZombie();
	} else if (randomType === 'tankZombie') {
		zombie = new TankZombie();
	} else {
		zombie = new Zombie();
	}
	// Apply speed multiplier
	zombie.speed *= zombieSpeedMultiplier;
	// Spawn from random edge
	var edge = Math.floor(Math.random() * 4);
	if (edge === 0) {
		// Top
		zombie.x = Math.random() * 2048;
		zombie.y = -30;
	} else if (edge === 1) {
		// Right
		zombie.x = 2078;
		zombie.y = Math.random() * 2732;
	} else if (edge === 2) {
		// Bottom
		zombie.x = Math.random() * 2048;
		zombie.y = 2762;
	} else {
		// Left
		zombie.x = -30;
		zombie.y = Math.random() * 2732;
	}
	zombie.lastX = zombie.x;
	zombie.lastY = zombie.y;
	// Create spawn particles
	createParticles(zombie.x, zombie.y, 6, 0x8b4513);
	zombies.push(zombie);
	game.addChild(zombie);
	zombiesSpawned++;
}
// Update UI function
function updateUI() {
	scoreText.setText('Score: ' + LK.getScore());
	waveText.setText('Wave: ' + currentWave);
	timerText.setText('Time: ' + Math.max(0, Math.ceil((150 * 60 - gameTime) / 60)));
	comboText.setText('Combo: ' + combo + (maxCombo > 0 ? ' (Best: ' + maxCombo + ')' : ''));
}
// Handle move events
function handleMove(x, y, obj) {
	if (dragNode) {
		// Keep target position within bounds
		var targetX = Math.max(40, Math.min(2008, x));
		var targetY = Math.max(40, Math.min(2692, y));
		// Stop any existing movement tween
		tween.stop(dragNode, {
			x: true,
			y: true
		});
		// Smoothly move to target position
		tween(dragNode, {
			x: targetX,
			y: targetY
		}, {
			duration: 300,
			easing: tween.easeOut
		});
	}
}
// Game event handlers
game.move = handleMove;
game.down = function (x, y, obj) {
	if (player) {
		dragNode = player;
		handleMove(x, y, obj);
	}
};
game.up = function (x, y, obj) {
	dragNode = null;
};
// Main game update loop
game.update = function () {
	// Update particles
	for (var p = particles.length - 1; p >= 0; p--) {
		var particle = particles[p];
		if (particle.life <= 0) {
			particles.splice(p, 1);
		}
	}
	// Update trail particles
	for (var t = trailParticles.length - 1; t >= 0; t--) {
		var trailParticle = trailParticles[t];
		if (trailParticle.life <= 0) {
			trailParticles.splice(t, 1);
		}
	}
	// Create player trail when moving
	if (player) {
		var playerMoved = Math.abs(player.x - playerLastX) > 5 || Math.abs(player.y - playerLastY) > 5;
		if (playerMoved) {
			trailTimer++;
			if (trailTimer >= 3) {
				// Create trail every 3 frames when moving
				var trail = new TrailParticle();
				trail.x = playerLastX;
				trail.y = playerLastY;
				tween(trail, {
					tint: 0x4caf50
				}, {
					duration: 0
				});
				trailParticles.push(trail);
				game.addChild(trail);
				trailTimer = 0;
			}
		}
		playerLastX = player.x;
		playerLastY = player.y;
	}
	// Only run game logic when player exists
	if (!player) {
		return;
	}
	gameTime++;
	waveTime++;
	// Update kill streak timer
	if (killStreakTimer > 0) {
		killStreakTimer--;
		if (killStreakTimer <= 0) {
			killStreak = 0;
		}
	}
	// Update combo timer
	if (comboTimer > 0) {
		comboTimer--;
		if (comboTimer <= 0) {
			combo = 0;
		}
	}
	// Wave management
	var config = waveConfigs[Math.min(currentWave - 1, waveConfigs.length - 1)];
	// Spawn zombies
	if (zombiesSpawned < config.zombieCount) {
		spawnTimer++;
		if (spawnTimer >= config.spawnDelay) {
			spawnZombie();
			spawnTimer = 0;
		}
	}
	// Check wave completion
	if (zombiesSpawned >= config.zombieCount && zombies.length === 0) {
		currentWave++;
		zombiesSpawned = 0;
		waveTime = 0;
		// Bonus points for wave completion
		LK.setScore(LK.getScore() + currentWave * 50);
		LK.getSound('waveStart').play();
		// Restore some health
		player.health = Math.min(player.maxHealth, player.health + 20);
		// Create celebration particles
		createParticles(player.x, player.y, 15, 0x00ff00);
	}
	// Update zombies and check player collision for combat
	for (var k = zombies.length - 1; k >= 0; k--) {
		var zombie = zombies[k];
		// Initialize collision tracking if not exists
		if (zombie.lastCollidingWithPlayer === undefined) {
			zombie.lastCollidingWithPlayer = false;
		}
		// Check current collision state
		var currentlyColliding = zombie.intersects(player);
		// If collision just started (transition from false to true)
		if (!zombie.lastCollidingWithPlayer && currentlyColliding) {
			// Player kills zombie by running into it
			zombie.health--;
			// Flash zombie when hit
			LK.effects.flashObject(zombie, 0xff0000, 200);
			LK.getSound('playerAttack').play();
			// Create hit particles
			createParticles(zombie.x, zombie.y, 8, 0xff0000);
			if (zombie.health <= 0) {
				// Update combo system
				combo++;
				comboTimer = 120; // 2 seconds to maintain combo
				if (combo > maxCombo) {
					maxCombo = combo;
				}
				// Add score with kill streak and combo multiplier
				var basePoints = zombie.points;
				var killStreakMultiplier = 1 + killStreak * 0.1;
				var comboMultiplier = 1 + Math.min(combo - 1, 10) * 0.2; // Max 3x from combo
				var points = basePoints * killStreakMultiplier * comboMultiplier;
				LK.setScore(LK.getScore() + Math.floor(points));
				killStreak++;
				killStreakTimer = 180; // 3 seconds
				// Flash combo text when combo increases
				if (combo > 1) {
					tween(comboText, {
						tint: 0xFFFFFF
					}, {
						duration: 100,
						onFinish: function onFinish() {
							tween(comboText, {
								tint: 0xFFD700
							}, {
								duration: 100
							});
						}
					});
				}
				// Create death particles
				createParticles(zombie.x, zombie.y, 12, 0xffff00);
				LK.getSound('zombieDeath').play();
				zombie.destroy();
				zombies.splice(k, 1);
				zombiesKilled++;
			} else {
				// If zombie survives, player takes damage
				player.health -= 5;
				LK.effects.flashScreen(0xff0000, 300);
				LK.getSound('playerHurt').play();
				if (player.health <= 0) {
					LK.showGameOver();
					return;
				}
			}
		}
		// Update collision tracking
		zombie.lastCollidingWithPlayer = currentlyColliding;
	}
	// Check win condition (150 seconds = 9000 frames at 60fps)
	if (gameTime >= 9000) {
		LK.showYouWin();
		return;
	}
	// Update UI
	updateUI();
}; ===================================================================
--- original.js
+++ change.js
@@ -293,10 +293,10 @@
 	self.maxLife = 30;
 	self.update = function () {
 		self.life--;
 		self.alpha = self.life / self.maxLife;
-		self.scaleX = self.alpha * 0.8;
-		self.scaleY = self.alpha * 0.8;
+		self.scaleX = self.alpha * trailSize;
+		self.scaleY = self.alpha * trailSize;
 		if (self.life <= 0) {
 			self.destroy();
 		}
 	};
@@ -361,8 +361,12 @@
 var spawnTimer = 0;
 var dragNode = null;
 var killStreak = 0;
 var killStreakTimer = 0;
+var combo = 0;
+var comboTimer = 0;
+var maxCombo = 0;
+var trailSize = 1.5; // Make trail bigger
 // Wave configuration
 var waveConfigs = [{
 	zombieCount: 8,
 	spawnDelay: 90,
@@ -418,15 +422,23 @@
 timerText.anchor.set(1, 0);
 timerText.x = -20;
 timerText.y = 20;
 LK.gui.topRight.addChild(timerText);
-var healthText = new Text2('Tap or swipe into the cubes for points', {
+var instructionText = new Text2('Tap the cubes to get points', {
 	size: 50,
 	fill: 0xFFFFFF
 });
-healthText.anchor.set(0.5, 1);
-healthText.y = -20;
-LK.gui.bottom.addChild(healthText);
+instructionText.anchor.set(0.5, 1);
+instructionText.y = -20;
+LK.gui.bottom.addChild(instructionText);
+var comboText = new Text2('Combo: 0', {
+	size: 60,
+	fill: 0xFFD700
+});
+comboText.anchor.set(1, 0);
+comboText.x = -20;
+comboText.y = 100;
+LK.gui.topRight.addChild(comboText);
 // Initialize game function
 function initializeGame() {
 	// Initialize player
 	if (!player) {
@@ -557,9 +569,10 @@
 // Update UI function
 function updateUI() {
 	scoreText.setText('Score: ' + LK.getScore());
 	waveText.setText('Wave: ' + currentWave);
-	timerText.setText('Time: ' + Math.max(0, Math.ceil((90 * 60 - gameTime) / 60)));
+	timerText.setText('Time: ' + Math.max(0, Math.ceil((150 * 60 - gameTime) / 60)));
+	comboText.setText('Combo: ' + combo + (maxCombo > 0 ? ' (Best: ' + maxCombo + ')' : ''));
 }
 // Handle move events
 function handleMove(x, y, obj) {
 	if (dragNode) {
@@ -643,8 +656,15 @@
 		if (killStreakTimer <= 0) {
 			killStreak = 0;
 		}
 	}
+	// Update combo timer
+	if (comboTimer > 0) {
+		comboTimer--;
+		if (comboTimer <= 0) {
+			combo = 0;
+		}
+	}
 	// Wave management
 	var config = waveConfigs[Math.min(currentWave - 1, waveConfigs.length - 1)];
 	// Spawn zombies
 	if (zombiesSpawned < config.zombieCount) {
@@ -685,13 +705,37 @@
 			LK.getSound('playerAttack').play();
 			// Create hit particles
 			createParticles(zombie.x, zombie.y, 8, 0xff0000);
 			if (zombie.health <= 0) {
-				// Add score with kill streak multiplier
-				var points = zombie.points * (1 + killStreak * 0.1);
+				// Update combo system
+				combo++;
+				comboTimer = 120; // 2 seconds to maintain combo
+				if (combo > maxCombo) {
+					maxCombo = combo;
+				}
+				// Add score with kill streak and combo multiplier
+				var basePoints = zombie.points;
+				var killStreakMultiplier = 1 + killStreak * 0.1;
+				var comboMultiplier = 1 + Math.min(combo - 1, 10) * 0.2; // Max 3x from combo
+				var points = basePoints * killStreakMultiplier * comboMultiplier;
 				LK.setScore(LK.getScore() + Math.floor(points));
 				killStreak++;
 				killStreakTimer = 180; // 3 seconds
+				// Flash combo text when combo increases
+				if (combo > 1) {
+					tween(comboText, {
+						tint: 0xFFFFFF
+					}, {
+						duration: 100,
+						onFinish: function onFinish() {
+							tween(comboText, {
+								tint: 0xFFD700
+							}, {
+								duration: 100
+							});
+						}
+					});
+				}
 				// Create death particles
 				createParticles(zombie.x, zombie.y, 12, 0xffff00);
 				LK.getSound('zombieDeath').play();
 				zombie.destroy();
@@ -710,10 +754,10 @@
 		}
 		// Update collision tracking
 		zombie.lastCollidingWithPlayer = currentlyColliding;
 	}
-	// Check win condition (90 seconds = 5400 frames at 60fps)
-	if (gameTime >= 5400) {
+	// Check win condition (150 seconds = 9000 frames at 60fps)
+	if (gameTime >= 9000) {
 		LK.showYouWin();
 		return;
 	}
 	// Update UI