/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
var enemyTypes = ['enemy1', 'enemy2', 'enemy3', 'enemy4', 'enemy5', 'enemy6', 'enemy7', 'enemy8'];
var assetId = enemyTypes[type] || 'enemy1';
var enemyGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
var healthOptions = [5600, 7200, 8100];
var baseHealth = healthOptions[Math.floor(Math.random() * healthOptions.length)];
var healthBonus = Math.floor((waveNumber - 1) / 5) * 200; // +200 HP every 5 waves
self.maxHealth = baseHealth + healthBonus;
self.health = self.maxHealth;
self.healthBar = self.addChild(new HealthBar(self.maxHealth, self.health, 80));
self.healthBar.y = -60;
self.healthText = self.addChild(new Text2(self.health.toString(), {
size: 32,
fill: 0xFFFFFF
}));
self.healthText.anchor.set(0.5, 0.5);
self.healthText.y = -80;
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health);
self.healthText.setText(Math.max(0, self.health).toString());
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('hit').play();
if (self.health <= 0) {
return true; // Enemy is dead
}
return false;
};
return self;
});
var EnemyProjectile = Container.expand(function (startX, startY, targetX, targetY) {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20,
tint: 0xFF4444
});
self.x = startX;
self.y = startY;
self.speed = 600; // 10 units per second at 60px per unit (10 units/sec * 60px/unit)
self.damage = 800; // Fixed damage as per requirement
self.maxRange = 600; // 10 units at 60px per unit
self.startX = startX;
self.startY = startY;
self.trails = [];
// Calculate precise initial direction to player's current position
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
self.update = function () {
// Move in fixed direction at constant speed
self.x += self.dirX * self.speed / 60; // Convert to per-tick movement
self.y += self.dirY * self.speed / 60;
// Create trail effect every few frames
if (LK.ticks % 4 === 0) {
var trail = game.addChild(LK.getAsset('enemyTrail', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
rotation: Math.atan2(self.dirY, self.dirX),
alpha: 0.7
}));
self.trails.push(trail);
// Fade out trail
tween(trail, {
alpha: 0
}, {
duration: 250,
onFinish: function onFinish() {
trail.destroy();
var index = self.trails.indexOf(trail);
if (index > -1) {
self.trails.splice(index, 1);
}
}
});
}
// Check collision with player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distanceToPlayer = Math.sqrt(dx * dx + dy * dy);
if (distanceToPlayer <= 50) {
// Hit radius
var isDead = player.takeDamage(self.damage);
if (isDead) {
LK.showGameOver();
return;
}
self.cleanupTrails();
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index > -1) {
enemyProjectiles.splice(index, 1);
}
return;
}
// Check if projectile has traveled beyond maximum range
var traveledDistance = Math.sqrt((self.x - self.startX) * (self.x - self.startX) + (self.y - self.startY) * (self.y - self.startY));
if (traveledDistance >= self.maxRange) {
self.cleanupTrails();
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index > -1) {
enemyProjectiles.splice(index, 1);
}
return;
}
// Remove if out of bounds
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.cleanupTrails();
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index > -1) {
enemyProjectiles.splice(index, 1);
}
}
};
self.cleanupTrails = function () {
for (var i = 0; i < self.trails.length; i++) {
self.trails[i].destroy();
}
self.trails = [];
};
return self;
});
var HealthBar = Container.expand(function (maxHealth, currentHealth, width) {
var self = Container.call(this);
var bgBar = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: width || 80
});
var fillBar = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5,
width: width || 80,
x: -(width || 80) / 2
});
self.maxHealth = maxHealth;
self.currentHealth = currentHealth;
self.updateHealth = function (newHealth) {
self.currentHealth = Math.max(0, Math.min(self.maxHealth, newHealth));
var healthPercent = self.currentHealth / self.maxHealth;
fillBar.width = (width || 80) * healthPercent;
if (healthPercent > 0.6) {
fillBar.tint = 0x4CAF50; // Green
} else if (healthPercent > 0.3) {
fillBar.tint = 0xFFC107; // Yellow
} else {
fillBar.tint = 0xF44336; // Red
}
};
self.updateHealth(currentHealth);
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 9200;
self.health = self.maxHealth;
self.lastDamageTime = 0;
self.attackRange = 480; // 8 units at ~60px per unit
self.attackDamage = 1200;
self.lastAttackTime = 0;
self.attackCooldown = 500; // 0.5 seconds between attacks
self.healthBar = self.addChild(new HealthBar(self.maxHealth, self.health, 100));
self.healthBar.y = -70;
self.healthText = self.addChild(new Text2(self.health.toString(), {
size: 36,
fill: 0xFFFFFF
}));
self.healthText.anchor.set(0.5, 0.5);
self.healthText.y = -90;
self.takeDamage = function (damage) {
self.health -= damage;
self.lastDamageTime = LK.ticks;
self.healthBar.updateHealth(self.health);
self.healthText.setText(Math.max(0, self.health).toString());
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('playerHit').play();
if (self.health <= 0) {
return true; // Player is dead
}
return false;
};
self.update = function () {
// Health regeneration after 15 seconds (900 ticks at 60fps)
if (LK.ticks - self.lastDamageTime > 900 && self.health < self.maxHealth) {
self.health = Math.min(self.maxHealth, self.health + 800 / 60); // 800 HP per second
self.healthBar.updateHealth(self.health);
self.healthText.setText(Math.floor(self.health).toString());
}
// Auto attack nearby enemies with projectiles
if (LK.ticks - self.lastAttackTime > self.attackCooldown / 16.67) {
// Convert ms to ticks
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
if (nearestEnemy) {
self.lastAttackTime = LK.ticks;
// Create projectile to target
var projectile = game.addChild(new PlayerProjectile(self.x, self.y, nearestEnemy.x, nearestEnemy.y));
playerProjectiles.push(projectile);
}
}
};
return self;
});
var PlayerProjectile = Container.expand(function (startX, startY, targetX, targetY) {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
width: 15,
height: 15,
tint: 0xFFFF00
});
self.x = startX;
self.y = startY;
self.speed = 800;
self.damage = 1200;
self.trails = [];
// Calculate initial direction
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
self.update = function () {
// Move projectile
self.x += self.dirX * self.speed / 60;
self.y += self.dirY * self.speed / 60;
// Create trail effect every few frames
if (LK.ticks % 3 === 0) {
var trail = game.addChild(LK.getAsset('playerTrail', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
rotation: Math.atan2(self.dirY, self.dirX),
alpha: 0.8
}));
self.trails.push(trail);
// Fade out trail
tween(trail, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
trail.destroy();
var index = self.trails.indexOf(trail);
if (index > -1) {
self.trails.splice(index, 1);
}
}
});
}
// Remove if out of bounds
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.cleanupTrails();
self.destroy();
var index = playerProjectiles.indexOf(self);
if (index > -1) {
playerProjectiles.splice(index, 1);
}
}
};
self.cleanupTrails = function () {
for (var i = 0; i < self.trails.length; i++) {
self.trails[i].destroy();
}
self.trails = [];
};
return self;
});
var PowerupIcon = Container.expand(function (type) {
var self = Container.call(this);
var assetMap = {
'maxHealth': 'powerupMaxHealth',
'heal': 'powerupHeal',
'damage': 'powerupDamage'
};
var iconGraphics = self.attachAsset(assetMap[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.spawnTime = LK.ticks;
var labelText = '';
if (type === 'maxHealth') labelText = '+HP';else if (type === 'heal') labelText = 'HEAL';else if (type === 'damage') labelText = '+DMG';
var label = self.addChild(new Text2(labelText, {
size: 24,
fill: 0xFFFFFF
}));
label.anchor.set(0.5, 0.5);
label.y = 50;
self.update = function () {
// Check collision with player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 80) {
// Collision radius
applyPowerup(self.type);
destroyPowerupSelection();
return;
}
// Auto-destroy after 10 seconds (600 ticks at 60fps)
if (LK.ticks - self.spawnTime >= 600) {
destroyPowerupSelection();
}
};
return self;
});
var VirtualJoystick = Container.expand(function () {
var self = Container.call(this);
var joystickBase = self.attachAsset('joystick', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
var joystickKnob = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.isActive = false;
self.startX = 0;
self.startY = 0;
self.knobX = 0;
self.knobY = 0;
self.maxDistance = 50;
self.visible = false;
self.activate = function (x, y) {
self.isActive = true;
self.visible = true;
self.x = x;
self.y = y;
self.startX = x;
self.startY = y;
joystickKnob.x = 0;
joystickKnob.y = 0;
};
self.updateKnob = function (x, y) {
if (!self.isActive) return {
x: 0,
y: 0
};
var dx = x - self.startX;
var dy = y - self.startY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.maxDistance) {
dx = dx / distance * self.maxDistance;
dy = dy / distance * self.maxDistance;
}
joystickKnob.x = dx;
joystickKnob.y = dy;
return {
x: dx / self.maxDistance,
y: dy / self.maxDistance
};
};
self.deactivate = function () {
self.isActive = false;
self.visible = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2E2E2E
});
/****
* Game Code
****/
var player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
var enemies = [];
var enemyProjectiles = [];
var playerProjectiles = [];
var powerupIcons = [];
var showingPowerups = false;
var joystick = LK.gui.addChild(new VirtualJoystick());
var isDragging = false;
var lastEnemyAttackTime = 0;
var waveNumber = 1;
var enemiesKilledThisWave = 0;
var waveText = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 100;
function showNotification(message) {
var notification = game.addChild(new Text2(message, {
size: 48,
fill: 0xFFFF00
}));
notification.anchor.set(0.5, 0.5);
notification.x = 1024;
notification.y = 800;
notification.alpha = 0;
tween(notification, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(notification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
notification.destroy();
}
});
}, 2000);
}
});
}
function createPowerupSelection() {
if (showingPowerups) return;
showingPowerups = true;
var types = ['maxHealth', 'heal', 'damage'];
// Select one random powerup type
var randomType = types[Math.floor(Math.random() * types.length)];
var powerup = game.addChild(new PowerupIcon(randomType));
powerup.x = 1024;
powerup.y = 1366;
powerupIcons.push(powerup);
// Scale animation
powerup.scaleX = 0;
powerup.scaleY = 0;
tween(powerup, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.bounceOut
});
// Set 10 second timeout for automatic cleanup
LK.setTimeout(function () {
if (showingPowerups) {
destroyPowerupSelection();
}
}, 10000);
}
function applyPowerup(type) {
if (type === 'maxHealth') {
player.maxHealth += 2000;
player.healthBar.maxHealth = player.maxHealth;
player.healthBar.updateHealth(player.health);
showNotification('Maks can arttı!');
} else if (type === 'heal') {
player.health = Math.min(player.maxHealth, player.health + 5000);
player.healthBar.updateHealth(player.health);
player.healthText.setText(Math.floor(player.health).toString());
showNotification('+5000 can!');
} else if (type === 'damage') {
player.attackDamage += 400;
showNotification('Hasar +400!');
}
LK.getSound('powerup').play();
}
function destroyPowerupSelection() {
for (var i = 0; i < powerupIcons.length; i++) {
powerupIcons[i].destroy();
}
powerupIcons = [];
showingPowerups = false;
}
function spawnEnemyWave() {
// Clear existing enemies
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
// Clear existing projectiles
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
enemyProjectiles[i].destroy();
enemyProjectiles.splice(i, 1);
}
// Spawn 3 random enemies
for (var i = 0; i < 3; i++) {
var enemyType = Math.floor(Math.random() * 8);
var enemy = game.addChild(new Enemy(enemyType));
// Random position ensuring at least 8 units away from player spawn (1024, 1366)
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 50) {
var angle = Math.random() * Math.PI * 2;
var distance = 300 + Math.random() * 400;
enemy.x = 1024 + Math.cos(angle) * distance;
enemy.y = 1366 + Math.sin(angle) * distance;
// Keep enemies within bounds
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(100, Math.min(2632, enemy.y));
// Check distance from player spawn point (1024, 1366)
var dx = enemy.x - 1024;
var dy = enemy.y - 1366;
var distanceFromSpawn = Math.sqrt(dx * dx + dy * dy);
if (distanceFromSpawn >= 8) {
validPosition = true;
}
attempts++;
}
enemies.push(enemy);
}
waveText.setText('Wave: ' + waveNumber);
}
function createWaveTransition() {
// Check for enemy scaling every 5 waves
if (waveNumber % 5 === 0) {
LK.setTimeout(function () {
showNotification('Düşman hasarı +200 arttı!');
}, 500);
LK.setTimeout(function () {
showNotification('Düşman canı +200 arttı!');
}, 1500);
}
// Create 8 spinning objects for animation
var transitionObjects = [];
var enemyTypes = ['enemy1', 'enemy2', 'enemy3', 'enemy4', 'enemy5', 'enemy6', 'enemy7', 'enemy8'];
for (var i = 0; i < 8; i++) {
var obj = game.addChild(LK.getAsset(enemyTypes[i], {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + Math.cos(i * Math.PI / 4) * 300,
y: 1366 + Math.sin(i * Math.PI / 4) * 300,
scaleX: 1.5,
scaleY: 1.5
}));
transitionObjects.push(obj);
// Animate spinning and moving
tween(obj, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.linear
});
tween(obj, {
x: 1024 + Math.cos(Math.random() * Math.PI * 2) * 500,
y: 1366 + Math.sin(Math.random() * Math.PI * 2) * 500
}, {
duration: 1500,
easing: tween.easeInOut
});
}
// After animation, select 3 random objects to become enemies
LK.setTimeout(function () {
// Randomly select 3 objects
var selectedIndices = [];
while (selectedIndices.length < 3) {
var randomIndex = Math.floor(Math.random() * 8);
if (selectedIndices.indexOf(randomIndex) === -1) {
selectedIndices.push(randomIndex);
}
}
// Convert selected objects to enemies
for (var i = 0; i < selectedIndices.length; i++) {
var selectedObj = transitionObjects[selectedIndices[i]];
var enemyType = selectedIndices[i];
var enemy = game.addChild(new Enemy(enemyType));
enemy.x = selectedObj.x;
enemy.y = selectedObj.y;
enemies.push(enemy);
}
// Remove all transition objects
for (var i = 0; i < transitionObjects.length; i++) {
transitionObjects[i].destroy();
}
// Show powerup selection every 3 waves
if (waveNumber % 3 === 0) {
LK.setTimeout(function () {
createPowerupSelection();
}, 500);
}
}, 2000);
}
// Initialize first wave
spawnEnemyWave();
function handleMove(x, y, obj) {
if (isDragging) {
var movement = joystick.updateKnob(x, y);
// Move player based on joystick input with increased speed for dodging
var speed = 8;
player.x += movement.x * speed;
player.y += movement.y * speed;
// Keep player within bounds
player.x = Math.max(50, Math.min(1998, player.x));
player.y = Math.max(50, Math.min(2682, player.y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
isDragging = true;
joystick.activate(x, y);
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
isDragging = false;
joystick.deactivate();
};
game.update = function () {
// Check if player is dead
if (player.health <= 0) {
LK.showGameOver();
return;
}
// Handle player projectile collisions
for (var p = playerProjectiles.length - 1; p >= 0; p--) {
var projectile = playerProjectiles[p];
var hitEnemy = false;
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
var dx = enemy.x - projectile.x;
var dy = enemy.y - projectile.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 40) {
// Hit radius
var isDead = enemy.takeDamage(player.attackDamage);
if (isDead) {
var index = enemies.indexOf(enemy);
if (index > -1) {
enemy.destroy();
enemies.splice(index, 1);
enemiesKilledThisWave++;
if (enemiesKilledThisWave >= 3) {
enemiesKilledThisWave = 0;
waveNumber++;
waveText.setText('Wave: ' + waveNumber);
// Create wave transition animation
createWaveTransition();
}
}
}
hitEnemy = true;
break;
}
}
if (hitEnemy) {
projectile.cleanupTrails();
projectile.destroy();
playerProjectiles.splice(p, 1);
}
}
// Wave completion is now handled by enemy kill counter in Player class
// Enemy attacks every second (60 ticks)
if (LK.ticks - lastEnemyAttackTime >= 60 && enemies.length > 0) {
lastEnemyAttackTime = LK.ticks;
// Find enemies within attack range of player (10 units = 600 pixels)
var enemiesInRange = [];
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 600) {
enemiesInRange.push(enemy);
}
}
// Only attack if there are enemies in range
if (enemiesInRange.length > 0) {
var attackingEnemy = enemiesInRange[Math.floor(Math.random() * enemiesInRange.length)];
// Create projectile from enemy to player
var projectile = game.addChild(new EnemyProjectile(attackingEnemy.x, attackingEnemy.y, player.x, player.y));
enemyProjectiles.push(projectile);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
var enemyTypes = ['enemy1', 'enemy2', 'enemy3', 'enemy4', 'enemy5', 'enemy6', 'enemy7', 'enemy8'];
var assetId = enemyTypes[type] || 'enemy1';
var enemyGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
var healthOptions = [5600, 7200, 8100];
var baseHealth = healthOptions[Math.floor(Math.random() * healthOptions.length)];
var healthBonus = Math.floor((waveNumber - 1) / 5) * 200; // +200 HP every 5 waves
self.maxHealth = baseHealth + healthBonus;
self.health = self.maxHealth;
self.healthBar = self.addChild(new HealthBar(self.maxHealth, self.health, 80));
self.healthBar.y = -60;
self.healthText = self.addChild(new Text2(self.health.toString(), {
size: 32,
fill: 0xFFFFFF
}));
self.healthText.anchor.set(0.5, 0.5);
self.healthText.y = -80;
self.takeDamage = function (damage) {
self.health -= damage;
self.healthBar.updateHealth(self.health);
self.healthText.setText(Math.max(0, self.health).toString());
LK.effects.flashObject(self, 0xFF0000, 200);
LK.getSound('hit').play();
if (self.health <= 0) {
return true; // Enemy is dead
}
return false;
};
return self;
});
var EnemyProjectile = Container.expand(function (startX, startY, targetX, targetY) {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 20,
tint: 0xFF4444
});
self.x = startX;
self.y = startY;
self.speed = 600; // 10 units per second at 60px per unit (10 units/sec * 60px/unit)
self.damage = 800; // Fixed damage as per requirement
self.maxRange = 600; // 10 units at 60px per unit
self.startX = startX;
self.startY = startY;
self.trails = [];
// Calculate precise initial direction to player's current position
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
self.update = function () {
// Move in fixed direction at constant speed
self.x += self.dirX * self.speed / 60; // Convert to per-tick movement
self.y += self.dirY * self.speed / 60;
// Create trail effect every few frames
if (LK.ticks % 4 === 0) {
var trail = game.addChild(LK.getAsset('enemyTrail', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
rotation: Math.atan2(self.dirY, self.dirX),
alpha: 0.7
}));
self.trails.push(trail);
// Fade out trail
tween(trail, {
alpha: 0
}, {
duration: 250,
onFinish: function onFinish() {
trail.destroy();
var index = self.trails.indexOf(trail);
if (index > -1) {
self.trails.splice(index, 1);
}
}
});
}
// Check collision with player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distanceToPlayer = Math.sqrt(dx * dx + dy * dy);
if (distanceToPlayer <= 50) {
// Hit radius
var isDead = player.takeDamage(self.damage);
if (isDead) {
LK.showGameOver();
return;
}
self.cleanupTrails();
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index > -1) {
enemyProjectiles.splice(index, 1);
}
return;
}
// Check if projectile has traveled beyond maximum range
var traveledDistance = Math.sqrt((self.x - self.startX) * (self.x - self.startX) + (self.y - self.startY) * (self.y - self.startY));
if (traveledDistance >= self.maxRange) {
self.cleanupTrails();
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index > -1) {
enemyProjectiles.splice(index, 1);
}
return;
}
// Remove if out of bounds
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.cleanupTrails();
self.destroy();
var index = enemyProjectiles.indexOf(self);
if (index > -1) {
enemyProjectiles.splice(index, 1);
}
}
};
self.cleanupTrails = function () {
for (var i = 0; i < self.trails.length; i++) {
self.trails[i].destroy();
}
self.trails = [];
};
return self;
});
var HealthBar = Container.expand(function (maxHealth, currentHealth, width) {
var self = Container.call(this);
var bgBar = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: width || 80
});
var fillBar = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5,
width: width || 80,
x: -(width || 80) / 2
});
self.maxHealth = maxHealth;
self.currentHealth = currentHealth;
self.updateHealth = function (newHealth) {
self.currentHealth = Math.max(0, Math.min(self.maxHealth, newHealth));
var healthPercent = self.currentHealth / self.maxHealth;
fillBar.width = (width || 80) * healthPercent;
if (healthPercent > 0.6) {
fillBar.tint = 0x4CAF50; // Green
} else if (healthPercent > 0.3) {
fillBar.tint = 0xFFC107; // Yellow
} else {
fillBar.tint = 0xF44336; // Red
}
};
self.updateHealth(currentHealth);
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 9200;
self.health = self.maxHealth;
self.lastDamageTime = 0;
self.attackRange = 480; // 8 units at ~60px per unit
self.attackDamage = 1200;
self.lastAttackTime = 0;
self.attackCooldown = 500; // 0.5 seconds between attacks
self.healthBar = self.addChild(new HealthBar(self.maxHealth, self.health, 100));
self.healthBar.y = -70;
self.healthText = self.addChild(new Text2(self.health.toString(), {
size: 36,
fill: 0xFFFFFF
}));
self.healthText.anchor.set(0.5, 0.5);
self.healthText.y = -90;
self.takeDamage = function (damage) {
self.health -= damage;
self.lastDamageTime = LK.ticks;
self.healthBar.updateHealth(self.health);
self.healthText.setText(Math.max(0, self.health).toString());
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('playerHit').play();
if (self.health <= 0) {
return true; // Player is dead
}
return false;
};
self.update = function () {
// Health regeneration after 15 seconds (900 ticks at 60fps)
if (LK.ticks - self.lastDamageTime > 900 && self.health < self.maxHealth) {
self.health = Math.min(self.maxHealth, self.health + 800 / 60); // 800 HP per second
self.healthBar.updateHealth(self.health);
self.healthText.setText(Math.floor(self.health).toString());
}
// Auto attack nearby enemies with projectiles
if (LK.ticks - self.lastAttackTime > self.attackCooldown / 16.67) {
// Convert ms to ticks
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
if (nearestEnemy) {
self.lastAttackTime = LK.ticks;
// Create projectile to target
var projectile = game.addChild(new PlayerProjectile(self.x, self.y, nearestEnemy.x, nearestEnemy.y));
playerProjectiles.push(projectile);
}
}
};
return self;
});
var PlayerProjectile = Container.expand(function (startX, startY, targetX, targetY) {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
width: 15,
height: 15,
tint: 0xFFFF00
});
self.x = startX;
self.y = startY;
self.speed = 800;
self.damage = 1200;
self.trails = [];
// Calculate initial direction
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / distance;
self.dirY = dy / distance;
self.update = function () {
// Move projectile
self.x += self.dirX * self.speed / 60;
self.y += self.dirY * self.speed / 60;
// Create trail effect every few frames
if (LK.ticks % 3 === 0) {
var trail = game.addChild(LK.getAsset('playerTrail', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
rotation: Math.atan2(self.dirY, self.dirX),
alpha: 0.8
}));
self.trails.push(trail);
// Fade out trail
tween(trail, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
trail.destroy();
var index = self.trails.indexOf(trail);
if (index > -1) {
self.trails.splice(index, 1);
}
}
});
}
// Remove if out of bounds
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.cleanupTrails();
self.destroy();
var index = playerProjectiles.indexOf(self);
if (index > -1) {
playerProjectiles.splice(index, 1);
}
}
};
self.cleanupTrails = function () {
for (var i = 0; i < self.trails.length; i++) {
self.trails[i].destroy();
}
self.trails = [];
};
return self;
});
var PowerupIcon = Container.expand(function (type) {
var self = Container.call(this);
var assetMap = {
'maxHealth': 'powerupMaxHealth',
'heal': 'powerupHeal',
'damage': 'powerupDamage'
};
var iconGraphics = self.attachAsset(assetMap[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.spawnTime = LK.ticks;
var labelText = '';
if (type === 'maxHealth') labelText = '+HP';else if (type === 'heal') labelText = 'HEAL';else if (type === 'damage') labelText = '+DMG';
var label = self.addChild(new Text2(labelText, {
size: 24,
fill: 0xFFFFFF
}));
label.anchor.set(0.5, 0.5);
label.y = 50;
self.update = function () {
// Check collision with player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 80) {
// Collision radius
applyPowerup(self.type);
destroyPowerupSelection();
return;
}
// Auto-destroy after 10 seconds (600 ticks at 60fps)
if (LK.ticks - self.spawnTime >= 600) {
destroyPowerupSelection();
}
};
return self;
});
var VirtualJoystick = Container.expand(function () {
var self = Container.call(this);
var joystickBase = self.attachAsset('joystick', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
var joystickKnob = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.isActive = false;
self.startX = 0;
self.startY = 0;
self.knobX = 0;
self.knobY = 0;
self.maxDistance = 50;
self.visible = false;
self.activate = function (x, y) {
self.isActive = true;
self.visible = true;
self.x = x;
self.y = y;
self.startX = x;
self.startY = y;
joystickKnob.x = 0;
joystickKnob.y = 0;
};
self.updateKnob = function (x, y) {
if (!self.isActive) return {
x: 0,
y: 0
};
var dx = x - self.startX;
var dy = y - self.startY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > self.maxDistance) {
dx = dx / distance * self.maxDistance;
dy = dy / distance * self.maxDistance;
}
joystickKnob.x = dx;
joystickKnob.y = dy;
return {
x: dx / self.maxDistance,
y: dy / self.maxDistance
};
};
self.deactivate = function () {
self.isActive = false;
self.visible = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2E2E2E
});
/****
* Game Code
****/
var player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
var enemies = [];
var enemyProjectiles = [];
var playerProjectiles = [];
var powerupIcons = [];
var showingPowerups = false;
var joystick = LK.gui.addChild(new VirtualJoystick());
var isDragging = false;
var lastEnemyAttackTime = 0;
var waveNumber = 1;
var enemiesKilledThisWave = 0;
var waveText = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 100;
function showNotification(message) {
var notification = game.addChild(new Text2(message, {
size: 48,
fill: 0xFFFF00
}));
notification.anchor.set(0.5, 0.5);
notification.x = 1024;
notification.y = 800;
notification.alpha = 0;
tween(notification, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(notification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
notification.destroy();
}
});
}, 2000);
}
});
}
function createPowerupSelection() {
if (showingPowerups) return;
showingPowerups = true;
var types = ['maxHealth', 'heal', 'damage'];
// Select one random powerup type
var randomType = types[Math.floor(Math.random() * types.length)];
var powerup = game.addChild(new PowerupIcon(randomType));
powerup.x = 1024;
powerup.y = 1366;
powerupIcons.push(powerup);
// Scale animation
powerup.scaleX = 0;
powerup.scaleY = 0;
tween(powerup, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.bounceOut
});
// Set 10 second timeout for automatic cleanup
LK.setTimeout(function () {
if (showingPowerups) {
destroyPowerupSelection();
}
}, 10000);
}
function applyPowerup(type) {
if (type === 'maxHealth') {
player.maxHealth += 2000;
player.healthBar.maxHealth = player.maxHealth;
player.healthBar.updateHealth(player.health);
showNotification('Maks can arttı!');
} else if (type === 'heal') {
player.health = Math.min(player.maxHealth, player.health + 5000);
player.healthBar.updateHealth(player.health);
player.healthText.setText(Math.floor(player.health).toString());
showNotification('+5000 can!');
} else if (type === 'damage') {
player.attackDamage += 400;
showNotification('Hasar +400!');
}
LK.getSound('powerup').play();
}
function destroyPowerupSelection() {
for (var i = 0; i < powerupIcons.length; i++) {
powerupIcons[i].destroy();
}
powerupIcons = [];
showingPowerups = false;
}
function spawnEnemyWave() {
// Clear existing enemies
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
enemies.splice(i, 1);
}
// Clear existing projectiles
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
enemyProjectiles[i].destroy();
enemyProjectiles.splice(i, 1);
}
// Spawn 3 random enemies
for (var i = 0; i < 3; i++) {
var enemyType = Math.floor(Math.random() * 8);
var enemy = game.addChild(new Enemy(enemyType));
// Random position ensuring at least 8 units away from player spawn (1024, 1366)
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 50) {
var angle = Math.random() * Math.PI * 2;
var distance = 300 + Math.random() * 400;
enemy.x = 1024 + Math.cos(angle) * distance;
enemy.y = 1366 + Math.sin(angle) * distance;
// Keep enemies within bounds
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(100, Math.min(2632, enemy.y));
// Check distance from player spawn point (1024, 1366)
var dx = enemy.x - 1024;
var dy = enemy.y - 1366;
var distanceFromSpawn = Math.sqrt(dx * dx + dy * dy);
if (distanceFromSpawn >= 8) {
validPosition = true;
}
attempts++;
}
enemies.push(enemy);
}
waveText.setText('Wave: ' + waveNumber);
}
function createWaveTransition() {
// Check for enemy scaling every 5 waves
if (waveNumber % 5 === 0) {
LK.setTimeout(function () {
showNotification('Düşman hasarı +200 arttı!');
}, 500);
LK.setTimeout(function () {
showNotification('Düşman canı +200 arttı!');
}, 1500);
}
// Create 8 spinning objects for animation
var transitionObjects = [];
var enemyTypes = ['enemy1', 'enemy2', 'enemy3', 'enemy4', 'enemy5', 'enemy6', 'enemy7', 'enemy8'];
for (var i = 0; i < 8; i++) {
var obj = game.addChild(LK.getAsset(enemyTypes[i], {
anchorX: 0.5,
anchorY: 0.5,
x: 1024 + Math.cos(i * Math.PI / 4) * 300,
y: 1366 + Math.sin(i * Math.PI / 4) * 300,
scaleX: 1.5,
scaleY: 1.5
}));
transitionObjects.push(obj);
// Animate spinning and moving
tween(obj, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.linear
});
tween(obj, {
x: 1024 + Math.cos(Math.random() * Math.PI * 2) * 500,
y: 1366 + Math.sin(Math.random() * Math.PI * 2) * 500
}, {
duration: 1500,
easing: tween.easeInOut
});
}
// After animation, select 3 random objects to become enemies
LK.setTimeout(function () {
// Randomly select 3 objects
var selectedIndices = [];
while (selectedIndices.length < 3) {
var randomIndex = Math.floor(Math.random() * 8);
if (selectedIndices.indexOf(randomIndex) === -1) {
selectedIndices.push(randomIndex);
}
}
// Convert selected objects to enemies
for (var i = 0; i < selectedIndices.length; i++) {
var selectedObj = transitionObjects[selectedIndices[i]];
var enemyType = selectedIndices[i];
var enemy = game.addChild(new Enemy(enemyType));
enemy.x = selectedObj.x;
enemy.y = selectedObj.y;
enemies.push(enemy);
}
// Remove all transition objects
for (var i = 0; i < transitionObjects.length; i++) {
transitionObjects[i].destroy();
}
// Show powerup selection every 3 waves
if (waveNumber % 3 === 0) {
LK.setTimeout(function () {
createPowerupSelection();
}, 500);
}
}, 2000);
}
// Initialize first wave
spawnEnemyWave();
function handleMove(x, y, obj) {
if (isDragging) {
var movement = joystick.updateKnob(x, y);
// Move player based on joystick input with increased speed for dodging
var speed = 8;
player.x += movement.x * speed;
player.y += movement.y * speed;
// Keep player within bounds
player.x = Math.max(50, Math.min(1998, player.x));
player.y = Math.max(50, Math.min(2682, player.y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
isDragging = true;
joystick.activate(x, y);
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
isDragging = false;
joystick.deactivate();
};
game.update = function () {
// Check if player is dead
if (player.health <= 0) {
LK.showGameOver();
return;
}
// Handle player projectile collisions
for (var p = playerProjectiles.length - 1; p >= 0; p--) {
var projectile = playerProjectiles[p];
var hitEnemy = false;
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
var dx = enemy.x - projectile.x;
var dy = enemy.y - projectile.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 40) {
// Hit radius
var isDead = enemy.takeDamage(player.attackDamage);
if (isDead) {
var index = enemies.indexOf(enemy);
if (index > -1) {
enemy.destroy();
enemies.splice(index, 1);
enemiesKilledThisWave++;
if (enemiesKilledThisWave >= 3) {
enemiesKilledThisWave = 0;
waveNumber++;
waveText.setText('Wave: ' + waveNumber);
// Create wave transition animation
createWaveTransition();
}
}
}
hitEnemy = true;
break;
}
}
if (hitEnemy) {
projectile.cleanupTrails();
projectile.destroy();
playerProjectiles.splice(p, 1);
}
}
// Wave completion is now handled by enemy kill counter in Player class
// Enemy attacks every second (60 ticks)
if (LK.ticks - lastEnemyAttackTime >= 60 && enemies.length > 0) {
lastEnemyAttackTime = LK.ticks;
// Find enemies within attack range of player (10 units = 600 pixels)
var enemiesInRange = [];
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 600) {
enemiesInRange.push(enemy);
}
}
// Only attack if there are enemies in range
if (enemiesInRange.length > 0) {
var attackingEnemy = enemiesInRange[Math.floor(Math.random() * enemiesInRange.length)];
// Create projectile from enemy to player
var projectile = game.addChild(new EnemyProjectile(attackingEnemy.x, attackingEnemy.y, player.x, player.y));
enemyProjectiles.push(projectile);
}
}
};