User prompt
remove the old route when new created
User prompt
When the knife button is pressed, draw a route that shows the shortest distance between the enemy and the player, and display the effect where that route meets the player's asset. the knife meets the enemy in the middle of asset. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a knife throw button. enemies take damage when knife hits them. knives are limited to 5 for each level ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the knife button is pressed, draw a route that shows the shortest distance between the enemy and the player, and display the effect where that route meets the player's asset. remove the same thing with attack button attack button only creates punch effect not any route effect ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a knife throw button and do this when new button is pressed. also enemies take damage when knife hits them. knives are limited to 5 for each level ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the attack button is pressed, draw a route that shows the shortest distance between the enemy and the player, and display the effect where that route meets the player's asset. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
move the movement keys away from each other and prevent them from intersecting with each other
User prompt
Show a warning with an arrow on the side where the enemy is. As you move forward, the warning will change from transparent to visible and when the enemy becomes visible on the screen, the warning will disappear. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add collision to player and mobs. they collide and They don't interfere with each other.
User prompt
make all buttons bigger and add an asset for each of them
User prompt
It should move when the movement keys are hold, not when clicked.
User prompt
add buttons for all directions to move the player, add a attack button, increase attacks range
User prompt
game is not wave based. game is level based with each level contains different type and number of enemies. you move the player and the playable map is not limited with the visble screen camera follows the char as the char moves. enemies roam randomly and starts to attack the pkayer once they sees it
Code edit (1 edits merged)
Please save this source code
User prompt
Pixel Hero Adventure
Initial prompt
a pixel game like dan the man
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collectTimer = 0;
self.update = function () {
// Auto-collect after short delay
self.collectTimer++;
if (self.collectTimer > 30) {
// 0.5 seconds
self.collect();
}
// Spin animation
coinGraphics.rotation += 0.1;
};
self.collect = function () {
LK.getSound('coin').play();
// Remove from coins array
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] === self) {
coins.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0
});
self.health = 2;
self.speed = 1;
self.attackCooldown = 0;
self.fromLeft = true;
self.update = function () {
// Move toward hero
if (self.fromLeft) {
self.x += self.speed;
enemyGraphics.scaleX = 1;
} else {
self.x -= self.speed;
enemyGraphics.scaleX = -1;
}
// Attack hero if close enough
var distanceToHero = Math.abs(self.x - hero.x);
if (distanceToHero < 100 && self.attackCooldown <= 0) {
hero.takeDamage();
self.attackCooldown = 120; // 2 seconds at 60fps
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Drop coin
var coin = game.addChild(new Coin());
coin.x = self.x;
coin.y = self.y;
// Add score and combo
var baseScore = 10;
var comboMultiplier = Math.floor(hero.comboCount / 5) + 1;
var finalScore = baseScore * comboMultiplier;
LK.setScore(LK.getScore() + finalScore);
hero.addCombo();
// Remove from enemies array
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
updateScoreDisplay();
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 1.0
});
self.maxHealth = 5;
self.health = self.maxHealth;
self.isAttacking = false;
self.invulnerable = false;
self.damageBoost = false;
self.comboCount = 0;
self.attack = function (targetX) {
if (self.isAttacking) return;
self.isAttacking = true;
// Face direction of attack
if (targetX < self.x) {
heroGraphics.scaleX = -1;
} else {
heroGraphics.scaleX = 1;
}
// Attack animation
tween(heroGraphics, {
scaleY: 1.2
}, {
duration: 100
});
tween(heroGraphics, {
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
self.isAttacking = false;
}
});
// Create punch effect
var effect = game.addChild(LK.getAsset('punchEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
}));
effect.x = self.x + heroGraphics.scaleX * 80;
effect.y = self.y - 80;
tween(effect, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
effect.destroy();
}
});
LK.getSound('punch').play();
};
self.takeDamage = function () {
if (self.invulnerable) return;
self.health--;
self.comboCount = 0;
// Flash red when hit
LK.effects.flashObject(self, 0xff0000, 500);
// Temporary invulnerability
self.invulnerable = true;
LK.setTimeout(function () {
self.invulnerable = false;
}, 1000);
LK.getSound('hit').play();
updateHealthDisplay();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.heal = function () {
if (self.health < self.maxHealth) {
self.health++;
updateHealthDisplay();
}
};
self.addCombo = function () {
self.comboCount++;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'health'; // 'health', 'invulnerable', 'damage'
self.lifetime = 600; // 10 seconds
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.expire();
}
// Check collision with hero
if (self.intersects(hero)) {
self.collect();
}
// Pulse animation
var scale = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
powerupGraphics.scaleX = scale;
powerupGraphics.scaleY = scale;
};
self.collect = function () {
LK.getSound('powerup').play();
if (self.type === 'health') {
hero.heal();
} else if (self.type === 'invulnerable') {
hero.invulnerable = true;
LK.setTimeout(function () {
hero.invulnerable = false;
}, 5000);
} else if (self.type === 'damage') {
hero.damageBoost = true;
LK.setTimeout(function () {
hero.damageBoost = false;
}, 5000);
}
// Remove from powerups array
for (var i = powerups.length - 1; i >= 0; i--) {
if (powerups[i] === self) {
powerups.splice(i, 1);
break;
}
}
self.destroy();
};
self.expire = function () {
// Remove from powerups array
for (var i = powerups.length - 1; i >= 0; i--) {
if (powerups[i] === self) {
powerups.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var hero;
var enemies = [];
var coins = [];
var powerups = [];
var currentWave = 1;
var enemiesLeftInWave = 3;
var spawnTimer = 0;
var powerupSpawnTimer = 0;
var hearts = [];
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 150;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 50;
var comboText = new Text2('Combo: 0x', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(1, 0);
LK.gui.topRight.addChild(comboText);
comboText.x = -50;
comboText.y = 120;
// Create hero
hero = game.addChild(new Hero());
hero.x = 1024; // Center of screen
hero.y = 2200; // Near bottom
// Create health display
function updateHealthDisplay() {
// Remove existing hearts
for (var i = hearts.length - 1; i >= 0; i--) {
hearts[i].destroy();
}
hearts = [];
// Create new hearts
for (var i = 0; i < hero.health; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 200 + i * 80;
heart.y = 200;
LK.gui.topLeft.addChild(heart);
hearts.push(heart);
}
}
function updateScoreDisplay() {
scoreText.setText('Score: ' + LK.getScore());
var comboMultiplier = Math.floor(hero.comboCount / 5) + 1;
comboText.setText('Combo: ' + comboMultiplier + 'x');
}
function spawnEnemy() {
var enemy = game.addChild(new Enemy());
// Random spawn from left or right
enemy.fromLeft = Math.random() < 0.5;
if (enemy.fromLeft) {
enemy.x = -100;
enemy.speed = 1 + currentWave * 0.3;
} else {
enemy.x = 2148;
enemy.speed = 1 + currentWave * 0.3;
}
enemy.y = 2200; // Same level as hero
enemy.health = 1 + Math.floor(currentWave / 3); // Increase health every 3 waves
enemies.push(enemy);
enemiesLeftInWave--;
}
function spawnPowerUp() {
var powerup = game.addChild(new PowerUp());
powerup.x = 500 + Math.random() * 1048; // Random x position
powerup.y = 2000; // Above ground level
// Random powerup type
var types = ['health', 'invulnerable', 'damage'];
powerup.type = types[Math.floor(Math.random() * types.length)];
// Color by type
var powerupGraphics = powerup.getChildAt(0);
if (powerup.type === 'health') {
powerupGraphics.tint = 0x00ff00; // Green
} else if (powerup.type === 'invulnerable') {
powerupGraphics.tint = 0x0088ff; // Blue
} else if (powerup.type === 'damage') {
powerupGraphics.tint = 0xff8800; // Orange
}
powerups.push(powerup);
}
function findNearestEnemy(x, y) {
var nearest = null;
var shortestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - x, 2) + Math.pow(enemy.y - y, 2));
if (distance < shortestDistance) {
shortestDistance = distance;
nearest = enemy;
}
}
return nearest;
}
// Initialize UI
updateHealthDisplay();
updateScoreDisplay();
// Game input
game.down = function (x, y, obj) {
if (!hero.isAttacking) {
var nearestEnemy = findNearestEnemy(x, y);
if (nearestEnemy) {
hero.attack(nearestEnemy.x);
// Check if attack hits
var distanceToEnemy = Math.abs(hero.x - nearestEnemy.x);
if (distanceToEnemy < 150) {
var damage = hero.damageBoost ? 2 : 1;
for (var i = 0; i < damage; i++) {
nearestEnemy.takeDamage();
}
}
} else {
// Attack in direction of tap
hero.attack(x);
}
}
};
// Main game loop
game.update = function () {
// Update all game objects
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Remove if off screen
if (enemy.x < -200 || enemy.x > 2248) {
enemies.splice(i, 1);
enemy.destroy();
}
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].update();
}
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].update();
}
// Spawn logic
spawnTimer++;
if (spawnTimer > 180 && enemiesLeftInWave > 0) {
// 3 seconds between spawns
spawnEnemy();
spawnTimer = 0;
}
// Check for wave completion
if (enemiesLeftInWave <= 0 && enemies.length === 0) {
currentWave++;
enemiesLeftInWave = 3 + currentWave; // Increase enemies per wave
waveText.setText('Wave: ' + currentWave);
// Chance to spawn powerup on wave complete
if (Math.random() < 0.6) {
spawnPowerUp();
}
}
// Powerup spawn timer
powerupSpawnTimer++;
if (powerupSpawnTimer > 1800) {
// 30 seconds
if (Math.random() < 0.3) {
spawnPowerUp();
}
powerupSpawnTimer = 0;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,426 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var Coin = Container.expand(function () {
+ var self = Container.call(this);
+ var coinGraphics = self.attachAsset('coin', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.collectTimer = 0;
+ self.update = function () {
+ // Auto-collect after short delay
+ self.collectTimer++;
+ if (self.collectTimer > 30) {
+ // 0.5 seconds
+ self.collect();
+ }
+ // Spin animation
+ coinGraphics.rotation += 0.1;
+ };
+ self.collect = function () {
+ LK.getSound('coin').play();
+ // Remove from coins array
+ for (var i = coins.length - 1; i >= 0; i--) {
+ if (coins[i] === self) {
+ coins.splice(i, 1);
+ break;
+ }
+ }
+ self.destroy();
+ };
+ return self;
+});
+var Enemy = Container.expand(function () {
+ var self = Container.call(this);
+ var enemyGraphics = self.attachAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 1.0
+ });
+ self.health = 2;
+ self.speed = 1;
+ self.attackCooldown = 0;
+ self.fromLeft = true;
+ self.update = function () {
+ // Move toward hero
+ if (self.fromLeft) {
+ self.x += self.speed;
+ enemyGraphics.scaleX = 1;
+ } else {
+ self.x -= self.speed;
+ enemyGraphics.scaleX = -1;
+ }
+ // Attack hero if close enough
+ var distanceToHero = Math.abs(self.x - hero.x);
+ if (distanceToHero < 100 && self.attackCooldown <= 0) {
+ hero.takeDamage();
+ self.attackCooldown = 120; // 2 seconds at 60fps
+ }
+ if (self.attackCooldown > 0) {
+ self.attackCooldown--;
+ }
+ };
+ self.takeDamage = function () {
+ self.health--;
+ LK.effects.flashObject(self, 0xffffff, 200);
+ if (self.health <= 0) {
+ self.die();
+ }
+ };
+ self.die = function () {
+ // Drop coin
+ var coin = game.addChild(new Coin());
+ coin.x = self.x;
+ coin.y = self.y;
+ // Add score and combo
+ var baseScore = 10;
+ var comboMultiplier = Math.floor(hero.comboCount / 5) + 1;
+ var finalScore = baseScore * comboMultiplier;
+ LK.setScore(LK.getScore() + finalScore);
+ hero.addCombo();
+ // Remove from enemies array
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ if (enemies[i] === self) {
+ enemies.splice(i, 1);
+ break;
+ }
+ }
+ self.destroy();
+ updateScoreDisplay();
+ };
+ return self;
+});
+var Hero = Container.expand(function () {
+ var self = Container.call(this);
+ var heroGraphics = self.attachAsset('hero', {
+ anchorX: 0.5,
+ anchorY: 1.0
+ });
+ self.maxHealth = 5;
+ self.health = self.maxHealth;
+ self.isAttacking = false;
+ self.invulnerable = false;
+ self.damageBoost = false;
+ self.comboCount = 0;
+ self.attack = function (targetX) {
+ if (self.isAttacking) return;
+ self.isAttacking = true;
+ // Face direction of attack
+ if (targetX < self.x) {
+ heroGraphics.scaleX = -1;
+ } else {
+ heroGraphics.scaleX = 1;
+ }
+ // Attack animation
+ tween(heroGraphics, {
+ scaleY: 1.2
+ }, {
+ duration: 100
+ });
+ tween(heroGraphics, {
+ scaleY: 1.0
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ self.isAttacking = false;
+ }
+ });
+ // Create punch effect
+ var effect = game.addChild(LK.getAsset('punchEffect', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ }));
+ effect.x = self.x + heroGraphics.scaleX * 80;
+ effect.y = self.y - 80;
+ tween(effect, {
+ scaleX: 2,
+ scaleY: 2,
+ alpha: 0
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ effect.destroy();
+ }
+ });
+ LK.getSound('punch').play();
+ };
+ self.takeDamage = function () {
+ if (self.invulnerable) return;
+ self.health--;
+ self.comboCount = 0;
+ // Flash red when hit
+ LK.effects.flashObject(self, 0xff0000, 500);
+ // Temporary invulnerability
+ self.invulnerable = true;
+ LK.setTimeout(function () {
+ self.invulnerable = false;
+ }, 1000);
+ LK.getSound('hit').play();
+ updateHealthDisplay();
+ if (self.health <= 0) {
+ LK.showGameOver();
+ }
+ };
+ self.heal = function () {
+ if (self.health < self.maxHealth) {
+ self.health++;
+ updateHealthDisplay();
+ }
+ };
+ self.addCombo = function () {
+ self.comboCount++;
+ };
+ return self;
+});
+var PowerUp = Container.expand(function () {
+ var self = Container.call(this);
+ var powerupGraphics = self.attachAsset('powerup', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.type = 'health'; // 'health', 'invulnerable', 'damage'
+ self.lifetime = 600; // 10 seconds
+ self.update = function () {
+ self.lifetime--;
+ if (self.lifetime <= 0) {
+ self.expire();
+ }
+ // Check collision with hero
+ if (self.intersects(hero)) {
+ self.collect();
+ }
+ // Pulse animation
+ var scale = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
+ powerupGraphics.scaleX = scale;
+ powerupGraphics.scaleY = scale;
+ };
+ self.collect = function () {
+ LK.getSound('powerup').play();
+ if (self.type === 'health') {
+ hero.heal();
+ } else if (self.type === 'invulnerable') {
+ hero.invulnerable = true;
+ LK.setTimeout(function () {
+ hero.invulnerable = false;
+ }, 5000);
+ } else if (self.type === 'damage') {
+ hero.damageBoost = true;
+ LK.setTimeout(function () {
+ hero.damageBoost = false;
+ }, 5000);
+ }
+ // Remove from powerups array
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ if (powerups[i] === self) {
+ powerups.splice(i, 1);
+ break;
+ }
+ }
+ self.destroy();
+ };
+ self.expire = function () {
+ // Remove from powerups array
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ if (powerups[i] === self) {
+ powerups.splice(i, 1);
+ break;
+ }
+ }
+ self.destroy();
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x2c3e50
+});
+
+/****
+* Game Code
+****/
+// Game variables
+var hero;
+var enemies = [];
+var coins = [];
+var powerups = [];
+var currentWave = 1;
+var enemiesLeftInWave = 3;
+var spawnTimer = 0;
+var powerupSpawnTimer = 0;
+var hearts = [];
+// UI Elements
+var scoreText = new Text2('Score: 0', {
+ size: 80,
+ fill: 0xFFFFFF
+});
+scoreText.anchor.set(0, 0);
+scoreText.x = 150;
+scoreText.y = 50;
+LK.gui.topLeft.addChild(scoreText);
+var waveText = new Text2('Wave: 1', {
+ size: 80,
+ fill: 0xFFFFFF
+});
+waveText.anchor.set(0.5, 0);
+LK.gui.top.addChild(waveText);
+waveText.y = 50;
+var comboText = new Text2('Combo: 0x', {
+ size: 60,
+ fill: 0xFFFF00
+});
+comboText.anchor.set(1, 0);
+LK.gui.topRight.addChild(comboText);
+comboText.x = -50;
+comboText.y = 120;
+// Create hero
+hero = game.addChild(new Hero());
+hero.x = 1024; // Center of screen
+hero.y = 2200; // Near bottom
+// Create health display
+function updateHealthDisplay() {
+ // Remove existing hearts
+ for (var i = hearts.length - 1; i >= 0; i--) {
+ hearts[i].destroy();
+ }
+ hearts = [];
+ // Create new hearts
+ for (var i = 0; i < hero.health; i++) {
+ var heart = LK.getAsset('heart', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ heart.x = 200 + i * 80;
+ heart.y = 200;
+ LK.gui.topLeft.addChild(heart);
+ hearts.push(heart);
+ }
+}
+function updateScoreDisplay() {
+ scoreText.setText('Score: ' + LK.getScore());
+ var comboMultiplier = Math.floor(hero.comboCount / 5) + 1;
+ comboText.setText('Combo: ' + comboMultiplier + 'x');
+}
+function spawnEnemy() {
+ var enemy = game.addChild(new Enemy());
+ // Random spawn from left or right
+ enemy.fromLeft = Math.random() < 0.5;
+ if (enemy.fromLeft) {
+ enemy.x = -100;
+ enemy.speed = 1 + currentWave * 0.3;
+ } else {
+ enemy.x = 2148;
+ enemy.speed = 1 + currentWave * 0.3;
+ }
+ enemy.y = 2200; // Same level as hero
+ enemy.health = 1 + Math.floor(currentWave / 3); // Increase health every 3 waves
+ enemies.push(enemy);
+ enemiesLeftInWave--;
+}
+function spawnPowerUp() {
+ var powerup = game.addChild(new PowerUp());
+ powerup.x = 500 + Math.random() * 1048; // Random x position
+ powerup.y = 2000; // Above ground level
+ // Random powerup type
+ var types = ['health', 'invulnerable', 'damage'];
+ powerup.type = types[Math.floor(Math.random() * types.length)];
+ // Color by type
+ var powerupGraphics = powerup.getChildAt(0);
+ if (powerup.type === 'health') {
+ powerupGraphics.tint = 0x00ff00; // Green
+ } else if (powerup.type === 'invulnerable') {
+ powerupGraphics.tint = 0x0088ff; // Blue
+ } else if (powerup.type === 'damage') {
+ powerupGraphics.tint = 0xff8800; // Orange
+ }
+ powerups.push(powerup);
+}
+function findNearestEnemy(x, y) {
+ var nearest = null;
+ var shortestDistance = Infinity;
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ var distance = Math.sqrt(Math.pow(enemy.x - x, 2) + Math.pow(enemy.y - y, 2));
+ if (distance < shortestDistance) {
+ shortestDistance = distance;
+ nearest = enemy;
+ }
+ }
+ return nearest;
+}
+// Initialize UI
+updateHealthDisplay();
+updateScoreDisplay();
+// Game input
+game.down = function (x, y, obj) {
+ if (!hero.isAttacking) {
+ var nearestEnemy = findNearestEnemy(x, y);
+ if (nearestEnemy) {
+ hero.attack(nearestEnemy.x);
+ // Check if attack hits
+ var distanceToEnemy = Math.abs(hero.x - nearestEnemy.x);
+ if (distanceToEnemy < 150) {
+ var damage = hero.damageBoost ? 2 : 1;
+ for (var i = 0; i < damage; i++) {
+ nearestEnemy.takeDamage();
+ }
+ }
+ } else {
+ // Attack in direction of tap
+ hero.attack(x);
+ }
+ }
+};
+// Main game loop
+game.update = function () {
+ // Update all game objects
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ var enemy = enemies[i];
+ enemy.update();
+ // Remove if off screen
+ if (enemy.x < -200 || enemy.x > 2248) {
+ enemies.splice(i, 1);
+ enemy.destroy();
+ }
+ }
+ for (var i = coins.length - 1; i >= 0; i--) {
+ coins[i].update();
+ }
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ powerups[i].update();
+ }
+ // Spawn logic
+ spawnTimer++;
+ if (spawnTimer > 180 && enemiesLeftInWave > 0) {
+ // 3 seconds between spawns
+ spawnEnemy();
+ spawnTimer = 0;
+ }
+ // Check for wave completion
+ if (enemiesLeftInWave <= 0 && enemies.length === 0) {
+ currentWave++;
+ enemiesLeftInWave = 3 + currentWave; // Increase enemies per wave
+ waveText.setText('Wave: ' + currentWave);
+ // Chance to spawn powerup on wave complete
+ if (Math.random() < 0.6) {
+ spawnPowerUp();
+ }
+ }
+ // Powerup spawn timer
+ powerupSpawnTimer++;
+ if (powerupSpawnTimer > 1800) {
+ // 30 seconds
+ if (Math.random() < 0.3) {
+ spawnPowerUp();
+ }
+ powerupSpawnTimer = 0;
+ }
+};
\ No newline at end of file