User prompt
que el personage aguante 3 golpes
User prompt
que el juego sea infinito
User prompt
un menu
User prompt
que el menu prinsipal tenga las obciones de obciones jugar y creditos
User prompt
que haya un menu prinsipal
User prompt
que el personage aguanta 3 ataques
User prompt
que el juego sea infinito
User prompt
que los ataques sean un fuego teledirigido y un orbe explosivo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
crea 2 ataques nuevos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que hayan 4 enemigos mas
User prompt
que tenga un sistema de ordas que aumentan la dificultad
User prompt
que haya un refugio que luego de 10000 puntos el personage entre y le de un multiplicador de daño mas un escudo al salir por 6 seg ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
añade una vase que luego de tener sierto puntage el personage entre a resguardarse
User prompt
que el ataque de orbe no se pueda tirar mas de 7 veses por orda
User prompt
que el ataque de orbe tenga un tiempo de 7 seg de recarga
User prompt
que el ataque de orbe tenga una recarga de 7
User prompt
que los enemigos tengan una barra de vida
User prompt
ahora que el proyectil ligrto se active con un boton
User prompt
que cada enemigo tenga distinta cantidad de vida
User prompt
ahora que el ataque de luz tenga solo 12 seg de recarga
User prompt
ahora que el ataque de luz tenga una recarga de 3 segundos y que elimine a todos los enemigos en pantalla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
que el ataque de fuego valla directamente al enemigo
User prompt
que los ataques del personage se activen con un boton en pantalla
User prompt
que haya una gran bariedad de monstruos
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BerserkerShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('berserkerShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5 + Math.random() * 1;
self.health = 5;
self.maxHealth = 5;
self.monsterType = 'berserker';
self.enraged = false;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
// Enrage when health is low
if (self.health <= self.maxHealth * 0.4 && !self.enraged) {
self.enraged = true;
self.speed *= 2;
shadowGraphics.tint = 0xff0000;
}
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Berserker effect when enraged
if (self.enraged) {
var shake = (Math.random() - 0.5) * 4;
self.x += shake;
self.y += shake;
// Pulsing red effect
var pulse = 1 + Math.sin(LK.ticks * 0.8) * 0.5;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var BomberShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('bomberShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2 + Math.random() * 1;
self.health = 2;
self.maxHealth = 2;
self.monsterType = 'bomber';
self.exploding = false;
self.explosionTimer = 30;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
if (distanceToHero < 100 && !self.exploding) {
self.exploding = true;
shadowGraphics.tint = 0xff4444;
}
if (self.exploding) {
self.explosionTimer--;
var flash = Math.sin(self.explosionTimer * 0.5) > 0 ? 0xff0000 : 0xffff00;
shadowGraphics.tint = flash;
if (self.explosionTimer <= 0) {
// Create explosion effect
for (var i = 0; i < 6; i++) {
var explosionAngle = i / 6 * Math.PI * 2;
var fragment = new Shadow();
fragment.x = self.x + Math.cos(explosionAngle) * 20;
fragment.y = self.y + Math.sin(explosionAngle) * 20;
fragment.speed = 2;
shadows.push(fragment);
game.addChild(fragment);
}
}
} else {
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var ExplosiveOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 180; // 3 seconds
self.speed = 3;
self.explosionRadius = 150;
self.damage = 4;
self.velocityX = 0;
self.velocityY = 0;
self.update = function () {
self.lifetime--;
self.x += self.velocityX;
self.y += self.velocityY;
// Pulsing effect
var scale = 1 + Math.sin(LK.ticks * 0.4) * 0.3;
orbGraphics.scaleX = scale;
orbGraphics.scaleY = scale;
// Color shifting from blue to red as it gets closer to explosion
var timeRatio = 1 - self.lifetime / 180;
var red = Math.floor(timeRatio * 255);
var blue = Math.floor((1 - timeRatio) * 255);
orbGraphics.tint = red << 16 | blue;
};
return self;
});
var FastShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('fastShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3 + Math.random() * 2;
self.health = 1;
self.maxHealth = 1;
self.monsterType = 'fast';
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Add erratic movement
self.x += Math.sin(LK.ticks * 0.2) * 2;
self.y += Math.cos(LK.ticks * 0.15) * 2;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var FireSpell = Container.expand(function () {
var self = Container.call(this);
var spellGraphics = self.attachAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 30; // Half second
self.radius = 80;
self.update = function () {
self.lifetime--;
// Grow the spell
var scale = 1 + (30 - self.lifetime) / 30;
spellGraphics.scaleX = scale;
spellGraphics.scaleY = scale;
spellGraphics.alpha = self.lifetime / 30;
};
return self;
});
var GuidedFire = Container.expand(function () {
var self = Container.call(this);
var fireGraphics = self.attachAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 300; // 5 seconds
self.speed = 4;
self.target = null;
self.damage = 3;
self.update = function () {
self.lifetime--;
// Find nearest enemy if no target or target is destroyed
if (!self.target || self.target.destroyed) {
var nearestDistance = Infinity;
self.target = null;
for (var i = 0; i < shadows.length; i++) {
var distance = Math.sqrt(Math.pow(self.x - shadows[i].x, 2) + Math.pow(self.y - shadows[i].y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
self.target = shadows[i];
}
}
}
// Move towards target
if (self.target) {
var angle = Math.atan2(self.target.y - self.y, self.target.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Rotate towards target
fireGraphics.rotation = angle;
}
// Fire effects
var scale = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
fireGraphics.scaleX = scale;
fireGraphics.scaleY = scale;
fireGraphics.tint = 0xff4400;
};
return self;
});
var HealerShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('healerShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.8 + Math.random() * 0.5;
self.health = 3;
self.maxHealth = 3;
self.monsterType = 'healer';
self.lastHeal = 0;
self.healCooldown = 120; // 2 seconds
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Healing ability
if (LK.ticks - self.lastHeal > self.healCooldown) {
for (var i = 0; i < shadows.length; i++) {
var otherShadow = shadows[i];
if (otherShadow !== self) {
var distance = Math.sqrt(Math.pow(self.x - otherShadow.x, 2) + Math.pow(self.y - otherShadow.y, 2));
if (distance < 150 && otherShadow.health < otherShadow.maxHealth) {
otherShadow.health = Math.min(otherShadow.maxHealth, otherShadow.health + 1);
LK.effects.flashObject(otherShadow, 0x00ff00, 300);
self.lastHeal = LK.ticks;
break;
}
}
}
}
// Pulsing green effect
var pulse = 1 + Math.sin(LK.ticks * 0.4) * 0.3;
shadowGraphics.tint = 0x44ff44;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.lightPower = 1;
self.fireRate = 60; // Fire every 60 ticks initially
self.lastLightShot = 0;
self.update = function () {
// Hero update method - no automatic firing
};
return self;
});
var LightOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobOffset = Math.random() * Math.PI * 2;
self.baseY = self.y;
self.update = function () {
self.y = self.baseY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10;
};
return self;
});
var LightProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('lightProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 180; // 3 seconds at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
};
return self;
});
var MimicShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('mimicShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.8 + Math.random() * 1.2;
self.health = 2;
self.maxHealth = 2;
self.monsterType = 'mimic';
self.lastCopy = 0;
self.copyCooldown = 240; // 4 seconds
self.copyTarget = null;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Copy nearest enemy abilities
if (LK.ticks - self.lastCopy > self.copyCooldown) {
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < shadows.length; i++) {
var otherShadow = shadows[i];
if (otherShadow !== self && otherShadow.monsterType !== 'mimic') {
var distance = Math.sqrt(Math.pow(self.x - otherShadow.x, 2) + Math.pow(self.y - otherShadow.y, 2));
if (distance < 200 && distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = otherShadow;
}
}
}
if (nearestEnemy) {
self.copyTarget = nearestEnemy.monsterType;
self.lastCopy = LK.ticks;
// Visual feedback
LK.effects.flashObject(self, 0xff00ff, 500);
// Copy some properties
if (nearestEnemy.monsterType === 'fast') {
self.speed = nearestEnemy.speed;
shadowGraphics.tint = 0xffff00;
} else if (nearestEnemy.monsterType === 'tank') {
self.health = Math.min(self.maxHealth + 2, nearestEnemy.health);
shadowGraphics.tint = 0x888888;
} else if (nearestEnemy.monsterType === 'teleporter') {
shadowGraphics.tint = 0x8844ff;
}
}
}
// Rainbow shifting effect
var hue = LK.ticks * 0.05 % 1;
var r = Math.sin(hue * Math.PI * 2) * 127 + 128;
var g = Math.sin((hue + 0.33) * Math.PI * 2) * 127 + 128;
var b = Math.sin((hue + 0.66) * Math.PI * 2) * 127 + 128;
var color = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b);
shadowGraphics.tint = color;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var Shadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 2;
self.health = 2;
self.maxHealth = 2;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var ShielderShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('shielderShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.2 + Math.random() * 0.8;
self.health = 4;
self.maxHealth = 4;
self.monsterType = 'shielder';
self.shieldActive = false;
self.lastShield = 0;
self.shieldCooldown = 180; // 3 seconds
self.shieldDuration = 120; // 2 seconds
self.shieldTimer = 0;
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Shield activation when damaged
if (self.health < self.maxHealth && !self.shieldActive && LK.ticks - self.lastShield > self.shieldCooldown) {
self.shieldActive = true;
self.shieldTimer = self.shieldDuration;
self.lastShield = LK.ticks;
shadowGraphics.tint = 0x4444ff;
}
// Shield timer
if (self.shieldActive) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shieldActive = false;
shadowGraphics.tint = 0xffffff;
}
// Pulsing blue effect when shielded
var pulse = 1 + Math.sin(LK.ticks * 0.6) * 0.4;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var SplitterShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('splitterShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5 + Math.random() * 1;
self.health = 3;
self.maxHealth = 3;
self.monsterType = 'splitter';
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Pulsing effect
var pulse = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
shadowGraphics.scaleX = pulse;
shadowGraphics.scaleY = pulse;
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var TankShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('tankShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5 + Math.random() * 0.5;
self.health = 8;
self.maxHealth = 8;
self.monsterType = 'tank';
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
// Visual health indicator
var healthPercent = self.health / self.maxHealth;
shadowGraphics.alpha = 0.5 + healthPercent * 0.5;
// Update health bar
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
var TeleporterShadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('teleporterShadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 1;
self.health = 2;
self.maxHealth = 2;
self.monsterType = 'teleporter';
self.lastTeleport = 0;
self.teleportCooldown = 180; // 3 seconds
// Create health bar
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarBg.y = -shadowGraphics.height / 2 - 15;
var healthBarFill = self.attachAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.5
});
healthBarFill.y = -shadowGraphics.height / 2 - 15;
self.update = function () {
var angle = Math.atan2(hero.y - self.y, hero.x - self.x);
var distanceToHero = Math.sqrt(Math.pow(hero.x - self.x, 2) + Math.pow(hero.y - self.y, 2));
// Teleport if far from hero and cooldown is ready
if (distanceToHero > 300 && LK.ticks - self.lastTeleport > self.teleportCooldown) {
var teleportDistance = 150;
var teleportAngle = Math.atan2(hero.y - self.y, hero.x - self.x);
self.x = hero.x - Math.cos(teleportAngle) * teleportDistance;
self.y = hero.y - Math.sin(teleportAngle) * teleportDistance;
self.lastTeleport = LK.ticks;
LK.effects.flashObject(self, 0x8844ff, 300);
} else {
// Normal movement
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
// Update health bar
var healthPercent = self.health / self.maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.tint = healthPercent > 0.5 ? 0x00ff00 : healthPercent > 0.25 ? 0xffff00 : 0xff0000;
};
return self;
});
/****
* Initialize Game
****/
// Guided fire button press handler
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Guided fire button press handler
// Create single cube background
function handleGuidedFireButton(x, y, obj) {
var timeSinceLastFire = LK.ticks - lastIceAttack;
if (timeSinceLastFire >= iceAttackCooldown && shadows.length > 0) {
// Create 3 guided fire projectiles
for (var i = 0; i < 3; i++) {
var guidedFire = new GuidedFire();
guidedFire.x = hero.x + (i - 1) * 30;
guidedFire.y = hero.y;
iceAttacks.push(guidedFire);
game.addChild(guidedFire);
}
lastIceAttack = LK.ticks;
LK.effects.flashObject(iceButton, 0xff4400, 300);
// Cooldown visual feedback
tween(iceButton, {
alpha: 0.3
}, {
duration: 0
});
tween(iceButton, {
alpha: 0.8
}, {
duration: iceAttackCooldown * 16.67
});
}
}
function createMainMenu() {
gameState = 'menu';
// Create menu container
menuContainer = new Container();
game.addChild(menuContainer);
// Create background decorative elements
for (var i = 0; i < 8; i++) {
var decorShadow = LK.getAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.1 + Math.random() * 0.2,
scaleX: 0.5 + Math.random() * 1.0,
scaleY: 0.5 + Math.random() * 1.0
});
decorShadow.x = Math.random() * 2048;
decorShadow.y = Math.random() * 2732;
menuContainer.addChild(decorShadow);
// Add slow rotation to decorative shadows
tween(decorShadow, {
rotation: Math.PI * 2
}, {
duration: 10000 + Math.random() * 5000,
easing: tween.easeLinear
});
}
// Create floating light orbs as background
for (var j = 0; j < 12; j++) {
var decorOrb = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3 + Math.random() * 0.4,
scaleX: 0.3 + Math.random() * 0.7,
scaleY: 0.3 + Math.random() * 0.7
});
decorOrb.x = Math.random() * 2048;
decorOrb.y = Math.random() * 2732;
menuContainer.addChild(decorOrb);
// Add floating animation
var floatDuration = 3000 + Math.random() * 2000;
tween(decorOrb, {
y: decorOrb.y + (Math.random() - 0.5) * 200,
x: decorOrb.x + (Math.random() - 0.5) * 100
}, {
duration: floatDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(decorOrb, {
y: decorOrb.y - (Math.random() - 0.5) * 200,
x: decorOrb.x - (Math.random() - 0.5) * 100
}, {
duration: floatDuration,
easing: tween.easeInOut
});
}
});
}
// Create main title with glow effect
var titleText = new Text2('SHADOW DEFENSE', {
size: 140,
fill: 0xFFFF00
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 700;
menuContainer.addChild(titleText);
// Add title pulsing effect
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
// Create subtitle text
var subtitleText = new Text2('Defend against the shadow invasion!', {
size: 65,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 850;
menuContainer.addChild(subtitleText);
// Create high score display
var bestScoreText = new Text2('Best Score: ' + (storage.get('bestScore') || 0), {
size: 55,
fill: 0x00FFFF
});
bestScoreText.anchor.set(0.5, 0.5);
bestScoreText.x = 1024;
bestScoreText.y = 950;
menuContainer.addChild(bestScoreText);
// Create play button with enhanced styling
playButton = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 3.5,
alpha: 0.9
});
playButton.x = 1024;
playButton.y = 1200;
menuContainer.addChild(playButton);
// Create play button text
var playText = new Text2('PLAY', {
size: 90,
fill: 0x000000
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 1200;
menuContainer.addChild(playText);
// Create detailed instructions
var instructionText = new Text2('• Tap and drag to move your hero\n• Use spell buttons to cast magic\n• Collect light orbs for power\n• Survive infinite waves of shadows', {
size: 45,
fill: 0xCCCCCC
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1450;
menuContainer.addChild(instructionText);
// Create spell preview icons
var spellPreviewY = 1650;
var spellSpacing = 300;
// Fire spell preview
var firePreview = LK.getAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.7
});
firePreview.x = 1024 - spellSpacing * 1.5;
firePreview.y = spellPreviewY;
menuContainer.addChild(firePreview);
var fireLabel = new Text2('Fire', {
size: 35,
fill: 0xFF4400
});
fireLabel.anchor.set(0.5, 0.5);
fireLabel.x = firePreview.x;
fireLabel.y = firePreview.y + 80;
menuContainer.addChild(fireLabel);
// Light spell preview
var lightPreview = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.7
});
lightPreview.x = 1024 - spellSpacing * 0.5;
lightPreview.y = spellPreviewY;
menuContainer.addChild(lightPreview);
var lightLabel = new Text2('Light', {
size: 35,
fill: 0xFFFF00
});
lightLabel.anchor.set(0.5, 0.5);
lightLabel.x = lightPreview.x;
lightLabel.y = lightPreview.y + 80;
menuContainer.addChild(lightLabel);
// Projectile spell preview
var projectilePreview = LK.getAsset('lightProjectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.7
});
projectilePreview.x = 1024 + spellSpacing * 0.5;
projectilePreview.y = spellPreviewY;
menuContainer.addChild(projectilePreview);
var projectileLabel = new Text2('Burst', {
size: 35,
fill: 0x00FFFF
});
projectileLabel.anchor.set(0.5, 0.5);
projectileLabel.x = projectilePreview.x;
projectileLabel.y = projectilePreview.y + 80;
menuContainer.addChild(projectileLabel);
// Guided fire spell preview
var guidedPreview = LK.getAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.7,
tint: 0xFF8800
});
guidedPreview.x = 1024 + spellSpacing * 1.5;
guidedPreview.y = spellPreviewY;
menuContainer.addChild(guidedPreview);
var guidedLabel = new Text2('Guided', {
size: 35,
fill: 0xFF8800
});
guidedLabel.anchor.set(0.5, 0.5);
guidedLabel.x = guidedPreview.x;
guidedLabel.y = guidedPreview.y + 80;
menuContainer.addChild(guidedLabel);
// Add pulsing effect to play button
tween(playButton, {
scaleX: 3.8,
scaleY: 3.8
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 3.5,
scaleY: 3.5
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
// Add rotation to spell previews
tween(firePreview, {
rotation: Math.PI * 2
}, {
duration: 8000,
easing: tween.easeLinear
});
tween(guidedPreview, {
rotation: -Math.PI * 2
}, {
duration: 6000,
easing: tween.easeLinear
});
// Hide game UI
scoreTxt.visible = false;
waveTxt.visible = false;
waveProgressTxt.visible = false;
healthTxt.visible = false;
fireButton.visible = false;
lightButton.visible = false;
lightProjectileButton.visible = false;
iceButton.visible = false;
windButton.visible = false;
hero.visible = false;
}
function startGame() {
gameState = 'playing';
// Save current score if it's a new high score
var currentBestScore = storage.get('bestScore') || 0;
if (score > currentBestScore) {
storage.set('bestScore', score);
}
// Remove menu
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
playButton = null;
}
// Show game UI
scoreTxt.visible = true;
waveTxt.visible = true;
waveProgressTxt.visible = true;
healthTxt.visible = true;
fireButton.visible = true;
lightButton.visible = true;
lightProjectileButton.visible = true;
iceButton.visible = true;
windButton.visible = true;
hero.visible = true;
// Reset game state
heroHealth = 3;
healthTxt.setText('Health: ' + heroHealth + '/' + maxHeroHealth);
score = 0;
scoreTxt.setText('Score: ' + score);
waveLevel = 1;
waveTxt.setText('Wave: ' + waveLevel);
waveActive = false;
// Clear all game objects
for (var i = shadows.length - 1; i >= 0; i--) {
shadows[i].destroy();
}
shadows = [];
for (var j = lightProjectiles.length - 1; j >= 0; j--) {
lightProjectiles[j].destroy();
}
lightProjectiles = [];
for (var k = fireSpells.length - 1; k >= 0; k--) {
fireSpells[k].destroy();
}
fireSpells = [];
for (var l = lightOrbs.length - 1; l >= 0; l--) {
lightOrbs[l].destroy();
}
lightOrbs = [];
for (var m = iceAttacks.length - 1; m >= 0; m--) {
iceAttacks[m].destroy();
}
iceAttacks = [];
for (var n = windAttacks.length - 1; n >= 0; n--) {
windAttacks[n].destroy();
}
windAttacks = [];
// Reset hero position
hero.x = 1024;
hero.y = 1366;
hero.alpha = 1.0;
// Reset other game variables
shelterActive = false;
if (shelterGraphics) {
shelterGraphics.destroy();
shelterGraphics = null;
}
damageBonusActive = false;
shieldActive = false;
lastDamage = 0;
// Initialize main menu
createMainMenu();
}
// Explosive orb button press handler
function handleExplosiveOrbButton(x, y, obj) {
var timeSinceLastOrb = LK.ticks - lastWindAttack;
if (timeSinceLastOrb >= windAttackCooldown) {
// Create explosive orb towards nearest enemy
var nearestShadow = null;
var nearestDistance = Infinity;
for (var i = 0; i < shadows.length; i++) {
var distance = Math.sqrt(Math.pow(hero.x - shadows[i].x, 2) + Math.pow(hero.y - shadows[i].y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
nearestShadow = shadows[i];
}
}
if (nearestShadow) {
var explosiveOrb = new ExplosiveOrb();
explosiveOrb.x = hero.x;
explosiveOrb.y = hero.y;
var angle = Math.atan2(nearestShadow.y - hero.y, nearestShadow.x - hero.x);
explosiveOrb.velocityX = Math.cos(angle) * explosiveOrb.speed;
explosiveOrb.velocityY = Math.sin(angle) * explosiveOrb.speed;
windAttacks.push(explosiveOrb);
game.addChild(explosiveOrb);
}
lastWindAttack = LK.ticks;
LK.effects.flashObject(windButton, 0xff8800, 300);
// Cooldown visual feedback
tween(windButton, {
alpha: 0.3
}, {
duration: 0
});
tween(windButton, {
alpha: 0.8
}, {
duration: windAttackCooldown * 16.67
});
}
}
var cube = LK.getAsset('cube', {
anchorX: 0.5,
anchorY: 0.5
});
cube.x = 1024;
cube.y = 1366;
game.addChild(cube);
var hero = game.addChild(new Hero());
hero.x = 1024;
hero.y = 1366;
var shadows = [];
var lightProjectiles = [];
var fireSpells = [];
var lightOrbs = [];
var iceAttacks = [];
var windAttacks = [];
var lastShadowSpawn = 0;
var shadowSpawnRate = 120; // Start spawning every 2 seconds
var waveLevel = 1;
var score = 0;
var lastFireSpell = 0;
var fireSpellCooldown = 90; // 1.5 seconds cooldown at 60fps
var maxActiveFireSpells = 3;
var lastLightAttack = 0;
var lightAttackCooldown = 420; // 7 seconds cooldown at 60fps
var orbsUsedThisWave = 0;
var maxOrbsPerWave = 7;
var waveEnemiesRemaining = 0;
var waveEnemiesTotal = 0;
var waveActive = false;
var waveStartDelay = 0;
var waveDifficultyMultiplier = 1.0;
var shelterActive = false;
var shelterScore = 10000; // Score threshold to activate shelter
var shelterDuration = 300; // 5 seconds at 60fps
var shelterTimer = 0;
var shelterGraphics = null;
var damageBonusActive = false;
var damageBonusTimer = 0;
var damageBonusDuration = 360; // 6 seconds at 60fps
var shieldActive = false;
var shieldTimer = 0;
var shieldDuration = 360; // 6 seconds at 60fps
var lastIceAttack = 0;
var iceAttackCooldown = 480; // 8 seconds cooldown
var lastWindAttack = 0;
var windAttackCooldown = 360; // 6 seconds cooldown
var heroHealth = 3;
var maxHeroHealth = 3;
var lastDamage = 0;
var damageCooldown = 120; // 2 seconds invincibility after taking damage
var gameState = 'menu'; // 'menu' or 'playing'
var menuContainer = null;
var playButton = null;
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(0.5, 0);
waveTxt.y = 70;
LK.gui.top.addChild(waveTxt);
var waveProgressTxt = new Text2('Enemies: 0/0', {
size: 40,
fill: 0x00FFFF
});
waveProgressTxt.anchor.set(0.5, 0);
waveProgressTxt.y = 130;
LK.gui.top.addChild(waveProgressTxt);
var healthTxt = new Text2('Health: 3/3', {
size: 50,
fill: 0xFF0000
});
healthTxt.anchor.set(0.5, 0);
healthTxt.y = 180;
LK.gui.top.addChild(healthTxt);
// Create fire button
var fireButton = LK.getAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
});
fireButton.x = 200;
fireButton.y = 2500;
game.addChild(fireButton);
// Create light attack button
var lightButton = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8,
alpha: 0.8
});
lightButton.x = 1800;
lightButton.y = 2500;
game.addChild(lightButton);
// Create light projectile button
var lightProjectileButton = LK.getAsset('lightProjectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0,
alpha: 0.8
});
lightProjectileButton.x = 1024;
lightProjectileButton.y = 2500;
game.addChild(lightProjectileButton);
// Create guided fire button
var iceButton = LK.getAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.8
});
iceButton.x = 512;
iceButton.y = 2500;
game.addChild(iceButton);
iceButton.down = handleGuidedFireButton;
// Create explosive orb button
var windButton = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.8
});
windButton.x = 1536;
windButton.y = 2500;
game.addChild(windButton);
windButton.down = handleExplosiveOrbButton;
// Fire button press handler
fireButton.down = function (x, y, obj) {
// Fire spell at nearest enemy - check cooldown and limit
var timeSinceLastFire = LK.ticks - lastFireSpell;
if (timeSinceLastFire >= fireSpellCooldown && fireSpells.length < maxActiveFireSpells && shadows.length > 0) {
// Find nearest shadow
var nearestShadow = null;
var nearestDistance = Infinity;
for (var i = 0; i < shadows.length; i++) {
var distance = Math.sqrt(Math.pow(hero.x - shadows[i].x, 2) + Math.pow(hero.y - shadows[i].y, 2));
if (distance < nearestDistance) {
nearestDistance = distance;
nearestShadow = shadows[i];
}
}
;
// Light attack button press handler
lightButton.down = function (x, y, obj) {
// Check cooldown and orb usage limit
var timeSinceLastLight = LK.ticks - lastLightAttack;
if (timeSinceLastLight >= lightAttackCooldown && orbsUsedThisWave < maxOrbsPerWave) {
// Destroy all enemies on screen
for (var i = shadows.length - 1; i >= 0; i--) {
var shadow = shadows[i];
// Create light orb for each destroyed shadow
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
// Add score based on monster type
var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
// Flash effect on each enemy before destruction
tween(shadow, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
shadow.destroy();
}
});
shadows.splice(i, 1);
}
// Update score display
scoreTxt.setText('Score: ' + score);
// Play sound effect
LK.getSound('shadowDestroy').play();
// Screen flash effect
LK.effects.flashScreen(0xffffaa, 800);
// Button feedback with cooldown visual
LK.effects.flashObject(lightButton, 0xffffaa, 400);
tween(lightButton, {
alpha: 0.3
}, {
duration: 0
});
tween(lightButton, {
alpha: 0.8
}, {
duration: lightAttackCooldown * 16.67
}); // Convert ticks to ms
// Update cooldown and usage counter
lastLightAttack = LK.ticks;
orbsUsedThisWave++;
}
};
// Light projectile button press handler
lightProjectileButton.down = function (x, y, obj) {
// Fire light projectile
var newProjectile = new LightProjectile();
newProjectile.x = hero.x;
newProjectile.y = hero.y;
// Fire in 8 directions
var directions = 8;
for (var i = 0; i < directions; i++) {
var angle = i / directions * Math.PI * 2;
var projectile = new LightProjectile();
projectile.x = hero.x;
projectile.y = hero.y;
projectile.velocityX = Math.cos(angle) * 8;
projectile.velocityY = Math.sin(angle) * 8;
lightProjectiles.push(projectile);
game.addChild(projectile);
}
// Button feedback
LK.effects.flashObject(lightProjectileButton, 0xffffaa, 200);
};
if (nearestShadow) {
var newFireSpell = new FireSpell();
newFireSpell.x = nearestShadow.x;
newFireSpell.y = nearestShadow.y;
fireSpells.push(newFireSpell);
game.addChild(newFireSpell);
lastFireSpell = LK.ticks;
LK.getSound('fireBlast').play();
// Button feedback
LK.effects.flashObject(fireButton, 0xff4400, 200);
}
}
};
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Keep hero within bounds
if (dragNode.x < 40) dragNode.x = 40;
if (dragNode.x > 2008) dragNode.x = 2008;
if (dragNode.y < 40) dragNode.y = 40;
if (dragNode.y > 2692) dragNode.y = 2692;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (gameState === 'menu') {
// Check if play button was pressed
if (playButton) {
var buttonDistance = Math.sqrt(Math.pow(x - playButton.x, 2) + Math.pow(y - playButton.y, 2));
if (buttonDistance < 100) {
startGame();
return;
}
}
} else if (gameState === 'playing') {
// Check if touching hero
var heroDistance = Math.sqrt(Math.pow(x - hero.x, 2) + Math.pow(y - hero.y, 2));
if (heroDistance < 60) {
dragNode = hero;
handleMove(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
function startWave() {
waveActive = true;
waveStartDelay = 180; // 3 second delay before spawning
waveEnemiesTotal = 5 + waveLevel * 2; // No cap - infinite scaling
waveEnemiesRemaining = waveEnemiesTotal;
waveDifficultyMultiplier = 1.0 + (waveLevel - 1) * 0.15; // 15% increase per wave
shadowSpawnRate = Math.max(30, 120 - waveLevel * 8); // Faster spawning each wave
orbsUsedThisWave = 0; // Reset orb usage for new wave
waveTxt.setText('Wave: ' + waveLevel);
waveProgressTxt.setText('Enemies: ' + (waveEnemiesTotal - waveEnemiesRemaining) + '/' + waveEnemiesTotal);
LK.effects.flashScreen(0x00FF00, 500);
}
game.update = function () {
if (gameState !== 'playing') {
return;
}
// Wave management
if (!waveActive && shadows.length === 0) {
// Start new wave when no enemies remain
startWave();
}
// Spawn shadows during active wave
if (waveActive && waveEnemiesRemaining > 0 && waveStartDelay <= 0 && LK.ticks - lastShadowSpawn >= shadowSpawnRate) {
var newShadow;
// Choose random monster type based on wave level
var monsterRoll = Math.random();
if (waveLevel < 3) {
// Early waves: mostly basic shadows
if (monsterRoll < 0.7) newShadow = new Shadow();else if (monsterRoll < 0.9) newShadow = new FastShadow();else newShadow = new TankShadow();
} else if (waveLevel < 6) {
// Mid waves: introduce more variety
if (monsterRoll < 0.4) newShadow = new Shadow();else if (monsterRoll < 0.6) newShadow = new FastShadow();else if (monsterRoll < 0.75) newShadow = new TankShadow();else if (monsterRoll < 0.9) newShadow = new SplitterShadow();else newShadow = new TeleporterShadow();
} else if (waveLevel < 10) {
// Late waves: all monster types including dangerous ones
if (monsterRoll < 0.2) newShadow = new Shadow();else if (monsterRoll < 0.35) newShadow = new FastShadow();else if (monsterRoll < 0.5) newShadow = new TankShadow();else if (monsterRoll < 0.65) newShadow = new SplitterShadow();else if (monsterRoll < 0.75) newShadow = new TeleporterShadow();else if (monsterRoll < 0.85) newShadow = new BomberShadow();else if (monsterRoll < 0.92) newShadow = new HealerShadow();else newShadow = new ShielderShadow();
} else {
// Very late waves: all enemy types including new ones
if (monsterRoll < 0.15) newShadow = new Shadow();else if (monsterRoll < 0.25) newShadow = new FastShadow();else if (monsterRoll < 0.35) newShadow = new TankShadow();else if (monsterRoll < 0.45) newShadow = new SplitterShadow();else if (monsterRoll < 0.55) newShadow = new TeleporterShadow();else if (monsterRoll < 0.65) newShadow = new BomberShadow();else if (monsterRoll < 0.75) newShadow = new HealerShadow();else if (monsterRoll < 0.85) newShadow = new ShielderShadow();else if (monsterRoll < 0.93) newShadow = new BerserkerShadow();else newShadow = new MimicShadow();
}
// Spawn from random edge
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top
newShadow.x = Math.random() * 2048;
newShadow.y = -30;
break;
case 1:
// Right
newShadow.x = 2078;
newShadow.y = Math.random() * 2732;
break;
case 2:
// Bottom
newShadow.x = Math.random() * 2048;
newShadow.y = 2762;
break;
case 3:
// Left
newShadow.x = -30;
newShadow.y = Math.random() * 2732;
break;
}
// Apply wave difficulty multiplier
newShadow.speed = (newShadow.speed + waveLevel * 0.3) * waveDifficultyMultiplier;
newShadow.health = Math.ceil(newShadow.health * waveDifficultyMultiplier);
newShadow.maxHealth = newShadow.health;
shadows.push(newShadow);
game.addChild(newShadow);
lastShadowSpawn = LK.ticks;
waveEnemiesRemaining--;
waveProgressTxt.setText('Enemies: ' + (waveEnemiesTotal - waveEnemiesRemaining) + '/' + waveEnemiesTotal);
}
// Wave start delay countdown
if (waveStartDelay > 0) {
waveStartDelay--;
}
// Check if wave is complete
if (waveActive && waveEnemiesRemaining <= 0 && shadows.length === 0) {
waveActive = false;
waveLevel++;
// Wave completion bonus
score += waveLevel * 50;
scoreTxt.setText('Score: ' + score);
LK.effects.flashScreen(0xFFFF00, 800);
}
// Check hero collision with shadows
for (var i = 0; i < shadows.length; i++) {
var shadow = shadows[i];
if (hero.intersects(shadow) && !shelterActive && !shieldActive && LK.ticks - lastDamage > damageCooldown) {
heroHealth--;
lastDamage = LK.ticks;
healthTxt.setText('Health: ' + heroHealth + '/' + maxHeroHealth);
LK.effects.flashScreen(0xff0000, 500);
LK.effects.flashObject(hero, 0xff0000, 1000);
if (heroHealth <= 0) {
// Save high score before game over
var currentBestScore = storage.get('bestScore') || 0;
if (score > currentBestScore) {
storage.set('bestScore', score);
}
LK.showGameOver();
return;
}
}
// Check bomber explosions
if (shadow.monsterType === 'bomber' && shadow.exploding && shadow.explosionTimer <= 0) {
var explosionDistance = Math.sqrt(Math.pow(hero.x - shadow.x, 2) + Math.pow(hero.y - shadow.y, 2));
if (explosionDistance < 120 && !shelterActive && !shieldActive && LK.ticks - lastDamage > damageCooldown) {
heroHealth--;
lastDamage = LK.ticks;
healthTxt.setText('Health: ' + heroHealth + '/' + maxHeroHealth);
LK.effects.flashScreen(0xff4400, 500);
LK.effects.flashObject(hero, 0xff4400, 1000);
if (heroHealth <= 0) {
// Save high score before game over
var currentBestScore = storage.get('bestScore') || 0;
if (score > currentBestScore) {
storage.set('bestScore', score);
}
LK.showGameOver();
return;
}
}
// Remove exploded bomber
shadow.destroy();
shadows.splice(i, 1);
i--; // Adjust index after removal
}
}
// Update and check light projectiles
for (var j = lightProjectiles.length - 1; j >= 0; j--) {
var projectile = lightProjectiles[j];
if (projectile.lifetime <= 0 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) {
projectile.destroy();
lightProjectiles.splice(j, 1);
continue;
}
// Check collision with shadows
for (var k = shadows.length - 1; k >= 0; k--) {
if (projectile.intersects(shadows[k])) {
var shadow = shadows[k];
// Check if enemy is shielded
var damage = damageBonusActive ? 2 : 1;
if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
damage = 0; // No damage when shielded
LK.effects.flashObject(shadow, 0x4444ff, 100);
} else {
shadow.health -= damage;
}
var shadowDestroyed = false;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter' && shadow.health <= 0) {
// Create two smaller fast shadows
for (var split = 0; split < 2; split++) {
var miniShadow = new FastShadow();
miniShadow.x = shadow.x + (split === 0 ? -30 : 30);
miniShadow.y = shadow.y + (Math.random() - 0.5) * 60;
miniShadow.speed *= 0.8;
shadows.push(miniShadow);
game.addChild(miniShadow);
}
}
if (shadow.monsterType === 'bomber' && shadow.exploding && shadow.explosionTimer > 0) {
// Bomber was destroyed while exploding, cancel explosion
shadow.exploding = false;
}
// Create light orb
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(k, 1);
shadowDestroyed = true;
var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
// Monster took damage but not destroyed
LK.effects.flashObject(shadow, 0xffffff, 200);
}
projectile.destroy();
lightProjectiles.splice(j, 1);
break;
}
}
}
// Update and check fire spells
for (var l = fireSpells.length - 1; l >= 0; l--) {
var spell = fireSpells[l];
if (spell.lifetime <= 0) {
spell.destroy();
fireSpells.splice(l, 1);
continue;
}
// Check collision with shadows
for (var m = shadows.length - 1; m >= 0; m--) {
var distance = Math.sqrt(Math.pow(spell.x - shadows[m].x, 2) + Math.pow(spell.y - shadows[m].y, 2));
if (distance < spell.radius) {
var shadow = shadows[m];
// Check if enemy is shielded
var damage = damageBonusActive ? 4 : 2; // Fire spells do more damage
if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
damage = Math.ceil(damage / 2); // Reduced damage when shielded
LK.effects.flashObject(shadow, 0x4444ff, 100);
}
shadow.health -= damage;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter') {
// Create two smaller fast shadows
for (var split = 0; split < 2; split++) {
var miniShadow = new FastShadow();
miniShadow.x = shadow.x + (split === 0 ? -30 : 30);
miniShadow.y = shadow.y + (Math.random() - 0.5) * 60;
miniShadow.speed *= 0.8;
shadows.push(miniShadow);
game.addChild(miniShadow);
}
}
if (shadow.monsterType === 'bomber' && shadow.exploding && shadow.explosionTimer > 0) {
// Bomber was destroyed while exploding, cancel explosion
shadow.exploding = false;
}
// Create light orb
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(m, 1);
var scoreValue = shadow.monsterType === 'tank' ? 30 : shadow.monsterType === 'splitter' ? 35 : shadow.monsterType === 'teleporter' ? 25 : shadow.monsterType === 'bomber' ? 40 : shadow.monsterType === 'healer' ? 45 : shadow.monsterType === 'shielder' ? 40 : shadow.monsterType === 'berserker' ? 50 : shadow.monsterType === 'mimic' ? 55 : 15;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
// Monster took damage but not destroyed
LK.effects.flashObject(shadow, 0xff8800, 200);
}
}
}
}
// Check light orb collection
for (var n = lightOrbs.length - 1; n >= 0; n--) {
var orb = lightOrbs[n];
if (hero.intersects(orb)) {
hero.lightPower++;
if (hero.fireRate > 20) {
hero.fireRate -= 2;
}
orb.destroy();
lightOrbs.splice(n, 1);
LK.getSound('collectOrb').play();
// Flash hero with light effect
LK.effects.flashObject(hero, 0xffffaa, 500);
}
}
// Shelter activation check
if (score >= shelterScore && !shelterActive) {
shelterActive = true;
shelterTimer = shelterDuration;
// Create shelter visual
shelterGraphics = LK.getAsset('shelter', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
shelterGraphics.x = hero.x;
shelterGraphics.y = hero.y;
game.addChild(shelterGraphics);
// Visual feedback for shelter activation
LK.effects.flashScreen(0x00ffff, 1000);
LK.effects.flashObject(hero, 0x00ffff, 1000);
// Make hero semi-transparent during shelter
hero.alpha = 0.5;
// Pulsing effect for shelter
tween(shelterGraphics, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(shelterGraphics, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
}
// Shelter timer countdown
if (shelterActive) {
shelterTimer--;
// Move shelter with hero
if (shelterGraphics) {
shelterGraphics.x = hero.x;
shelterGraphics.y = hero.y;
}
if (shelterTimer <= 0) {
shelterActive = false;
hero.alpha = 1.0; // Restore normal visibility
// Remove shelter visual
if (shelterGraphics) {
shelterGraphics.destroy();
shelterGraphics = null;
}
// Activate damage bonus and shield after leaving shelter
damageBonusActive = true;
damageBonusTimer = damageBonusDuration;
shieldActive = true;
shieldTimer = shieldDuration;
// Visual feedback for bonuses
LK.effects.flashScreen(0xff8800, 800);
LK.effects.flashObject(hero, 0xff8800, 1000);
// Keep shelter accessible at same interval for infinite play
shelterScore = score + 10000;
}
}
// Damage bonus timer countdown
if (damageBonusActive) {
damageBonusTimer--;
if (damageBonusTimer <= 0) {
damageBonusActive = false;
}
}
// Shield timer countdown
if (shieldActive) {
shieldTimer--;
if (shieldTimer <= 0) {
shieldActive = false;
}
}
// Hero invincibility visual effect
if (LK.ticks - lastDamage < damageCooldown) {
// Flashing effect during invincibility
hero.alpha = Math.sin(LK.ticks * 0.5) > 0 ? 0.3 : 0.8;
} else if (!shelterActive) {
hero.alpha = 1.0; // Normal visibility when not damaged and not in shelter
}
// Update and check guided fire attacks
for (var p = iceAttacks.length - 1; p >= 0; p--) {
var guidedFire = iceAttacks[p];
if (guidedFire.lifetime <= 0) {
guidedFire.destroy();
iceAttacks.splice(p, 1);
continue;
}
// Check collision with shadows
for (var q = shadows.length - 1; q >= 0; q--) {
if (guidedFire.intersects(shadows[q])) {
var shadow = shadows[q];
// Check if enemy is shielded
var damage = damageBonusActive ? guidedFire.damage * 2 : guidedFire.damage;
if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
damage = Math.ceil(damage / 2);
LK.effects.flashObject(shadow, 0x4444ff, 100);
}
shadow.health -= damage;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter') {
for (var split = 0; split < 2; split++) {
var miniShadow = new FastShadow();
miniShadow.x = shadow.x + (split === 0 ? -30 : 30);
miniShadow.y = shadow.y + (Math.random() - 0.5) * 60;
miniShadow.speed *= 0.8;
shadows.push(miniShadow);
game.addChild(miniShadow);
}
}
// Create light orb
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(q, 1);
var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
LK.effects.flashObject(shadow, 0xff4400, 200);
}
guidedFire.destroy();
iceAttacks.splice(p, 1);
break;
}
}
}
// Update and check explosive orbs
for (var r = windAttacks.length - 1; r >= 0; r--) {
var explosiveOrb = windAttacks[r];
var shouldExplode = false;
// Check if orb should explode (lifetime ended, hit enemy, or went off screen)
if (explosiveOrb.lifetime <= 0 || explosiveOrb.x < -100 || explosiveOrb.x > 2148 || explosiveOrb.y < -100 || explosiveOrb.y > 2832) {
shouldExplode = true;
} else {
// Check collision with shadows for immediate explosion
for (var s = 0; s < shadows.length; s++) {
if (explosiveOrb.intersects(shadows[s])) {
shouldExplode = true;
break;
}
}
}
if (shouldExplode) {
// Create explosion effect
LK.effects.flashScreen(0xff8800, 300);
// Damage all enemies within explosion radius
for (var s = shadows.length - 1; s >= 0; s--) {
var shadow = shadows[s];
var distance = Math.sqrt(Math.pow(explosiveOrb.x - shadow.x, 2) + Math.pow(explosiveOrb.y - shadow.y, 2));
if (distance < explosiveOrb.explosionRadius) {
var damage = damageBonusActive ? explosiveOrb.damage * 2 : explosiveOrb.damage;
if (shadow.monsterType === 'shielder' && shadow.shieldActive) {
damage = Math.ceil(damage / 2);
LK.effects.flashObject(shadow, 0x4444ff, 100);
}
shadow.health -= damage;
if (shadow.health <= 0) {
// Handle special monster behaviors on death
if (shadow.monsterType === 'splitter') {
for (var split = 0; split < 2; split++) {
var miniShadow = new FastShadow();
miniShadow.x = shadow.x + (split === 0 ? -30 : 30);
miniShadow.y = shadow.y + (Math.random() - 0.5) * 60;
miniShadow.speed *= 0.8;
shadows.push(miniShadow);
game.addChild(miniShadow);
}
}
// Create light orb
var newOrb = new LightOrb();
newOrb.x = shadow.x;
newOrb.y = shadow.y;
newOrb.baseY = newOrb.y;
lightOrbs.push(newOrb);
game.addChild(newOrb);
shadow.destroy();
shadows.splice(s, 1);
var scoreValue = shadow.monsterType === 'tank' ? 25 : shadow.monsterType === 'splitter' ? 30 : shadow.monsterType === 'teleporter' ? 20 : shadow.monsterType === 'bomber' ? 35 : shadow.monsterType === 'healer' ? 40 : shadow.monsterType === 'shielder' ? 35 : shadow.monsterType === 'berserker' ? 45 : shadow.monsterType === 'mimic' ? 50 : 10;
score += scoreValue;
scoreTxt.setText('Score: ' + score);
LK.getSound('shadowDestroy').play();
} else {
LK.effects.flashObject(shadow, 0xff8800, 200);
}
}
}
explosiveOrb.destroy();
windAttacks.splice(r, 1);
}
}
// Game is now infinite - no victory condition
};
// Start first wave
startWave(); ===================================================================
--- original.js
+++ change.js
@@ -617,10 +617,10 @@
/****
* Game Code
****/
-// Create single cube background
// Guided fire button press handler
+// Create single cube background
function handleGuidedFireButton(x, y, obj) {
var timeSinceLastFire = LK.ticks - lastIceAttack;
if (timeSinceLastFire >= iceAttackCooldown && shadows.length > 0) {
// Create 3 guided fire projectiles
@@ -650,116 +650,242 @@
gameState = 'menu';
// Create menu container
menuContainer = new Container();
game.addChild(menuContainer);
- // Create title text
+ // Create background decorative elements
+ for (var i = 0; i < 8; i++) {
+ var decorShadow = LK.getAsset('shadow', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.1 + Math.random() * 0.2,
+ scaleX: 0.5 + Math.random() * 1.0,
+ scaleY: 0.5 + Math.random() * 1.0
+ });
+ decorShadow.x = Math.random() * 2048;
+ decorShadow.y = Math.random() * 2732;
+ menuContainer.addChild(decorShadow);
+ // Add slow rotation to decorative shadows
+ tween(decorShadow, {
+ rotation: Math.PI * 2
+ }, {
+ duration: 10000 + Math.random() * 5000,
+ easing: tween.easeLinear
+ });
+ }
+ // Create floating light orbs as background
+ for (var j = 0; j < 12; j++) {
+ var decorOrb = LK.getAsset('lightOrb', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.3 + Math.random() * 0.4,
+ scaleX: 0.3 + Math.random() * 0.7,
+ scaleY: 0.3 + Math.random() * 0.7
+ });
+ decorOrb.x = Math.random() * 2048;
+ decorOrb.y = Math.random() * 2732;
+ menuContainer.addChild(decorOrb);
+ // Add floating animation
+ var floatDuration = 3000 + Math.random() * 2000;
+ tween(decorOrb, {
+ y: decorOrb.y + (Math.random() - 0.5) * 200,
+ x: decorOrb.x + (Math.random() - 0.5) * 100
+ }, {
+ duration: floatDuration,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(decorOrb, {
+ y: decorOrb.y - (Math.random() - 0.5) * 200,
+ x: decorOrb.x - (Math.random() - 0.5) * 100
+ }, {
+ duration: floatDuration,
+ easing: tween.easeInOut
+ });
+ }
+ });
+ }
+ // Create main title with glow effect
var titleText = new Text2('SHADOW DEFENSE', {
- size: 120,
+ size: 140,
fill: 0xFFFF00
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
- titleText.y = 800;
+ titleText.y = 700;
menuContainer.addChild(titleText);
+ // Add title pulsing effect
+ tween(titleText, {
+ scaleX: 1.1,
+ scaleY: 1.1
+ }, {
+ duration: 2000,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(titleText, {
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 2000,
+ easing: tween.easeInOut
+ });
+ }
+ });
// Create subtitle text
var subtitleText = new Text2('Defend against the shadow invasion!', {
- size: 60,
+ size: 65,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
- subtitleText.y = 950;
+ subtitleText.y = 850;
menuContainer.addChild(subtitleText);
- // Create play button
+ // Create high score display
+ var bestScoreText = new Text2('Best Score: ' + (storage.get('bestScore') || 0), {
+ size: 55,
+ fill: 0x00FFFF
+ });
+ bestScoreText.anchor.set(0.5, 0.5);
+ bestScoreText.x = 1024;
+ bestScoreText.y = 950;
+ menuContainer.addChild(bestScoreText);
+ // Create play button with enhanced styling
playButton = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
- scaleX: 3.0,
- scaleY: 3.0,
+ scaleX: 3.5,
+ scaleY: 3.5,
alpha: 0.9
});
playButton.x = 1024;
playButton.y = 1200;
menuContainer.addChild(playButton);
// Create play button text
var playText = new Text2('PLAY', {
- size: 80,
+ size: 90,
fill: 0x000000
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 1200;
menuContainer.addChild(playText);
- // Create options button
- optionsButton = LK.getAsset('lightOrb', {
+ // Create detailed instructions
+ var instructionText = new Text2('• Tap and drag to move your hero\n• Use spell buttons to cast magic\n• Collect light orbs for power\n• Survive infinite waves of shadows', {
+ size: 45,
+ fill: 0xCCCCCC
+ });
+ instructionText.anchor.set(0.5, 0.5);
+ instructionText.x = 1024;
+ instructionText.y = 1450;
+ menuContainer.addChild(instructionText);
+ // Create spell preview icons
+ var spellPreviewY = 1650;
+ var spellSpacing = 300;
+ // Fire spell preview
+ var firePreview = LK.getAsset('fireSpell', {
anchorX: 0.5,
anchorY: 0.5,
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.8
+ scaleX: 1.0,
+ scaleY: 1.0,
+ alpha: 0.7
});
- optionsButton.x = 1024;
- optionsButton.y = 1450;
- menuContainer.addChild(optionsButton);
- // Create options button text
- var optionsText = new Text2('OPTIONS', {
- size: 60,
- fill: 0x000000
+ firePreview.x = 1024 - spellSpacing * 1.5;
+ firePreview.y = spellPreviewY;
+ menuContainer.addChild(firePreview);
+ var fireLabel = new Text2('Fire', {
+ size: 35,
+ fill: 0xFF4400
});
- optionsText.anchor.set(0.5, 0.5);
- optionsText.x = 1024;
- optionsText.y = 1450;
- menuContainer.addChild(optionsText);
- // Create credits button
- creditsButton = LK.getAsset('lightOrb', {
+ fireLabel.anchor.set(0.5, 0.5);
+ fireLabel.x = firePreview.x;
+ fireLabel.y = firePreview.y + 80;
+ menuContainer.addChild(fireLabel);
+ // Light spell preview
+ var lightPreview = LK.getAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5,
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.8
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 0.7
});
- creditsButton.x = 1024;
- creditsButton.y = 1700;
- menuContainer.addChild(creditsButton);
- // Create credits button text
- var creditsText = new Text2('CREDITS', {
- size: 60,
- fill: 0x000000
+ lightPreview.x = 1024 - spellSpacing * 0.5;
+ lightPreview.y = spellPreviewY;
+ menuContainer.addChild(lightPreview);
+ var lightLabel = new Text2('Light', {
+ size: 35,
+ fill: 0xFFFF00
});
- creditsText.anchor.set(0.5, 0.5);
- creditsText.x = 1024;
- creditsText.y = 1700;
- menuContainer.addChild(creditsText);
- // Create instructions
- var instructionText = new Text2('Tap and drag to move your hero\nUse buttons to cast spells', {
- size: 50,
- fill: 0xCCCCCC
+ lightLabel.anchor.set(0.5, 0.5);
+ lightLabel.x = lightPreview.x;
+ lightLabel.y = lightPreview.y + 80;
+ menuContainer.addChild(lightLabel);
+ // Projectile spell preview
+ var projectilePreview = LK.getAsset('lightProjectile', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 0.7
});
- instructionText.anchor.set(0.5, 0.5);
- instructionText.x = 1024;
- instructionText.y = 1600;
- menuContainer.addChild(instructionText);
+ projectilePreview.x = 1024 + spellSpacing * 0.5;
+ projectilePreview.y = spellPreviewY;
+ menuContainer.addChild(projectilePreview);
+ var projectileLabel = new Text2('Burst', {
+ size: 35,
+ fill: 0x00FFFF
+ });
+ projectileLabel.anchor.set(0.5, 0.5);
+ projectileLabel.x = projectilePreview.x;
+ projectileLabel.y = projectilePreview.y + 80;
+ menuContainer.addChild(projectileLabel);
+ // Guided fire spell preview
+ var guidedPreview = LK.getAsset('fireSpell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 1.2,
+ scaleY: 1.2,
+ alpha: 0.7,
+ tint: 0xFF8800
+ });
+ guidedPreview.x = 1024 + spellSpacing * 1.5;
+ guidedPreview.y = spellPreviewY;
+ menuContainer.addChild(guidedPreview);
+ var guidedLabel = new Text2('Guided', {
+ size: 35,
+ fill: 0xFF8800
+ });
+ guidedLabel.anchor.set(0.5, 0.5);
+ guidedLabel.x = guidedPreview.x;
+ guidedLabel.y = guidedPreview.y + 80;
+ menuContainer.addChild(guidedLabel);
// Add pulsing effect to play button
tween(playButton, {
- scaleX: 3.3,
- scaleY: 3.3
+ scaleX: 3.8,
+ scaleY: 3.8
}, {
- duration: 1000,
+ duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(playButton, {
- scaleX: 3.0,
- scaleY: 3.0
+ scaleX: 3.5,
+ scaleY: 3.5
}, {
- duration: 1000,
+ duration: 1500,
easing: tween.easeInOut
});
}
});
- // Reset button variables
- playButton = null;
- optionsButton = null;
- creditsButton = null;
+ // Add rotation to spell previews
+ tween(firePreview, {
+ rotation: Math.PI * 2
+ }, {
+ duration: 8000,
+ easing: tween.easeLinear
+ });
+ tween(guidedPreview, {
+ rotation: -Math.PI * 2
+ }, {
+ duration: 6000,
+ easing: tween.easeLinear
+ });
// Hide game UI
scoreTxt.visible = false;
waveTxt.visible = false;
waveProgressTxt.visible = false;
@@ -772,8 +898,13 @@
hero.visible = false;
}
function startGame() {
gameState = 'playing';
+ // Save current score if it's a new high score
+ var currentBestScore = storage.get('bestScore') || 0;
+ if (score > currentBestScore) {
+ storage.set('bestScore', score);
+ }
// Remove menu
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
@@ -931,10 +1062,8 @@
var damageCooldown = 120; // 2 seconds invincibility after taking damage
var gameState = 'menu'; // 'menu' or 'playing'
var menuContainer = null;
var playButton = null;
-var optionsButton = null;
-var creditsButton = null;
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
@@ -1142,24 +1271,8 @@
startGame();
return;
}
}
- // Check if options button was pressed
- if (optionsButton) {
- var optionsDistance = Math.sqrt(Math.pow(x - optionsButton.x, 2) + Math.pow(y - optionsButton.y, 2));
- if (optionsDistance < 100) {
- showOptions();
- return;
- }
- }
- // Check if credits button was pressed
- if (creditsButton) {
- var creditsDistance = Math.sqrt(Math.pow(x - creditsButton.x, 2) + Math.pow(y - creditsButton.y, 2));
- if (creditsDistance < 100) {
- showCredits();
- return;
- }
- }
} else if (gameState === 'playing') {
// Check if touching hero
var heroDistance = Math.sqrt(Math.pow(x - hero.x, 2) + Math.pow(y - hero.y, 2));
if (heroDistance < 60) {
@@ -1266,8 +1379,13 @@
healthTxt.setText('Health: ' + heroHealth + '/' + maxHeroHealth);
LK.effects.flashScreen(0xff0000, 500);
LK.effects.flashObject(hero, 0xff0000, 1000);
if (heroHealth <= 0) {
+ // Save high score before game over
+ var currentBestScore = storage.get('bestScore') || 0;
+ if (score > currentBestScore) {
+ storage.set('bestScore', score);
+ }
LK.showGameOver();
return;
}
}
@@ -1280,8 +1398,13 @@
healthTxt.setText('Health: ' + heroHealth + '/' + maxHeroHealth);
LK.effects.flashScreen(0xff4400, 500);
LK.effects.flashObject(hero, 0xff4400, 1000);
if (heroHealth <= 0) {
+ // Save high score before game over
+ var currentBestScore = storage.get('bestScore') || 0;
+ if (score > currentBestScore) {
+ storage.set('bestScore', score);
+ }
LK.showGameOver();
return;
}
}
@@ -1627,109 +1750,5 @@
}
// Game is now infinite - no victory condition
};
// Start first wave
-startWave();
-function showOptions() {
- // Remove current menu
- if (menuContainer) {
- menuContainer.destroy();
- menuContainer = null;
- }
- // Create options menu container
- menuContainer = new Container();
- game.addChild(menuContainer);
- // Create options title
- var optionsTitle = new Text2('OPTIONS', {
- size: 100,
- fill: 0xFFFF00
- });
- optionsTitle.anchor.set(0.5, 0.5);
- optionsTitle.x = 1024;
- optionsTitle.y = 800;
- menuContainer.addChild(optionsTitle);
- // Create options text
- var optionsInfo = new Text2('Sound: ON\nMusic: ON\nDifficulty: Normal', {
- size: 70,
- fill: 0xFFFFFF
- });
- optionsInfo.anchor.set(0.5, 0.5);
- optionsInfo.x = 1024;
- optionsInfo.y = 1200;
- menuContainer.addChild(optionsInfo);
- // Create back button
- var backButton = LK.getAsset('lightOrb', {
- anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.8
- });
- backButton.x = 1024;
- backButton.y = 1600;
- menuContainer.addChild(backButton);
- // Create back button text
- var backText = new Text2('BACK', {
- size: 60,
- fill: 0x000000
- });
- backText.anchor.set(0.5, 0.5);
- backText.x = 1024;
- backText.y = 1600;
- menuContainer.addChild(backText);
- // Add back button handler
- backButton.down = function () {
- createMainMenu();
- };
-}
-function showCredits() {
- // Remove current menu
- if (menuContainer) {
- menuContainer.destroy();
- menuContainer = null;
- }
- // Create credits menu container
- menuContainer = new Container();
- game.addChild(menuContainer);
- // Create credits title
- var creditsTitle = new Text2('CREDITS', {
- size: 100,
- fill: 0xFFFF00
- });
- creditsTitle.anchor.set(0.5, 0.5);
- creditsTitle.x = 1024;
- creditsTitle.y = 700;
- menuContainer.addChild(creditsTitle);
- // Create credits text
- var creditsInfo = new Text2('Game Design: FRVR Team\n\nProgramming: Ava\n\nArt Assets: FRVR Studio\n\nThanks for playing!', {
- size: 60,
- fill: 0xFFFFFF
- });
- creditsInfo.anchor.set(0.5, 0.5);
- creditsInfo.x = 1024;
- creditsInfo.y = 1200;
- menuContainer.addChild(creditsInfo);
- // Create back button
- var backButton = LK.getAsset('lightOrb', {
- anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.8
- });
- backButton.x = 1024;
- backButton.y = 1700;
- menuContainer.addChild(backButton);
- // Create back button text
- var backText = new Text2('BACK', {
- size: 60,
- fill: 0x000000
- });
- backText.anchor.set(0.5, 0.5);
- backText.x = 1024;
- backText.y = 1700;
- menuContainer.addChild(backText);
- // Add back button handler
- backButton.down = function () {
- createMainMenu();
- };
-}
\ No newline at end of file
+startWave();
\ No newline at end of file
bola de fuego de pixeles. In-Game asset. 2d. High contrast. No shadows
monstruo de slime negro de pixeles. In-Game asset. 2d. High contrast. No shadows
suelo de sesped oscuro de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de luz de pixeles. In-Game asset. 2d. High contrast. No shadows
sombra de pixeles que de miedo. In-Game asset. 2d. High contrast. No shadows
portal de pixeles de luz. In-Game asset. 2d. High contrast. No shadows
angel en forma de ojo de pixeles. In-Game asset. 2d. High contrast. No shadows
que ahora tenga una exprecion de determinacion
fuego negro de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de luz azul de pixeles. In-Game asset. 2d. High contrast. No shadows
la muerte de pixeles. In-Game asset. 2d. High contrast. No shadows
orbe oscuro de pixeles con cara enojada. In-Game asset. 2d. High contrast. No shadows
berserquer de pixeles. In-Game asset. 2d. High contrast. No shadows
sombra mimica de pixeles. In-Game asset. 2d. High contrast. No shadows
casa de madera con barricadas de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de hielo de pixeles. In-Game asset. 2d. High contrast. No shadows
bola de viento de pixeles. In-Game asset. 2d. High contrast. No shadows