User prompt
make the background dark green
User prompt
make the enemies bigger
User prompt
the D-Pad doesn't work
User prompt
can you make a D-Pad controller
User prompt
make the enemies bigger
User prompt
it's too hard, make it easier
User prompt
make more enemies
User prompt
make the enemy bigger and the katana swing faster
User prompt
make the enemy have HP bars and make the player have a attack speed bar to show when it atttacks
User prompt
make the enemy flash white when hit
User prompt
make a explosion sprite for when your character does damage to an enemy, and please make it to where when an enemy touches the katana your character does not take damage ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the katana damage enemies and make the ninja blue
Code edit (1 edits merged)
Please save this source code
User prompt
Ninja Survivor
User prompt
can you make it not have any extra stuff other than a katana and a shuriken that throws every 5 seconds, also please make the game like Survivor.io or Vampire survivors?
Initial prompt
make a ARPG about a blue ninja named Harry and he fights monsters through waves.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var DPad = Container.expand(function () {
var self = Container.call(this);
// Create the D-Pad background with increased size
var padBg = LK.getAsset('player', {
width: 250,
height: 250,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333,
alpha: 0.6
});
// Create the directional buttons with increased size
var upButton = LK.getAsset('player', {
width: 85,
height: 85,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x666666
});
upButton.y = -80;
var downButton = LK.getAsset('player', {
width: 85,
height: 85,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x666666
});
downButton.y = 80;
var leftButton = LK.getAsset('player', {
width: 85,
height: 85,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x666666
});
leftButton.x = -80;
var rightButton = LK.getAsset('player', {
width: 85,
height: 85,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x666666
});
rightButton.x = 80;
// Add all components to the container
self.addChild(padBg);
self.addChild(upButton);
self.addChild(downButton);
self.addChild(leftButton);
self.addChild(rightButton);
// Direction state
self.direction = {
up: false,
down: false,
left: false,
right: false
};
// Make the entire D-Pad container interactive to capture all touch events
self.interactive = true;
// Buttons don't need to be individually interactive when container handles events
// Highlight function for visual feedback
function highlightButton(button) {
tween(button, {
tint: 0x00FFFF
}, {
duration: 100,
easing: tween.easeOut
});
}
function unhighlightButton(button) {
tween(button, {
tint: 0x666666
}, {
duration: 100,
easing: tween.easeIn
});
}
// Event handlers
self.down = function (x, y, obj) {
// Convert global coordinates to local coordinates
var localPos = {
x: x - self.x,
y: y - self.y
};
// Check which button was pressed using more generous hit areas
if (Math.abs(localPos.x) < 40 && localPos.y < -30) {
self.direction.up = true;
highlightButton(upButton);
} else if (Math.abs(localPos.x) < 40 && localPos.y > 30) {
self.direction.down = true;
highlightButton(downButton);
} else if (localPos.x < -30 && Math.abs(localPos.y) < 40) {
self.direction.left = true;
highlightButton(leftButton);
} else if (localPos.x > 30 && Math.abs(localPos.y) < 40) {
self.direction.right = true;
highlightButton(rightButton);
}
};
self.up = function (x, y, obj) {
// Reset all directions when touch ends
self.direction.up = false;
self.direction.down = false;
self.direction.left = false;
self.direction.right = false;
// Reset all button appearances
unhighlightButton(upButton);
unhighlightButton(downButton);
unhighlightButton(leftButton);
unhighlightButton(rightButton);
};
self.move = function (x, y, obj) {
// Convert global coordinates to local coordinates
var localPos = {
x: x - self.x,
y: y - self.y
};
// Update direction based on touch position with improved detection
self.direction.up = Math.abs(localPos.x) < 40 && localPos.y < -30;
self.direction.down = Math.abs(localPos.x) < 40 && localPos.y > 30;
self.direction.left = localPos.x < -30 && Math.abs(localPos.y) < 40;
self.direction.right = localPos.x > 30 && Math.abs(localPos.y) < 40;
// Update button appearances
if (self.direction.up) highlightButton(upButton);else unhighlightButton(upButton);
if (self.direction.down) highlightButton(downButton);else unhighlightButton(downButton);
if (self.direction.left) highlightButton(leftButton);else unhighlightButton(leftButton);
if (self.direction.right) highlightButton(rightButton);else unhighlightButton(rightButton);
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Make the enemy graphic much bigger
enemyGraphic.scale.x = 2.2;
enemyGraphic.scale.y = 2.2;
self.health = 20;
self.maxHealth = 20;
self.speed = 1.5;
self.damage = 5;
// Health bar
self.healthBar = new Container();
self.healthBar.y = -50;
self.healthBarBg = LK.getAsset('player', {
width: 70,
height: 8,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x222222
});
self.healthBarFill = LK.getAsset('player', {
width: 70,
height: 8,
anchorX: 0,
anchorY: 0.5,
tint: 0xFF0000
});
self.healthBarFill.x = -35;
self.healthBar.addChild(self.healthBarBg);
self.healthBar.addChild(self.healthBarFill);
self.addChild(self.healthBar);
self.attackCooldown = 0;
self.attackCooldownMax = 30; // Frames between attacks
self.experienceValue = 1;
self.hitByKatana = false;
self.katanaHitTimer = 0;
self.update = function () {
if (player.isDead) return;
// Move toward player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize and apply speed
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Update health bar
self.healthBarFill.width = 70 * (self.health / self.maxHealth);
// Attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Decrement katana hit timer if active
if (self.katanaHitTimer > 0) {
self.katanaHitTimer--;
if (self.katanaHitTimer === 0) {
self.hitByKatana = false;
}
}
// Attack player if touching and not recently hit by katana
if (self.intersects(player) && self.attackCooldown === 0 && !self.hitByKatana) {
player.takeDamage(self.damage);
self.attackCooldown = self.attackCooldownMax;
}
};
self.takeDamage = function (amount) {
self.health -= amount;
self.health = Math.max(0, self.health);
// Flash white when damaged
tween(enemyGraphic, {
tint: 0xFFFFFF
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(enemyGraphic, {
tint: 0xff2222 // Return to original enemy color
}, {
duration: 50,
easing: tween.easeIn
});
}
});
// Create explosion effect
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
// Add a small bounce effect using tween
tween(self, {
y: self.y - 10
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 10
}, {
duration: 100,
easing: tween.easeIn
});
}
});
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Spawn experience gem
var expGem = new ExperienceGem();
expGem.value = self.experienceValue;
expGem.x = self.x;
expGem.y = self.y;
game.addChild(expGem);
experienceGems.push(expGem);
// Remove from enemies array and destroy
var index = enemies.indexOf(self);
if (index !== -1) {
enemies.splice(index, 1);
}
self.destroy();
// Increment kill count
killCount++;
killCountText.setText("Kills: " + killCount);
};
return self;
});
var TankEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
// Override enemy appearance
self.getChildAt(0).tint = 0x2222ff; // Blue tint
// Override default properties
self.health = 50;
self.maxHealth = 50;
self.speed = 1.5; // Slower than regular enemies
self.damage = 15; // More damage
// Larger hitbox
self.scale.x = 2.8;
self.scale.y = 2.8;
return self;
});
var RangedEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
// Override enemy appearance
self.getChildAt(0).tint = 0xff22ff; // Purple tint
// Override default properties
self.health = 15;
self.maxHealth = 15;
self.speed = 1.8;
self.damage = 8;
self.shootRange = 300; // Range at which enemy will stop and shoot
self.projectileSpeed = 8;
self.attackCooldownMax = 90; // Slower attacks
// Override update method to add shooting behavior
var originalUpdate = self.update;
self.update = function () {
if (player.isDead) return;
// Calculate distance to player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If in range, stop and shoot
if (distance <= self.shootRange && self.attackCooldown === 0) {
// Shoot at player
var projectile = new EnemyProjectile();
projectile.x = self.x;
projectile.y = self.y;
// Direction toward player
if (distance > 0) {
projectile.direction = {
x: dx / distance,
y: dy / distance
};
}
projectile.speed = self.projectileSpeed;
projectile.damage = self.damage;
game.addChild(projectile);
enemyProjectiles.push(projectile);
self.attackCooldown = self.attackCooldownMax;
} else {
// Move only if not in range or on cooldown
if (distance > self.shootRange || self.attackCooldown > 0) {
// Use original movement logic
originalUpdate.call(self);
return;
}
}
// Update cooldowns and other logic
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Update health bar
self.healthBarFill.width = 70 * (self.health / self.maxHealth);
// Decrement katana hit timer if active
if (self.katanaHitTimer > 0) {
self.katanaHitTimer--;
if (self.katanaHitTimer === 0) {
self.hitByKatana = false;
}
}
};
return self;
});
var FastEnemy = Enemy.expand(function () {
var self = Enemy.call(this);
// Override enemy appearance
self.getChildAt(0).tint = 0x22ff22; // Green tint
// Override default properties
self.health = 10;
self.maxHealth = 10;
self.speed = 4; // Faster than regular enemies
self.damage = 5; // Less damage
// Slightly smaller hitbox, but still bigger than before
self.scale.x = 1.2;
self.scale.y = 1.2;
return self;
});
var EnemyProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphic = self.attachAsset('shuriken', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff00ff
});
self.direction = {
x: 0,
y: 0
};
self.speed = 8;
self.damage = 5;
self.update = function () {
// Move in direction
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Rotate for effect
projectileGraphic.rotation += 0.1;
// Check if off screen
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index !== -1) {
enemyProjectiles.splice(index, 1);
}
return;
}
// Check for player collision
if (self.intersects(player) && !player.isDead) {
player.takeDamage(self.damage);
// Remove projectile
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index !== -1) {
enemyProjectiles.splice(index, 1);
}
}
};
return self;
});
var ExperienceGem = Container.expand(function () {
var self = Container.call(this);
var gemGraphic = self.attachAsset('expGem', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1;
self.speed = 0;
self.magnetRange = 200;
self.isMovingToPlayer = false;
self.update = function () {
if (player.isDead) return;
// Calculate distance to player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If close to player, move toward player (magnetic effect)
if (distance < self.magnetRange || self.isMovingToPlayer) {
self.isMovingToPlayer = true;
self.speed += 0.2;
self.speed = Math.min(self.speed, 15);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// If touching player, give experience
if (self.intersects(player)) {
player.gainExperience(self.value);
// Remove from array and destroy
var index = experienceGems.indexOf(self);
if (index !== -1) {
experienceGems.splice(index, 1);
}
self.destroy();
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFA500
});
self.lifetime = 0;
self.maxLifetime = 15; // Short lifetime for quick explosion effect
self.update = function () {
self.lifetime++;
// Scale up and fade out
var progress = self.lifetime / self.maxLifetime;
explosionGraphic.scale.x = 1 + progress;
explosionGraphic.scale.y = 1 + progress;
explosionGraphic.alpha = 1 - progress;
// Destroy when animation complete
if (self.lifetime >= self.maxLifetime) {
self.destroy();
}
};
return self;
});
var Katana = Container.expand(function () {
var self = Container.call(this);
var katanaGraphic = self.attachAsset('katana', {
anchorX: 0,
anchorY: 0.5
});
self.damage = 20;
self.rotationSpeed = 0.25;
self.attackCooldown = 0;
self.attackCooldownMax = 8; // Frames between attacks
self.level = 1;
// Attack cooldown indicator
self.cooldownBar = new Container();
self.cooldownBar.y = 15;
self.cooldownBarBg = LK.getAsset('player', {
width: 150,
height: 5,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x222222
});
self.cooldownBarFill = LK.getAsset('player', {
width: 150,
height: 5,
anchorX: 0,
anchorY: 0.5,
tint: 0x00FFFF
});
self.cooldownBarFill.x = -75;
self.cooldownBar.addChild(self.cooldownBarBg);
self.cooldownBar.addChild(self.cooldownBarFill);
self.addChild(self.cooldownBar);
self.update = function () {
if (player.isDead) return;
// Rotate around player
self.rotation += self.rotationSpeed;
// Attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Update cooldown bar
var readyPercent = 1 - self.attackCooldown / self.attackCooldownMax;
self.cooldownBarFill.width = 150 * readyPercent;
// Modify color based on readiness
if (readyPercent === 1) {
self.cooldownBarFill.tint = 0x00FF00; // Green when ready
} else {
self.cooldownBarFill.tint = 0x00FFFF; // Cyan when charging
}
// Check for enemies in range and attack
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (self.intersects(enemy) && self.attackCooldown === 0) {
enemy.takeDamage(self.damage);
self.attackCooldown = self.attackCooldownMax;
LK.getSound('slash').play();
// Mark enemy as being hit by katana - this will be used to prevent damage to player
enemy.hitByKatana = true;
enemy.katanaHitTimer = 30; // Frames of immunity after being hit
// Don't break, allow the katana to hit multiple enemies in a single swing
}
}
};
self.levelUp = function () {
self.level += 1;
self.damage += 5;
self.attackCooldownMax = Math.max(10, self.attackCooldownMax - 2);
};
return self;
});
var LevelUpEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphic = self.attachAsset('levelUpIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.lifetime = 0;
self.maxLifetime = 60; // 1 second at 60fps
self.update = function () {
self.lifetime++;
// Scale up and fade out
var progress = self.lifetime / self.maxLifetime;
effectGraphic.scale.x = 1 + progress;
effectGraphic.scale.y = 1 + progress;
effectGraphic.alpha = 0.7 * (1 - progress);
if (self.lifetime >= self.maxLifetime) {
self.destroy();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerBody = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.health = 150;
self.maxHealth = 150;
self.level = 1;
self.experience = 0;
self.experienceToNextLevel = 10;
self.isDead = false;
// Health display
self.healthBar = new Container();
self.healthBar.y = -70;
self.healthBarBg = LK.getAsset('player', {
width: 100,
height: 10,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x222222
});
self.healthBarFill = LK.getAsset('player', {
width: 100,
height: 10,
anchorX: 0,
anchorY: 0.5,
tint: 0x00FF00
});
self.healthBarFill.x = -50;
self.healthBar.addChild(self.healthBarBg);
self.healthBar.addChild(self.healthBarFill);
self.addChild(self.healthBar);
self.update = function () {
if (self.isDead) return;
// Update health bar
self.healthBarFill.width = 100 * (self.health / self.maxHealth);
// Keep player within bounds when using D-Pad
self.x = Math.max(50, Math.min(2048 - 50, self.x));
self.y = Math.max(50, Math.min(2732 - 50, self.y));
};
self.takeDamage = function (amount) {
if (self.isDead) return;
self.health -= amount;
if (self.health <= 0) {
self.health = 0;
self.die();
} else {
// Flash red when damaged
LK.effects.flashObject(playerBody, 0xFF0000, 200);
}
};
self.gainExperience = function (amount) {
if (self.isDead) return;
self.experience += amount;
if (self.experience >= self.experienceToNextLevel) {
self.levelUp();
}
};
self.levelUp = function () {
self.level += 1;
self.experience = 0;
self.experienceToNextLevel = Math.floor(self.experienceToNextLevel * 1.3);
self.maxHealth += 10;
self.health = self.maxHealth;
// Level up effects
var levelUpEffect = new LevelUpEffect();
levelUpEffect.x = self.x;
levelUpEffect.y = self.y;
game.addChild(levelUpEffect);
LK.getSound('levelup').play();
};
self.die = function () {
if (self.isDead) return;
self.isDead = true;
LK.getSound('death').play();
LK.effects.flashObject(playerBody, 0xFF0000, 1000);
// Game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
};
return self;
});
var Shuriken = Container.expand(function () {
var self = Container.call(this);
var shurikenGraphic = self.attachAsset('shuriken', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 15;
self.speed = 10;
self.direction = {
x: 0,
y: 0
};
self.pierceCount = 1; // How many enemies it can hit before disappearing
self.hitEnemies = []; // Track which enemies we've already hit
self.level = 1;
self.update = function () {
// Move in direction
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Rotate the shuriken for effect
shurikenGraphic.rotation += 0.2;
// Check if off screen
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
var index = shurikens.indexOf(self);
if (index !== -1) {
shurikens.splice(index, 1);
}
return;
}
// Check for enemy collisions
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
// Skip enemies we've already hit
if (self.hitEnemies.indexOf(enemy) !== -1) {
continue;
}
if (self.intersects(enemy)) {
enemy.takeDamage(self.damage);
LK.getSound('hit').play();
self.hitEnemies.push(enemy);
// If we've hit enough enemies, destroy this shuriken
if (self.hitEnemies.length >= self.pierceCount) {
self.destroy();
var index = shurikens.indexOf(self);
if (index !== -1) {
shurikens.splice(index, 1);
}
return;
}
}
}
};
self.levelUp = function () {
self.level += 1;
self.damage += 10;
self.pierceCount += 2;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x003300
});
/****
* Game Code
****/
// Global variables
var player;
var katana;
var shurikens = [];
var enemies = [];
var experienceGems = [];
var enemyProjectiles = [];
var dragPosition = null;
var dpad;
var movementSpeed = 8;
var gameTime = 0;
var shurikenTimer = 0;
var enemySpawnTimer = 0;
var waveNumber = 1;
var killCount = 0;
// UI elements
var timeText;
var waveText;
var killCountText;
var levelText;
// Initialize player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Initialize katana
katana = new Katana();
player.addChild(katana);
// Initialize D-Pad
dpad = new DPad();
dpad.x = 200;
dpad.y = 2732 - 200;
game.addChild(dpad);
// Initialize UI
timeText = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timeText.anchor.set(1, 0);
LK.gui.topRight.addChild(timeText);
waveText = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
killCountText = new Text2('Kills: 0', {
size: 60,
fill: 0xFFFFFF
});
killCountText.anchor.set(0, 0);
LK.gui.topRight.addChild(killCountText);
killCountText.y = 70;
levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
levelText.x = 120; // Avoid platform level menu icon area
// Spawn initial enemies
spawnEnemyWave(5);
// Play background music
LK.playMusic('bgmusic');
// Handle player movement
game.down = function (x, y, obj) {
dragPosition = {
x: x,
y: y
};
};
game.move = function (x, y, obj) {
if (dragPosition) {
player.x = x;
player.y = y;
}
};
game.up = function (x, y, obj) {
dragPosition = null;
};
// Main game update loop
game.update = function () {
if (player.isDead) return;
// Update game time (in seconds)
gameTime += 1 / 60;
timeText.setText('Time: ' + Math.floor(gameTime) + 's');
// Update level text
levelText.setText('Level: ' + player.level);
// Handle D-Pad movement
if (dpad.direction.up) {
player.y -= movementSpeed;
}
if (dpad.direction.down) {
player.y += movementSpeed;
}
if (dpad.direction.left) {
player.x -= movementSpeed;
}
if (dpad.direction.right) {
player.x += movementSpeed;
}
// Keep player within bounds
player.x = Math.max(50, Math.min(2048 - 50, player.x));
player.y = Math.max(50, Math.min(2732 - 50, player.y));
// Shuriken spawning logic
shurikenTimer++;
if (shurikenTimer >= 180) {
// Every 3 seconds (60fps * 3)
spawnShuriken();
shurikenTimer = 0;
}
// Enemy spawning logic
enemySpawnTimer++;
var spawnRate = Math.max(400 - waveNumber * 10, 120); // Slower spawns to make game easier
if (enemySpawnTimer >= spawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
}
// Wave progression
if (Math.floor(gameTime) % 30 === 0 && Math.floor(gameTime) > 0 && Math.floor(gameTime / 30) > waveNumber - 1) {
waveNumber++;
waveText.setText('Wave: ' + waveNumber);
spawnEnemyWave(5 + waveNumber);
}
};
// Helper functions
function spawnShuriken() {
for (var i = 0; i < (player.level > 5 ? 2 : 1); i++) {
var shuriken = new Shuriken();
shuriken.x = player.x;
shuriken.y = player.y;
// Choose a random enemy to target, or random direction if no enemies
if (enemies.length > 0) {
var targetEnemy = enemies[Math.floor(Math.random() * enemies.length)];
var dx = targetEnemy.x - player.x;
var dy = targetEnemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
shuriken.direction = {
x: dx / distance,
y: dy / distance
};
} else {
// Random direction if enemy is directly on top of player
var angle = Math.random() * Math.PI * 2;
shuriken.direction = {
x: Math.cos(angle),
y: Math.sin(angle)
};
}
} else {
// Random direction if no enemies
var angle = Math.random() * Math.PI * 2;
shuriken.direction = {
x: Math.cos(angle),
y: Math.sin(angle)
};
}
game.addChild(shuriken);
shurikens.push(shuriken);
LK.getSound('throw').play();
}
}
function spawnEnemy() {
var enemy;
// Choose random enemy type with increasing difficulty by wave
var randType = Math.random();
if (waveNumber >= 3 && randType < 0.25) {
// 25% chance for ranged enemies after wave 3
enemy = new RangedEnemy();
} else if (waveNumber >= 2 && randType < 0.5) {
// 25% chance for tank enemies after wave 2
enemy = new TankEnemy();
} else if (randType < 0.75) {
// 25% chance for fast enemies
enemy = new FastEnemy();
} else {
// 25% chance for regular enemies
enemy = new Enemy();
}
// Scale enemy stats with wave number (reduced scaling for easier gameplay)
enemy.health *= 1 + waveNumber * 0.1;
enemy.maxHealth = enemy.health;
enemy.speed *= 1 + waveNumber * 0.03;
enemy.damage *= 1 + waveNumber * 0.05;
enemy.experienceValue = 2 + Math.floor(waveNumber / 2);
// Spawn outside the screen
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -100;
break;
case 1:
// Right
enemy.x = 2148;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2832;
break;
case 3:
// Left
enemy.x = -100;
enemy.y = Math.random() * 2732;
break;
}
game.addChild(enemy);
enemies.push(enemy);
}
function spawnEnemyWave(count) {
// Add more enemies as game progresses
var actualCount = count + Math.floor(waveNumber / 2);
// Special wave types based on wave number
if (waveNumber % 5 === 0) {
// Boss wave - add a few super tank enemies
var bossCount = Math.min(3, Math.floor(waveNumber / 5));
for (var i = 0; i < bossCount; i++) {
var bossEnemy = new TankEnemy();
bossEnemy.health = 100 + waveNumber * 10;
bossEnemy.maxHealth = bossEnemy.health;
bossEnemy.damage *= 1.5;
bossEnemy.scale.x = 2.5;
bossEnemy.scale.y = 2.5;
bossEnemy.experienceValue = 5 + Math.floor(waveNumber / 2);
// Spawn at random edge
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
bossEnemy.x = Math.random() * 2048;
bossEnemy.y = -100;
break;
case 1:
bossEnemy.x = 2148;
bossEnemy.y = Math.random() * 2732;
break;
case 2:
bossEnemy.x = Math.random() * 2048;
bossEnemy.y = 2832;
break;
case 3:
bossEnemy.x = -100;
bossEnemy.y = Math.random() * 2732;
break;
}
game.addChild(bossEnemy);
enemies.push(bossEnemy);
}
// Add remaining enemies
for (var i = 0; i < actualCount - bossCount; i++) {
spawnEnemy();
}
} else if (waveNumber % 3 === 0) {
// Swarm wave - lots of fast enemies
for (var i = 0; i < actualCount * 1.5; i++) {
var fastEnemy = new FastEnemy();
// Spawn at random edge
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
fastEnemy.x = Math.random() * 2048;
fastEnemy.y = -100;
break;
case 1:
fastEnemy.x = 2148;
fastEnemy.y = Math.random() * 2732;
break;
case 2:
fastEnemy.x = Math.random() * 2048;
fastEnemy.y = 2832;
break;
case 3:
fastEnemy.x = -100;
fastEnemy.y = Math.random() * 2732;
break;
}
game.addChild(fastEnemy);
enemies.push(fastEnemy);
}
} else if (waveNumber % 2 === 0) {
// Ranged wave - more ranged enemies
for (var i = 0; i < actualCount; i++) {
if (i < actualCount / 2) {
var rangedEnemy = new RangedEnemy();
// Spawn at random edge
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
rangedEnemy.x = Math.random() * 2048;
rangedEnemy.y = -100;
break;
case 1:
rangedEnemy.x = 2148;
rangedEnemy.y = Math.random() * 2732;
break;
case 2:
rangedEnemy.x = Math.random() * 2048;
rangedEnemy.y = 2832;
break;
case 3:
rangedEnemy.x = -100;
rangedEnemy.y = Math.random() * 2732;
break;
}
game.addChild(rangedEnemy);
enemies.push(rangedEnemy);
} else {
spawnEnemy();
}
}
} else {
// Normal wave - random enemies
for (var i = 0; i < actualCount; i++) {
spawnEnemy();
}
}
} ===================================================================
--- original.js
+++ change.js
@@ -702,9 +702,9 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x003300
});
/****
* Game Code
a ninja star. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
green exp diamond
a katana. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
monster. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
ninja. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
yellow arrow. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat