User prompt
ahora quita el circulo del menu de mejora y pon un cudrado
User prompt
haz que en el menu de mejoras las mejoras se muesten una al lado de la otra
User prompt
ahora el menu de mejora va a ser cuadrado
User prompt
que el brujo sea mas grande
User prompt
aumenta el tamano del brujo
User prompt
has que el menu se cierre cuando se escoja una opcion
User prompt
ahora sale por segunda vez el menu de mejora despues del enemigo 35
User prompt
ahora en el golem empieza a aprecer despues del enemigo 30
User prompt
crea un nuevo enemigo el golem
User prompt
crea una hitbox invisible en los enemigos del doble de su tamaño
User prompt
Quita los puntos amarillos en el menú principal
User prompt
Quita todo lo verde del menú principal
User prompt
Quita los puntos que aparecen en la pantalla de inicio
User prompt
Cambia el menú de inicio y hazlo parecido a la portada de un libro ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Cambia el fondo celeste y pon uno morado
User prompt
Cambia todo el menú de inicio y hazlo parecido a la portada de un libro ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Aplica todas estas mejoras ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Quita la imagen del mago del menú principal
User prompt
Crea un menú de juego más bonito
User prompt
Pon más bonito el camino
User prompt
Crea un nuevo enemigo que sale después del enemigo 30 que se llame golem
User prompt
Que la segunda fase del menú de mejora sea después del enemigo 40
User prompt
Crea una segunda aparición del menú de mejora después del enemigo 30
User prompt
Has más grande la hitbox invisible
User prompt
Has la hitbox invisible más grande
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobOffset = Math.random() * Math.PI * 2;
self.initialY = 0;
self.update = function () {
if (self.initialY === 0) {
self.initialY = self.y;
}
// Only do bobbing animation and collection if not animating to coin counter
if (!self.isAnimating) {
// Bobbing animation
self.y = self.initialY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10;
// Check collection by knight
if (knight && self.intersects(knight)) {
self.collect();
}
}
};
self.collect = function () {
LK.getSound('coinCollect').play();
LK.setScore(LK.getScore() + 5);
coinCounter++;
coinText.setText('Coins: ' + coinCounter);
// Remove from coins array
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] === self) {
coins.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
// Game arrays to track objects
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.5,
scaleY: 1.5
});
// Create invisible larger hitbox for better collision detection
var enemyHitbox = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 5.0,
// Much larger than visible enemy
scaleY: 5.0
});
enemyHitbox.alpha = 0; // Make hitbox invisible
enemyHitbox.tint = 0xFF0000; // Red tint (invisible anyway)
self.health = 100;
self.maxHealth = 100;
self.speed = 7;
// Note: health, maxHealth and speed will be overridden by difficulty system
self.lastX = 0;
self.update = function () {
// Progressive speed increase - increase speed by 50% over 10 seconds
if (!self.speedTweenStarted) {
self.speedTweenStarted = true;
var targetSpeed = self.speed * 2.5; // Increase speed by 150%
tween(self, {
speed: targetSpeed
}, {
duration: 10000,
// 10 seconds
easing: tween.easeOut
});
}
// Move along the assigned path toward the wizard
if (wizard && self.pathAngle !== undefined) {
// Move along the path direction toward the wizard
var moveX = -Math.cos(self.pathAngle) * self.speed;
var moveY = -Math.sin(self.pathAngle) * self.speed;
self.x += moveX;
self.y += moveY;
} else if (wizard) {
// Fallback: move directly toward the wizard if no path assigned
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Fallback: move down if knight doesn't exist
self.y += self.speed;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
// Flash red when hit
LK.effects.flashObject(self, 0xFF0000, 200);
// Enemies die from any projectile hit
self.die();
};
self.down = function (x, y, obj) {
// Create projectile from wizard to enemy when enemy is tapped
if (wizard && projectiles.length < 10) {
// Limit projectiles to prevent spam
var projectile = game.addChild(new Projectile());
projectile.x = wizard.x;
projectile.y = wizard.y;
// Calculate direction from wizard to enemy
var dx = self.x - wizard.x;
var dy = self.y - wizard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
projectile.direction.x = dx / distance;
projectile.direction.y = dy / distance;
}
projectiles.push(projectile);
LK.getSound('spellCast').play();
}
};
self.die = function () {
// Play pain sound when enemy dies
LK.getSound('painSound').play();
// Drop coin
var coin = game.addChild(new Coin());
coin.x = self.x;
coin.y = self.y - 50;
coin.isAnimating = true;
coins.push(coin);
// Animate coin moving toward coin counter
var coinTargetX = 120 + coinText.width / 2;
var coinTargetY = 90 + coinText.height / 2;
tween(coin, {
x: coinTargetX,
y: coinTargetY,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Increment coin counter after animation
coinCounter++;
coinText.setText('Coins: ' + coinCounter);
// Remove coin from array and destroy
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] === coin) {
coins.splice(i, 1);
break;
}
}
coin.destroy();
}
});
// Increment enemy kill counter
enemyKillCounter++;
killCountText.setText('Puntuacion: ' + enemyKillCounter);
// Add experience to wizard
wizard.gainExperience(25);
// Remove from enemies array
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
LK.setScore(LK.getScore() + 10);
};
return self;
});
var GameMenu = Container.expand(function () {
var self = Container.call(this);
// Create book background
var bookBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 25,
scaleY: 35
});
bookBg.tint = 0x1a0e0a; // Very dark brown background
bookBg.alpha = 1;
// Book cover main panel
var bookCover = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 22,
scaleY: 32
});
bookCover.tint = 0x3d2914; // Rich brown leather color
bookCover.alpha = 1;
// Book spine effect (center line)
var bookSpine = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 0.5,
scaleY: 32
});
bookSpine.tint = 0x2a1a0a; // Darker brown for spine
bookSpine.alpha = 0.8;
// Add book corner decorations
var cornerPositions = [{
x: 300,
y: 300
}, {
x: 1748,
y: 300
}, {
x: 300,
y: 2432
}, {
x: 1748,
y: 2432
}];
for (var i = 0; i < cornerPositions.length; i++) {
// Gold corner piece
var corner = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: cornerPositions[i].x,
y: cornerPositions[i].y,
scaleX: 3,
scaleY: 3
});
corner.tint = 0xD4AF37; // Antique gold
corner.alpha = 0.9;
// Corner ornament rotation
var rotation = 0;
if (i === 1) rotation = Math.PI / 2;else if (i === 2) rotation = -Math.PI / 2;else if (i === 3) rotation = Math.PI;
corner.rotation = rotation;
}
// Create ornate border frame
var borderTop = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 400,
scaleX: 20,
scaleY: 0.3
});
borderTop.tint = 0xD4AF37;
borderTop.alpha = 0.7;
var borderBottom = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2332,
scaleX: 20,
scaleY: 0.3
});
borderBottom.tint = 0xD4AF37;
borderBottom.alpha = 0.7;
var borderLeft = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 400,
y: 2732 / 2,
scaleX: 0.3,
scaleY: 28
});
borderLeft.tint = 0xD4AF37;
borderLeft.alpha = 0.7;
var borderRight = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
x: 1648,
y: 2732 / 2,
scaleX: 0.3,
scaleY: 28
});
borderRight.tint = 0xD4AF37;
borderRight.alpha = 0.7;
// Create embossed title effect with gold lettering
var titleShadow = new Text2('WIZARD\nDEFENDER', {
size: 180,
fill: 0x1a0e0a,
font: "monospace"
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 2048 / 2 + 8;
titleShadow.y = 808;
self.addChild(titleShadow);
var titleText = new Text2('WIZARD\nDEFENDER', {
size: 180,
fill: 0xD4AF37,
font: "monospace"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 800;
self.addChild(titleText);
// Add subtle title animation
tween(titleText, {
scaleX: 1.02,
scaleY: 1.02
}, {
duration: 4000,
loop: true,
yoyo: true,
easing: tween.easeInOut
});
// Subtitle in elegant script
var subtitle = new Text2('A Tale of Magic & Defense', {
size: 70,
fill: 0xC9A961,
font: "monospace"
});
subtitle.anchor.set(0.5, 0.5);
subtitle.x = 2048 / 2;
subtitle.y = 1050;
subtitle.alpha = 0.9;
self.addChild(subtitle);
// Add wizard emblem in center
var wizardEmblem = self.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1400,
scaleX: 4,
scaleY: 4
});
wizardEmblem.tint = 0xD4AF37;
wizardEmblem.alpha = 0.3;
// Add circular frame around wizard
var emblemFrame = self.attachAsset('pathSelector', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1400,
scaleX: 5,
scaleY: 5
});
emblemFrame.tint = 0xD4AF37;
emblemFrame.alpha = 0.2;
// Rotate emblem frame slowly
tween(emblemFrame, {
rotation: Math.PI * 2
}, {
duration: 20000,
loop: true,
easing: tween.linear
});
// Author text at bottom
var authorText = new Text2('By the Archmages of FRVR', {
size: 60,
fill: 0xC9A961,
font: "monospace"
});
authorText.anchor.set(0.5, 0.5);
authorText.x = 2048 / 2;
authorText.y = 1800;
authorText.alpha = 0.8;
self.addChild(authorText);
// Start reading button styled as book clasp
var claspBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2100,
scaleX: 4,
scaleY: 1.5
});
claspBg.tint = 0x8B4513; // Saddle brown
var claspMetal = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2100,
scaleX: 2.5,
scaleY: 1.2
});
claspMetal.tint = 0xD4AF37;
var startText = new Text2('OPEN BOOK', {
size: 80,
fill: 0x1a0e0a,
font: "monospace"
});
startText.anchor.set(0.5, 0.5);
startText.x = 2048 / 2;
startText.y = 2100;
self.addChild(startText);
// Add hover effect for clasp
tween(claspMetal, {
scaleX: 2.7,
scaleY: 1.4
}, {
duration: 1500,
loop: true,
yoyo: true,
easing: tween.easeInOut
});
// Sparkles removed to clean up startup screen
// Page edge effect (worn edges)
var leftEdge = self.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0.5,
x: 380,
y: 2732 / 2,
scaleX: 0.1,
scaleY: 30
});
leftEdge.tint = 0xF5DEB3; // Wheat color for pages
leftEdge.alpha = 0.3;
var rightEdge = self.attachAsset('healthBarBg', {
anchorX: 1,
anchorY: 0.5,
x: 1668,
y: 2732 / 2,
scaleX: 0.1,
scaleY: 30
});
rightEdge.tint = 0xF5DEB3;
rightEdge.alpha = 0.3;
// Button interaction
self.down = function (x, y, obj) {
// Check if clasp/button area was clicked
if (x >= 824 && x <= 1224 && y >= 2000 && y <= 2200) {
// Book opening effect
tween(bookCover, {
scaleX: 0.1,
alpha: 0
}, {
duration: 800,
easing: tween.easeIn
});
tween(self, {
rotation: 0.1
}, {
duration: 400,
yoyo: true,
onFinish: function onFinish() {
self.startGame();
}
});
}
};
// Update method for sparkles
self.update = function () {
// Sparkles are animated via tweens, no update needed
};
self.startGame = function () {
// Page turn effect
var pageTurn = self.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 0,
scaleY: 32
});
pageTurn.tint = 0xF5DEB3;
tween(pageTurn, {
scaleX: 25,
x: 2048
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
pageTurn.destroy();
}
});
// Fade out menu
tween(self, {
alpha: 0
}, {
duration: 500,
delay: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
self.alpha = 1;
}
});
gameStarted = true;
// Show all game elements with fade in
castle.visible = true;
castle.alpha = 0;
tween(castle, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
wizard.visible = true;
wizard.alpha = 0;
tween(wizard, {
alpha: 1
}, {
duration: 1000,
delay: 300,
easing: tween.easeOut
});
for (var i = 0; i < paths.length; i++) {
paths[i].visible = true;
}
// Show all stone path segments with staggered animation
for (var i = 0; i < game.children.length; i++) {
var child = game.children[i];
if (child.pathIndex !== undefined && child !== paths[child.pathIndex]) {
child.visible = true;
var originalAlpha = child.alpha;
child.alpha = 0;
tween(child, {
alpha: originalAlpha
}, {
duration: 500,
delay: Math.random() * 500,
easing: tween.easeOut
});
}
}
coinText.visible = true;
killCountText.visible = true;
tapText.visible = true;
healthBarBg.visible = true;
healthBar.visible = true;
healthText.visible = true;
// Start medieval music
LK.playMusic('medievalTheme');
};
return self;
});
var Golem = Container.expand(function () {
var self = Container.call(this);
var golemGraphics = self.attachAsset('golem', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.8,
scaleY: 1.8
});
// Create invisible larger hitbox for better collision detection
var golemHitbox = self.attachAsset('golem', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 5.0,
// Much larger than visible golem
scaleY: 5.0
});
golemHitbox.alpha = 0; // Make hitbox invisible
golemHitbox.tint = 0xFF0000; // Red tint (invisible anyway)
self.health = 200;
self.maxHealth = 200;
self.speed = 4;
self.hitsToKill = 4;
self.hitsTaken = 0;
// Note: health, maxHealth and speed will be overridden by difficulty system
self.lastX = 0;
self.update = function () {
// Progressive speed increase - increase speed by 150% over 10 seconds
if (!self.speedTweenStarted) {
self.speedTweenStarted = true;
var targetSpeed = self.speed * 2.0; // Increase speed by 100%
tween(self, {
speed: targetSpeed
}, {
duration: 12000,
// 12 seconds
easing: tween.easeOut
});
}
// Move along the assigned path toward the wizard
if (wizard && self.pathAngle !== undefined) {
// Move along the path direction toward the wizard
var moveX = -Math.cos(self.pathAngle) * self.speed;
var moveY = -Math.sin(self.pathAngle) * self.speed;
self.x += moveX;
self.y += moveY;
} else if (wizard) {
// Fallback: move directly toward the wizard if no path assigned
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Fallback: move down if knight doesn't exist
self.y += self.speed;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.hitsTaken++;
// Flash red when hit
LK.effects.flashObject(self, 0xFF0000, 200);
// Golems need 4 hits to die
if (self.hitsTaken >= self.hitsToKill) {
self.die();
}
};
self.down = function (x, y, obj) {
// Create projectile from wizard to golem when golem is tapped
if (wizard && projectiles.length < 10) {
// Limit projectiles to prevent spam
var projectile = game.addChild(new Projectile());
projectile.x = wizard.x;
projectile.y = wizard.y;
// Calculate direction from wizard to golem
var dx = self.x - wizard.x;
var dy = self.y - wizard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
projectile.direction.x = dx / distance;
projectile.direction.y = dy / distance;
}
projectiles.push(projectile);
LK.getSound('spellCast').play();
}
};
self.die = function () {
// Play pain sound when golem dies
LK.getSound('painSound').play();
// Drop coin
var coin = game.addChild(new Coin());
coin.x = self.x;
coin.y = self.y - 50;
coin.isAnimating = true;
coins.push(coin);
// Animate coin moving toward coin counter
var coinTargetX = 120 + coinText.width / 2;
var coinTargetY = 90 + coinText.height / 2;
tween(coin, {
x: coinTargetX,
y: coinTargetY,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Increment coin counter after animation
coinCounter++;
coinText.setText('Coins: ' + coinCounter);
// Remove coin from array and destroy
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] === coin) {
coins.splice(i, 1);
break;
}
}
coin.destroy();
}
});
// Increment enemy kill counter
enemyKillCounter++;
killCountText.setText('Puntuacion: ' + enemyKillCounter);
// Add experience to wizard
wizard.gainExperience(25);
// Remove from golems array
for (var i = golems.length - 1; i >= 0; i--) {
if (golems[i] === self) {
golems.splice(i, 1);
break;
}
}
self.destroy();
LK.setScore(LK.getScore() + 20);
};
return self;
});
var Ogre = Container.expand(function () {
var self = Container.call(this);
var ogreGraphics = self.attachAsset('ogre', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.5,
scaleY: 1.5
});
// Create invisible larger hitbox for better collision detection
var ogreHitbox = self.attachAsset('ogre', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 5.0,
// Much larger than visible ogre
scaleY: 5.0
});
ogreHitbox.alpha = 0; // Make hitbox invisible
ogreHitbox.tint = 0xFF0000; // Red tint (invisible anyway)
self.health = 100;
self.maxHealth = 100;
self.speed = 7;
self.hitsToKill = 2;
self.hitsTaken = 0;
// Note: health, maxHealth and speed will be overridden by difficulty system
self.lastX = 0;
self.update = function () {
// Progressive speed increase - increase speed by 150% over 10 seconds
if (!self.speedTweenStarted) {
self.speedTweenStarted = true;
var targetSpeed = self.speed * 2.5; // Increase speed by 150%
tween(self, {
speed: targetSpeed
}, {
duration: 10000,
// 10 seconds
easing: tween.easeOut
});
}
// Move along the assigned path toward the wizard
if (wizard && self.pathAngle !== undefined) {
// Move along the path direction toward the wizard
var moveX = -Math.cos(self.pathAngle) * self.speed;
var moveY = -Math.sin(self.pathAngle) * self.speed;
self.x += moveX;
self.y += moveY;
} else if (wizard) {
// Fallback: move directly toward the wizard if no path assigned
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Normalize direction and apply speed
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else {
// Fallback: move down if knight doesn't exist
self.y += self.speed;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
self.hitsTaken++;
// Flash red when hit
LK.effects.flashObject(self, 0xFF0000, 200);
// Ogres need 2 hits to die
if (self.hitsTaken >= self.hitsToKill) {
self.die();
}
};
self.down = function (x, y, obj) {
// Create projectile from wizard to ogre when ogre is tapped
if (wizard && projectiles.length < 10) {
// Limit projectiles to prevent spam
var projectile = game.addChild(new Projectile());
projectile.x = wizard.x;
projectile.y = wizard.y;
// Calculate direction from wizard to ogre
var dx = self.x - wizard.x;
var dy = self.y - wizard.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
projectile.direction.x = dx / distance;
projectile.direction.y = dy / distance;
}
projectiles.push(projectile);
LK.getSound('spellCast').play();
}
};
self.die = function () {
// Play pain sound when ogre dies
LK.getSound('painSound').play();
// Drop coin
var coin = game.addChild(new Coin());
coin.x = self.x;
coin.y = self.y - 50;
coin.isAnimating = true;
coins.push(coin);
// Animate coin moving toward coin counter
var coinTargetX = 120 + coinText.width / 2;
var coinTargetY = 90 + coinText.height / 2;
tween(coin, {
x: coinTargetX,
y: coinTargetY,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Increment coin counter after animation
coinCounter++;
coinText.setText('Coins: ' + coinCounter);
// Remove coin from array and destroy
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] === coin) {
coins.splice(i, 1);
break;
}
}
coin.destroy();
}
});
// Increment enemy kill counter
enemyKillCounter++;
killCountText.setText('Puntuacion: ' + enemyKillCounter);
// Add experience to wizard
wizard.gainExperience(25);
// Remove from ogres array
for (var i = ogres.length - 1; i >= 0; i--) {
if (ogres[i] === self) {
ogres.splice(i, 1);
break;
}
}
self.destroy();
LK.setScore(LK.getScore() + 15);
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 50;
self.direction = {
x: 0,
y: 0
};
self.lastIntersecting = {};
self.update = function () {
// Move projectile
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.removeFromGame();
return;
}
// Check collision with enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!self.lastIntersecting[i]) {
self.lastIntersecting[i] = false;
}
var currentIntersecting = self.intersects(enemy);
if (!self.lastIntersecting[i] && currentIntersecting) {
// Hit enemy
enemy.takeDamage(50);
self.removeFromGame();
return;
}
self.lastIntersecting[i] = currentIntersecting;
}
// Check collision with ogres
for (var i = ogres.length - 1; i >= 0; i--) {
var ogre = ogres[i];
var ogreKey = 'ogre_' + i;
if (!self.lastIntersecting[ogreKey]) {
self.lastIntersecting[ogreKey] = false;
}
var currentOgreIntersecting = self.intersects(ogre);
if (!self.lastIntersecting[ogreKey] && currentOgreIntersecting) {
// Hit ogre
ogre.takeDamage(50);
self.removeFromGame();
return;
}
self.lastIntersecting[ogreKey] = currentOgreIntersecting;
}
// Check collision with golems
for (var i = golems.length - 1; i >= 0; i--) {
var golem = golems[i];
var golemKey = 'golem_' + i;
if (!self.lastIntersecting[golemKey]) {
self.lastIntersecting[golemKey] = false;
}
var currentGolemIntersecting = self.intersects(golem);
if (!self.lastIntersecting[golemKey] && currentGolemIntersecting) {
// Hit golem
golem.takeDamage(50);
self.removeFromGame();
return;
}
self.lastIntersecting[golemKey] = currentGolemIntersecting;
}
};
self.removeFromGame = function () {
// Remove from projectiles array
for (var i = projectiles.length - 1; i >= 0; i--) {
if (projectiles[i] === self) {
projectiles.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var UpgradeMenu = Container.expand(function () {
var self = Container.call(this);
// Set high z-index to ensure menu appears above all game elements
self.zIndex = 1000;
// Cooldown system for upgrade menu
self.cooldownDuration = 120; // 2 seconds at 60fps
self.cooldownTimer = 0;
// Semi-transparent background overlay
var menuBg = self.attachAsset('pathSelector', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 30,
scaleY: 40
});
menuBg.alpha = 0.8;
menuBg.tint = 0x4A4A4A; // Dark gray background
// Title text
var titleText = new Text2('UPGRADES', {
size: 120,
fill: 0xFFD700,
font: "monospace"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
self.addChild(titleText);
// Upgrade options
var upgradeOptions = [{
name: 'ATTACK SPEED',
description: 'Faster spells'
}, {
name: 'SPELL POWER',
description: 'More damage'
}, {
name: 'HEALTH BOOST',
description: 'More health'
}];
// Create upgrade buttons
for (var i = 0; i < upgradeOptions.length; i++) {
var upgrade = upgradeOptions[i];
var yPos = 1000 + i * 300;
// Upgrade button background
var upgradeBtn = self.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: yPos,
scaleX: 3,
scaleY: 1.5
});
upgradeBtn.upgradeIndex = i;
upgradeBtn.tint = 0x8B008B;
// Upgrade text
var upgradeText = new Text2(upgrade.name + '\n' + upgrade.description + '\nCost: 10 coins', {
size: 60,
fill: 0xFFFFFF,
font: "monospace"
});
upgradeText.anchor.set(0.5, 0.5);
upgradeText.x = 2048 / 2;
upgradeText.y = yPos;
self.addChild(upgradeText);
}
// Close button
var closeBtn = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2200,
scaleX: 2,
scaleY: 2
});
closeBtn.tint = 0xFF0000;
var closeText = new Text2('CLOSE', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 2048 / 2;
closeText.y = 2200;
self.addChild(closeText);
// Update method for cooldown timer
self.update = function () {
if (self.cooldownTimer > 0) {
self.cooldownTimer--;
// Apply visual feedback during cooldown
var cooldownAlpha = 0.3 + self.cooldownTimer / self.cooldownDuration * 0.7;
self.alpha = cooldownAlpha;
} else {
self.alpha = 1.0; // Full opacity when cooldown is over
}
};
// Handle upgrade purchases
self.down = function (x, y, obj) {
// Check if cooldown is active
if (self.cooldownTimer > 0) {
// Flash red to indicate cooldown is active
LK.effects.flashScreen(0xFF0000, 200);
return; // Exit early if cooldown is active
}
// Determine which upgrade was clicked based on Y position
var upgradeIndex = -1;
if (y >= 850 && y <= 1150) {
upgradeIndex = 0; // Attack Speed
} else if (y >= 1150 && y <= 1450) {
upgradeIndex = 1; // Spell Power
} else if (y >= 1450 && y <= 1750) {
upgradeIndex = 2; // Health Boost
}
// Check if upgrade button was clicked
if (upgradeIndex !== -1) {
if (coinCounter >= 10) {
coinCounter -= 10;
coinText.setText('Coins: ' + coinCounter);
// Apply upgrade based on index
switch (upgradeIndex) {
case 0:
// Attack Speed - reduce cooldown
wizard.attackCooldown = Math.max(5, wizard.attackCooldown - 5);
break;
case 1:
// Spell Power - increase damage multiplier
if (!wizard.spellPowerLevel) wizard.spellPowerLevel = 0;
wizard.spellPowerLevel++;
break;
case 2:
// Health Boost
wizard.maxHealth += 25;
wizard.health = Math.min(wizard.health + 25, wizard.maxHealth);
updateHealthBar();
break;
}
// Visual feedback - flash the upgrade area green
LK.effects.flashScreen(0x00FF00, 300);
// Close menu and resume game after successful purchase
self.closeMenu();
} else {
// Not enough coins - flash red
LK.effects.flashScreen(0xFF0000, 300);
// Close menu even when not enough coins
self.closeMenu();
}
} else if (y >= 2050 && y <= 2350) {
// Close button area clicked
self.closeMenu();
}
};
self.closeMenu = function () {
self.visible = false;
gameStarted = true;
// Resume game time
LK.playMusic('medievalTheme');
};
return self;
});
var Wizard = Container.expand(function () {
var self = Container.call(this);
var wizardGraphics = self.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 1.0
});
self.attackCooldown = 0;
self.level = 1;
self.experience = 0;
self.health = 100;
self.maxHealth = 100;
self.spellPowerLevel = 0; // Track spell power upgrades
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
self.attack = function (direction) {
if (self.attackCooldown <= 0) {
// Default direction if none specified
if (direction === undefined) {
direction = 0; // Default to center path
}
// Get attack angle based on path direction
var attackAngle = pathAngles[direction];
var attackDistance = 100;
// Calculate spell position based on attack direction
var spellX = self.x + Math.cos(attackAngle) * attackDistance;
var spellY = self.y + Math.sin(attackAngle) * attackDistance;
// Create spell effect
var spell = game.addChild(LK.getAsset('spell', {
anchorX: 0.5,
anchorY: 0.5,
x: spellX,
y: spellY,
scaleX: 0.5,
scaleY: 0.5
}));
// Animate spell with magical effects
tween(spell, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
spell.destroy();
}
});
// Add rotation animation to spell
tween(spell, {
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.linear
});
self.attackCooldown = 30; // 0.5 seconds at 60fps
LK.getSound('spellCast').play();
// Calculate damage based on spell power upgrades
var baseDamage = 50;
var spellPowerMultiplier = 1 + (self.spellPowerLevel || 0) * 0.5; // 50% more damage per upgrade
var totalDamage = Math.floor(baseDamage * spellPowerMultiplier);
// Attack enemies in the specified direction/path
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.pathIndex === direction) {
// Check if enemy is within attack range along this path
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Attack range
enemy.takeDamage(totalDamage);
}
}
}
// Attack ogres in the specified direction/path
for (var i = ogres.length - 1; i >= 0; i--) {
var ogre = ogres[i];
if (ogre.pathIndex === direction) {
// Check if ogre is within attack range along this path
var dx = ogre.x - self.x;
var dy = ogre.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Attack range
ogre.takeDamage(totalDamage);
}
}
}
// Attack golems in the specified direction/path
for (var i = golems.length - 1; i >= 0; i--) {
var golem = golems[i];
if (golem.pathIndex === direction) {
// Check if golem is within attack range along this path
var dx = golem.x - self.x;
var dy = golem.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Attack range
golem.takeDamage(totalDamage);
}
}
}
return true;
}
return false;
};
self.gainExperience = function (amount) {
self.experience += amount;
var expNeeded = self.level * 100;
if (self.experience >= expNeeded) {
self.levelUp();
}
};
self.levelUp = function () {
self.level++;
self.experience = 0;
// Visual level up effect
LK.effects.flashObject(self, 0xFFD700, 500);
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
// Game over when health reaches 0
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
}
// Update health bar
updateHealthBar();
// Flash red when hit
LK.effects.flashObject(self, 0xFF0000, 200);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x800080 // Purple background
});
/****
* Game Code
****/
// Game state variables
var gameStarted = false;
var gameMenu;
var upgradeMenu;
var upgradeMenuShown = false;
var secondUpgradeMenuShown = false;
// Game arrays to track objects
var enemies = [];
var ogres = [];
var golems = [];
var coins = [];
var projectiles = [];
// Create and show game menu
gameMenu = game.addChild(new GameMenu());
// Create upgrade menu (initially hidden)
upgradeMenu = game.addChild(new UpgradeMenu());
upgradeMenu.visible = false;
// Create castle background
var castle = game.addChild(LK.getAsset('castle', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: 2732 - 200
}));
castle.visible = false;
// Create 5 stone paths leading toward the wizard position
var paths = [];
var knightX = 2048 / 2;
var knightY = 2732 - 250;
// Create paths: center, two diagonal, and two side paths
var pathAngles = [-Math.PI / 2,
// Center (straight down)
-Math.PI / 4,
// Diagonal right
-3 * Math.PI / 4,
// Diagonal left
0,
// Right side (horizontal)
Math.PI // Left side (horizontal)
]; // 5 paths: center, two diagonal, two sides
// Create multiple stone segments for each path to form visible stone roads
for (var p = 0; p < 5; p++) {
var angle = pathAngles[p];
// Calculate path length - make center path longer
var pathLength = p === 0 ? 3000 : 1800; // Center path is longer
var segmentSize = 120; // Size of each stone segment
var numSegments = Math.floor(pathLength / segmentSize);
// Path-specific colors for visual distinction
var pathColors = [0x8B7355,
// Center path - warm brown
0x696969,
// Diagonal right - dark gray
0x708090,
// Diagonal left - slate gray
0x778899,
// Right side - light slate gray
0x556B2F // Left side - dark olive green
];
// Create individual stone segments along the path
for (var s = 0; s < numSegments; s++) {
var segmentDistance = s * segmentSize + segmentSize / 2;
var segmentX = knightX + Math.cos(angle) * segmentDistance;
var segmentY = knightY + Math.sin(angle) * segmentDistance;
// Create main stone path segment
var stoneSegment = game.addChild(LK.getAsset('stonePath', {
anchorX: 0.5,
anchorY: 0.5,
x: segmentX,
y: segmentY,
scaleX: 2.0 + Math.random() * 0.4,
// Slight size variation
scaleY: 2.0 + Math.random() * 0.4,
rotation: angle + Math.PI / 2 + (Math.random() - 0.5) * 0.3 // Slight rotation variety
}));
// Apply path-specific coloring and transparency
stoneSegment.tint = pathColors[p];
stoneSegment.alpha = 0.7 + Math.random() * 0.25; // Better transparency range
stoneSegment.visible = false;
stoneSegment.pathIndex = p;
// Add decorative border stones for center path
if (p === 0 && s % 3 === 0) {
// Every 3rd segment on center path
// Left border stone
var leftBorder = game.addChild(LK.getAsset('stonePath', {
anchorX: 0.5,
anchorY: 0.5,
x: segmentX + Math.cos(angle + Math.PI / 2) * 80,
y: segmentY + Math.sin(angle + Math.PI / 2) * 80,
scaleX: 1.2,
scaleY: 1.2,
rotation: angle + Math.PI / 2
}));
leftBorder.tint = 0x654321; // Darker brown
leftBorder.alpha = 0.8;
leftBorder.visible = false;
leftBorder.pathIndex = p;
// Right border stone
var rightBorder = game.addChild(LK.getAsset('stonePath', {
anchorX: 0.5,
anchorY: 0.5,
x: segmentX + Math.cos(angle - Math.PI / 2) * 80,
y: segmentY + Math.sin(angle - Math.PI / 2) * 80,
scaleX: 1.2,
scaleY: 1.2,
rotation: angle + Math.PI / 2
}));
rightBorder.tint = 0x654321; // Darker brown
rightBorder.alpha = 0.8;
rightBorder.visible = false;
rightBorder.pathIndex = p;
}
// Add small decorative stones around main paths
if (s % 4 === 1 && Math.random() > 0.6) {
// Random decorative stones
var decorX = segmentX + (Math.random() - 0.5) * 200;
var decorY = segmentY + (Math.random() - 0.5) * 200;
var decorStone = game.addChild(LK.getAsset('stonePath', {
anchorX: 0.5,
anchorY: 0.5,
x: decorX,
y: decorY,
scaleX: 0.8 + Math.random() * 0.6,
scaleY: 0.8 + Math.random() * 0.6,
rotation: Math.random() * Math.PI * 2
}));
decorStone.tint = 0x2F4F4F; // Dark slate gray
decorStone.alpha = 0.4 + Math.random() * 0.3;
decorStone.visible = false;
decorStone.pathIndex = p;
}
}
}
// Create invisible path collision areas for touch detection
for (var p = 0; p < 5; p++) {
var angle = pathAngles[p];
var pathLength = p === 0 ? 3000 : 1800;
var centerX = knightX + Math.cos(angle) * (pathLength / 2);
var centerY = knightY + Math.sin(angle) * (pathLength / 2);
// Create invisible collision path
var path = game.addChild(LK.getAsset('pathSelector', {
anchorX: 0.5,
anchorY: 0.5,
x: centerX,
y: centerY,
scaleX: 2,
scaleY: pathLength / 60,
rotation: angle + Math.PI / 2
}));
// Make collision path completely invisible
path.alpha = 0;
path.visible = false;
path.pathIndex = p;
// Add touch handler for directional attacks
path.down = function (x, y, obj) {
// Attack in this path's direction
wizard.attack(obj.pathIndex);
// Visual feedback - flash all stone segments on this path
for (var i = 0; i < game.children.length; i++) {
var child = game.children[i];
if (child.pathIndex === obj.pathIndex && child !== obj) {
LK.effects.flashObject(child, 0xFFFFFF, 300);
}
}
};
paths.push(path);
}
// Create wizard
var wizard = game.addChild(new Wizard());
wizard.x = knightX;
wizard.y = knightY;
wizard.visible = false;
// UI Elements
// Removed scoreText and levelText to eliminate stray characters in top right
var coinCounter = 0;
var enemyKillCounter = 0;
var coinText = new Text2('Coins: 0', {
size: 60,
fill: 0xFFD700,
font: "monospace"
});
coinText.anchor.set(0, 0);
LK.gui.topLeft.addChild(coinText);
coinText.x = 120;
coinText.y = 90;
coinText.visible = false;
var killCountText = new Text2('Puntuacion: 0', {
size: 60,
fill: 0xFF6B6B,
font: "monospace"
});
killCountText.anchor.set(0, 0);
LK.gui.topLeft.addChild(killCountText);
killCountText.x = 120;
killCountText.y = 150;
killCountText.visible = false;
var tapText = new Text2('TAP TO CAST SPELLS!', {
size: 100,
fill: 0xFF6B6B,
font: "monospace"
});
tapText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(tapText);
tapText.y = -200;
tapText.visible = false;
// Health bar UI
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBarBg);
healthBarBg.x = 120;
healthBarBg.y = 20;
healthBarBg.visible = false;
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBar);
healthBar.x = 120;
healthBar.y = 20;
healthBar.visible = false;
var healthText = new Text2('Health: 100/100', {
size: 50,
fill: 0xFFFFFF,
font: "monospace"
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 120;
healthText.y = 50;
healthText.visible = false;
function updateHealthBar() {
var healthPercent = wizard.health / wizard.maxHealth;
healthBar.scaleX = healthPercent;
healthText.setText('Health: ' + wizard.health + '/' + wizard.maxHealth);
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
}
// Enemy spawning variables
var enemySpawnTimer = 0;
var lastSpawnedPath = -1; // Track the last spawned path
var consecutiveSpawns = 0; // Track consecutive spawns from same path
// Cooldown system variables
var pathLastSpawnTime = [-1, -1, -1, -1, -1]; // Track last spawn time for each path
var pathConsecutiveSpawns = [0, 0, 0, 0, 0]; // Track consecutive spawns per path
var pathCooldownDuration = 300; // 5 seconds at 60fps
// Game input handling
game.down = function (x, y, obj) {
// Check if a path was tapped for directional attack
var pathTapped = false;
for (var p = 0; p < paths.length; p++) {
var path = paths[p];
// Convert tap position to path's local coordinates
var localPos = path.toLocal({
x: x,
y: y
});
// Check if tap is within path bounds
if (Math.abs(localPos.x) < path.width / 2 && Math.abs(localPos.y) < path.height / 2) {
// Attack in this path's direction
wizard.attack(path.pathIndex);
pathTapped = true;
break;
}
}
// No default attack - player must tap a path to attack
};
// Main game update loop
game.update = function () {
// Sort children by z-index to ensure proper rendering order
game.children.sort(function (a, b) {
return (a.zIndex || 0) - (b.zIndex || 0);
});
// Only update game logic if game has started
if (!gameStarted) {
return;
}
// Show upgrade menu after 12 enemies are killed
if (enemyKillCounter >= 12 && !upgradeMenuShown) {
upgradeMenuShown = true;
upgradeMenu.visible = true;
upgradeMenu.cooldownTimer = upgradeMenu.cooldownDuration; // Start 2-second cooldown
gameStarted = false; // Pause game while menu is open
LK.stopMusic(); // Pause music
// Clear all enemies on screen when upgrade menu is shown
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemies.splice(i, 1);
enemy.destroy();
}
// Clear all ogres on screen when upgrade menu is shown
for (var i = ogres.length - 1; i >= 0; i--) {
var ogre = ogres[i];
ogres.splice(i, 1);
ogre.destroy();
}
// Clear all golems on screen when upgrade menu is shown
for (var i = golems.length - 1; i >= 0; i--) {
var golem = golems[i];
golems.splice(i, 1);
golem.destroy();
}
}
// Show second upgrade menu after 40 enemies are killed
if (enemyKillCounter >= 40 && !secondUpgradeMenuShown) {
secondUpgradeMenuShown = true;
upgradeMenu.visible = true;
upgradeMenu.cooldownTimer = upgradeMenu.cooldownDuration; // Start 2-second cooldown
gameStarted = false; // Pause game while menu is open
LK.stopMusic(); // Pause music
// Clear all enemies on screen when upgrade menu is shown
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemies.splice(i, 1);
enemy.destroy();
}
// Clear all ogres on screen when upgrade menu is shown
for (var i = ogres.length - 1; i >= 0; i--) {
var ogre = ogres[i];
ogres.splice(i, 1);
ogre.destroy();
}
// Clear all golems on screen when upgrade menu is shown
for (var i = golems.length - 1; i >= 0; i--) {
var golem = golems[i];
golems.splice(i, 1);
golem.destroy();
}
}
// Reset consecutive spawns for paths that have cooled down (runs every frame)
for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
// Check if enough time has passed since last spawn (cooldown expired)
if (pathLastSpawnTime[pathIdx] !== -1 && LK.ticks - pathLastSpawnTime[pathIdx] > pathCooldownDuration) {
// Reset consecutive spawns for this path due to cooldown
pathConsecutiveSpawns[pathIdx] = 0;
}
}
// Progressive difficulty system based on kills
var difficultyLevel = Math.floor(enemyKillCounter / 10); // Every 10 kills increases difficulty
var currentSpawnRate = Math.max(30, 90 - difficultyLevel * 8); // Faster spawning over time
var enemyHealthMultiplier = 1 + difficultyLevel * 0.3; // 30% more health per difficulty level
var enemySpeedMultiplier = 1 + difficultyLevel * 0.35; // 35% faster per difficulty level
// Spawn enemies
enemySpawnTimer++;
if (enemySpawnTimer >= currentSpawnRate) {
enemySpawnTimer = 0;
var enemy = game.addChild(new Enemy());
// Apply difficulty scaling to enemy stats
enemy.health = Math.floor(100 * enemyHealthMultiplier);
enemy.maxHealth = enemy.health;
enemy.speed = 3 * enemySpeedMultiplier;
// Spawn enemy at a random path entrance
var randomPathIndex;
if (enemyKillCounter < 5) {
// First 5 enemies spawn from center path only
randomPathIndex = 0; // Center path
} else {
// After 5 enemies, spawn from any path but limit consecutive spawns with cooldown system
// Build available paths list
var availablePaths = [];
for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
// If path has spawned less than 2 consecutive times, it's available
if (pathConsecutiveSpawns[pathIdx] < 2) {
availablePaths.push(pathIdx);
}
}
// If no paths available, reset ALL paths to ensure balanced distribution
if (availablePaths.length === 0) {
// Reset all paths' consecutive spawn counters
for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
pathConsecutiveSpawns[pathIdx] = 0;
availablePaths.push(pathIdx);
}
}
randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)];
}
// Update path-specific spawn tracking
// Always increment consecutive spawns for the selected path
pathConsecutiveSpawns[randomPathIndex]++;
// Update path spawn time and global tracking
pathLastSpawnTime[randomPathIndex] = LK.ticks;
lastSpawnedPath = randomPathIndex;
consecutiveSpawns = pathConsecutiveSpawns[randomPathIndex];
var pathAngle = pathAngles[randomPathIndex];
// Store the path information on the enemy
enemy.pathIndex = randomPathIndex;
enemy.pathAngle = pathAngle;
// Calculate spawn position at the far end of the path (screen edge)
var pathLength = randomPathIndex === 0 ? 3000 : 1800; // Match path lengths
var spawnDistance = pathLength * 0.8; // Spawn farther away - 80% of path length
enemy.x = knightX + Math.cos(pathAngle) * spawnDistance;
enemy.y = knightY + Math.sin(pathAngle) * spawnDistance;
// Make sure enemies spawn within screen bounds
enemy.x = Math.max(50, Math.min(1998, enemy.x));
enemy.y = Math.max(-200, Math.min(2732 + 100, enemy.y));
enemy.lastX = enemy.x;
enemies.push(enemy);
}
// Spawn ogres after 15 seconds (900 ticks at 60fps)
if (LK.ticks >= 900 && LK.ticks % 180 === 0) {
// Every 3 seconds after 15 seconds
var ogre = game.addChild(new Ogre());
// Apply difficulty scaling to ogre stats
ogre.health = Math.floor(150 * enemyHealthMultiplier); // Ogres have more base health
ogre.maxHealth = ogre.health;
ogre.speed = 2.5 * enemySpeedMultiplier; // Ogres are slightly slower
// Spawn ogre at a random path entrance
var ogrePathIndex = Math.floor(Math.random() * 5);
var ogrePathAngle = pathAngles[ogrePathIndex];
// Store the path information on the ogre
ogre.pathIndex = ogrePathIndex;
ogre.pathAngle = ogrePathAngle;
// Calculate spawn position at the far end of the path (screen edge)
var ogrePathLength = ogrePathIndex === 0 ? 3000 : 1800;
var ogreSpawnDistance = ogrePathLength * 0.8;
ogre.x = knightX + Math.cos(ogrePathAngle) * ogreSpawnDistance;
ogre.y = knightY + Math.sin(ogrePathAngle) * ogreSpawnDistance;
// Make sure ogres spawn within screen bounds
ogre.x = Math.max(50, Math.min(1998, ogre.x));
ogre.y = Math.max(-200, Math.min(2732 + 100, ogre.y));
ogre.lastX = ogre.x;
ogres.push(ogre);
}
// Spawn golems after 30 enemies killed
if (enemyKillCounter >= 30 && LK.ticks % 240 === 0) {
// Every 4 seconds after 30 enemies killed
var golem = game.addChild(new Golem());
// Apply difficulty scaling to golem stats
golem.health = Math.floor(200 * enemyHealthMultiplier); // Golems have most base health
golem.maxHealth = golem.health;
golem.speed = 2 * enemySpeedMultiplier; // Golems are slowest
// Spawn golem at a random path entrance
var golemPathIndex = Math.floor(Math.random() * 5);
var golemPathAngle = pathAngles[golemPathIndex];
// Store the path information on the golem
golem.pathIndex = golemPathIndex;
golem.pathAngle = golemPathAngle;
// Calculate spawn position at the far end of the path (screen edge)
var golemPathLength = golemPathIndex === 0 ? 3000 : 1800;
var golemSpawnDistance = golemPathLength * 0.8;
golem.x = knightX + Math.cos(golemPathAngle) * golemSpawnDistance;
golem.y = knightY + Math.sin(golemPathAngle) * golemSpawnDistance;
// Make sure golems spawn within screen bounds
golem.x = Math.max(50, Math.min(1998, golem.x));
golem.y = Math.max(-200, Math.min(2732 + 100, golem.y));
golem.lastX = golem.x;
golems.push(golem);
}
// Check enemy-knight collisions and cleanup off-screen enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Remove enemies that went off-screen at bottom
if (enemy.y > 2732 + 100) {
enemies.splice(i, 1);
enemy.destroy();
continue;
}
// Initialize lastIntersecting if not set
if (enemy.lastIntersecting === undefined) {
enemy.lastIntersecting = false;
}
// Check for collision transition
var currentIntersecting = enemy.intersects(wizard);
if (!enemy.lastIntersecting && currentIntersecting) {
// Damage wizard when enemy touches for the first time
wizard.takeDamage(20);
// Remove enemy after dealing damage
enemies.splice(i, 1);
enemy.destroy();
continue;
}
// Update last intersecting state
enemy.lastIntersecting = currentIntersecting;
}
// Check ogre-wizard collisions and cleanup off-screen ogres
for (var i = ogres.length - 1; i >= 0; i--) {
var ogre = ogres[i];
// Remove ogres that went off-screen at bottom
if (ogre.y > 2732 + 100) {
ogres.splice(i, 1);
ogre.destroy();
continue;
}
// Initialize lastIntersecting if not set
if (ogre.lastIntersecting === undefined) {
ogre.lastIntersecting = false;
}
// Check for collision transition
var currentOgreIntersecting = ogre.intersects(wizard);
if (!ogre.lastIntersecting && currentOgreIntersecting) {
// Damage wizard when ogre touches for the first time
wizard.takeDamage(30); // Ogres deal 30 damage
// Remove ogre after dealing damage
ogres.splice(i, 1);
ogre.destroy();
continue;
}
// Update last intersecting state
ogre.lastIntersecting = currentOgreIntersecting;
}
// Check golem-wizard collisions and cleanup off-screen golems
for (var i = golems.length - 1; i >= 0; i--) {
var golem = golems[i];
// Remove golems that went off-screen at bottom
if (golem.y > 2732 + 100) {
golems.splice(i, 1);
golem.destroy();
continue;
}
// Initialize lastIntersecting if not set
if (golem.lastIntersecting === undefined) {
golem.lastIntersecting = false;
}
// Check for collision transition
var currentGolemIntersecting = golem.intersects(wizard);
if (!golem.lastIntersecting && currentGolemIntersecting) {
// Damage wizard when golem touches for the first time
wizard.takeDamage(40); // Golems deal 40 damage
// Remove golem after dealing damage
golems.splice(i, 1);
golem.destroy();
continue;
}
// Update last intersecting state
golem.lastIntersecting = currentGolemIntersecting;
}
// Make tap text pulse
var pulse = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
tapText.scale.set(pulse, pulse);
};
// Remove tap text after 5 seconds
tween({}, {}, {
duration: 5000,
onFinish: function onFinish() {
if (tapText && tapText.parent) {
tapText.destroy();
}
}
}); ===================================================================
--- original.js
+++ change.js
@@ -182,455 +182,312 @@
return self;
});
var GameMenu = Container.expand(function () {
var self = Container.call(this);
- // Create parchment-style book background
- var bookBackground = self.attachAsset('pathSelector', {
+ // Create book background
+ var bookBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
- scaleX: 32,
- scaleY: 42
+ scaleX: 25,
+ scaleY: 35
});
- bookBackground.alpha = 0.98;
- bookBackground.tint = 0xF5DEB3; // Wheat color for parchment
- // Create ornate book border frame
- var outerBorder = self.attachAsset('healthBarBg', {
+ bookBg.tint = 0x1a0e0a; // Very dark brown background
+ bookBg.alpha = 1;
+ // Book cover main panel
+ var bookCover = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
- scaleX: 34,
- scaleY: 44
+ scaleX: 22,
+ scaleY: 32
});
- outerBorder.alpha = 1.0;
- outerBorder.tint = 0x8B4513; // Dark brown leather binding
- // Inner decorative border
- var innerBorder = self.attachAsset('healthBarBg', {
+ bookCover.tint = 0x3d2914; // Rich brown leather color
+ bookCover.alpha = 1;
+ // Book spine effect (center line)
+ var bookSpine = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
- scaleX: 30,
- scaleY: 40
+ scaleX: 0.5,
+ scaleY: 32
});
- innerBorder.alpha = 0.8;
- innerBorder.tint = 0xDAA520; // Goldenrod border
- // Create corner decorations (ornate book corners)
+ bookSpine.tint = 0x2a1a0a; // Darker brown for spine
+ bookSpine.alpha = 0.8;
+ // Add book corner decorations
var cornerPositions = [{
- x: 400,
- y: 400
- },
- // Top left
- {
- x: 1648,
- y: 400
- },
- // Top right
- {
- x: 400,
- y: 2332
- },
- // Bottom left
- {
- x: 1648,
- y: 2332
- } // Bottom right
- ];
+ x: 300,
+ y: 300
+ }, {
+ x: 1748,
+ y: 300
+ }, {
+ x: 300,
+ y: 2432
+ }, {
+ x: 1748,
+ y: 2432
+ }];
for (var i = 0; i < cornerPositions.length; i++) {
- var corner = self.attachAsset('spell', {
+ // Gold corner piece
+ var corner = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
x: cornerPositions[i].x,
y: cornerPositions[i].y,
scaleX: 3,
scaleY: 3
});
- corner.alpha = 0.7;
- corner.tint = 0xFFD700; // Gold corner decorations
- corner.rotation = Math.PI / 2 * i; // Rotate each corner
- // Gentle glow animation for corners
- tween(corner, {
- scaleX: 3.5,
- scaleY: 3.5,
- alpha: 0.9
- }, {
- duration: 3000,
- loop: true,
- yoyo: true,
- easing: tween.easeInOut
- });
+ corner.tint = 0xD4AF37; // Antique gold
+ corner.alpha = 0.9;
+ // Corner ornament rotation
+ var rotation = 0;
+ if (i === 1) rotation = Math.PI / 2;else if (i === 2) rotation = -Math.PI / 2;else if (i === 3) rotation = Math.PI;
+ corner.rotation = rotation;
}
- // Create book spine decoration on left side
- for (var i = 0; i < 12; i++) {
- var spineDecor = self.attachAsset('stonePath', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 200,
- y: 600 + i * 150,
- scaleX: 0.8,
- scaleY: 2.5
- });
- spineDecor.tint = 0x654321; // Dark brown spine details
- spineDecor.alpha = 0.6;
- spineDecor.rotation = Math.PI / 2;
- }
- // Add vintage paper texture with subtle aged spots
- for (var i = 0; i < 25; i++) {
- var ageSpot = self.attachAsset('coin', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 400 + Math.random() * 1248,
- y: 500 + Math.random() * 1732,
- scaleX: 0.3 + Math.random() * 0.8,
- scaleY: 0.3 + Math.random() * 0.8
- });
- ageSpot.alpha = 0.1 + Math.random() * 0.15;
- ageSpot.tint = 0x8B7355; // Brown aging spots
- }
- // Create illuminated manuscript-style title
- var titleContainer = new Container();
- titleContainer.x = 2048 / 2;
- titleContainer.y = 700;
- self.addChild(titleContainer);
- // Main title with ornate medieval styling
- var mainTitle = new Text2('WIZARD', {
- size: 200,
- fill: 0x8B0000,
- font: "monospace"
+ // Create ornate border frame
+ var borderTop = self.attachAsset('healthBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 400,
+ scaleX: 20,
+ scaleY: 0.3
});
- mainTitle.anchor.set(0.5, 0.5);
- mainTitle.y = -50;
- titleContainer.addChild(mainTitle);
- // Title shadow for depth
- var titleShadow = new Text2('WIZARD', {
- size: 200,
- fill: 0x000000,
+ borderTop.tint = 0xD4AF37;
+ borderTop.alpha = 0.7;
+ var borderBottom = self.attachAsset('healthBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2332,
+ scaleX: 20,
+ scaleY: 0.3
+ });
+ borderBottom.tint = 0xD4AF37;
+ borderBottom.alpha = 0.7;
+ var borderLeft = self.attachAsset('healthBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 400,
+ y: 2732 / 2,
+ scaleX: 0.3,
+ scaleY: 28
+ });
+ borderLeft.tint = 0xD4AF37;
+ borderLeft.alpha = 0.7;
+ var borderRight = self.attachAsset('healthBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 1648,
+ y: 2732 / 2,
+ scaleX: 0.3,
+ scaleY: 28
+ });
+ borderRight.tint = 0xD4AF37;
+ borderRight.alpha = 0.7;
+ // Create embossed title effect with gold lettering
+ var titleShadow = new Text2('WIZARD\nDEFENDER', {
+ size: 180,
+ fill: 0x1a0e0a,
font: "monospace"
});
titleShadow.anchor.set(0.5, 0.5);
- titleShadow.x = 5;
- titleShadow.y = -45;
- titleShadow.alpha = 0.3;
- titleContainer.addChildAt(titleShadow, 0);
- var subTitle = new Text2('DEFENDER', {
+ titleShadow.x = 2048 / 2 + 8;
+ titleShadow.y = 808;
+ self.addChild(titleShadow);
+ var titleText = new Text2('WIZARD\nDEFENDER', {
size: 180,
- fill: 0x8B0000,
+ fill: 0xD4AF37,
font: "monospace"
});
- subTitle.anchor.set(0.5, 0.5);
- subTitle.y = 120;
- titleContainer.addChild(subTitle);
- // Subtitle shadow
- var subTitleShadow = new Text2('DEFENDER', {
- size: 180,
- fill: 0x000000,
+ titleText.anchor.set(0.5, 0.5);
+ titleText.x = 2048 / 2;
+ titleText.y = 800;
+ self.addChild(titleText);
+ // Add subtle title animation
+ tween(titleText, {
+ scaleX: 1.02,
+ scaleY: 1.02
+ }, {
+ duration: 4000,
+ loop: true,
+ yoyo: true,
+ easing: tween.easeInOut
+ });
+ // Subtitle in elegant script
+ var subtitle = new Text2('A Tale of Magic & Defense', {
+ size: 70,
+ fill: 0xC9A961,
font: "monospace"
});
- subTitleShadow.anchor.set(0.5, 0.5);
- subTitleShadow.x = 5;
- subTitleShadow.y = 125;
- subTitleShadow.alpha = 0.3;
- titleContainer.addChildAt(subTitleShadow, 0);
- // Add decorative flourishes around title
- var leftFlourish = self.attachAsset('spell', {
+ subtitle.anchor.set(0.5, 0.5);
+ subtitle.x = 2048 / 2;
+ subtitle.y = 1050;
+ subtitle.alpha = 0.9;
+ self.addChild(subtitle);
+ // Add wizard emblem in center
+ var wizardEmblem = self.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5,
- x: 600,
- y: 700,
+ x: 2048 / 2,
+ y: 1400,
scaleX: 4,
- scaleY: 1.5
+ scaleY: 4
});
- leftFlourish.alpha = 0.5;
- leftFlourish.tint = 0xDAA520;
- var rightFlourish = self.attachAsset('spell', {
+ wizardEmblem.tint = 0xD4AF37;
+ wizardEmblem.alpha = 0.3;
+ // Add circular frame around wizard
+ var emblemFrame = self.attachAsset('pathSelector', {
anchorX: 0.5,
anchorY: 0.5,
- x: 1448,
- y: 700,
- scaleX: 4,
- scaleY: 1.5
+ x: 2048 / 2,
+ y: 1400,
+ scaleX: 5,
+ scaleY: 5
});
- rightFlourish.alpha = 0.5;
- rightFlourish.tint = 0xDAA520;
- rightFlourish.scaleX = -4; // Mirror the flourish
- // Animate title entrance with book opening effect
- titleContainer.scaleX = 0;
- titleContainer.scaleY = 0;
- tween(titleContainer, {
- scaleX: 1,
- scaleY: 1
+ emblemFrame.tint = 0xD4AF37;
+ emblemFrame.alpha = 0.2;
+ // Rotate emblem frame slowly
+ tween(emblemFrame, {
+ rotation: Math.PI * 2
}, {
- duration: 1200,
- delay: 500,
- easing: tween.elasticOut
+ duration: 20000,
+ loop: true,
+ easing: tween.linear
});
- // Add subtitle describing the tome
- var bookSubtitle = new Text2('~ A MAGICAL TOME OF DEFENSE ~', {
- size: 70,
- fill: 0x654321,
+ // Author text at bottom
+ var authorText = new Text2('By the Archmages of FRVR', {
+ size: 60,
+ fill: 0xC9A961,
font: "monospace"
});
- bookSubtitle.anchor.set(0.5, 0.5);
- bookSubtitle.x = 2048 / 2;
- bookSubtitle.y = 1000;
- bookSubtitle.alpha = 0;
- self.addChild(bookSubtitle);
- // Fade in book subtitle
- tween(bookSubtitle, {
- alpha: 1
- }, {
- duration: 1500,
- delay: 800,
- easing: tween.easeOut
- });
- // Create author attribution like a real book
- var authorText = new Text2('By the Ancient Order of Wizards', {
- size: 50,
- fill: 0x556B2F,
- font: "monospace"
- });
authorText.anchor.set(0.5, 0.5);
authorText.x = 2048 / 2;
- authorText.y = 1150;
- authorText.alpha = 0;
+ authorText.y = 1800;
+ authorText.alpha = 0.8;
self.addChild(authorText);
- tween(authorText, {
- alpha: 0.8
- }, {
- duration: 1500,
- delay: 1200,
- easing: tween.easeOut
- });
- // Add medieval instructions in book style
- var instructionsText = new Text2('~ Touch the Ancient Paths to Cast Spells ~\n~ Defend the Sacred Castle ~', {
- size: 60,
- fill: 0x2F4F4F,
- font: "monospace"
- });
- instructionsText.anchor.set(0.5, 0.5);
- instructionsText.x = 2048 / 2;
- instructionsText.y = 1350;
- instructionsText.alpha = 0;
- self.addChild(instructionsText);
- // Fade in instructions
- tween(instructionsText, {
- alpha: 1
- }, {
- duration: 1500,
- delay: 1000,
- easing: tween.easeOut
- });
- // Create ornate start button like a book clasp
- var buttonContainer = new Container();
- buttonContainer.x = 2048 / 2;
- buttonContainer.y = 1800;
- self.addChild(buttonContainer);
- // Button ornate background (book clasp design)
- var buttonFrame = buttonContainer.attachAsset('healthBarBg', {
+ // Start reading button styled as book clasp
+ var claspBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
- x: 0,
- y: 0,
- scaleX: 5,
- scaleY: 3
+ x: 2048 / 2,
+ y: 2100,
+ scaleX: 4,
+ scaleY: 1.5
});
- buttonFrame.tint = 0x8B4513; // Dark brown frame
- var buttonInner = buttonContainer.attachAsset('healthBar', {
+ claspBg.tint = 0x8B4513; // Saddle brown
+ var claspMetal = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
- x: 0,
- y: 0,
- scaleX: 4.5,
- scaleY: 2.5
+ x: 2048 / 2,
+ y: 2100,
+ scaleX: 2.5,
+ scaleY: 1.2
});
- buttonInner.tint = 0xDAA520; // Gold inner
- // Decorative wizard seal in center
- var wizardSeal = buttonContainer.attachAsset('wizard', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: -100,
- y: 0,
- scaleX: 2,
- scaleY: 2
- });
- wizardSeal.tint = 0x4B0082; // Dark purple wizard
- // Start text in medieval style
- var startButtonText = new Text2('OPEN TOME', {
+ claspMetal.tint = 0xD4AF37;
+ var startText = new Text2('OPEN BOOK', {
size: 80,
- fill: 0xF5DEB3,
+ fill: 0x1a0e0a,
font: "monospace"
});
- startButtonText.anchor.set(0.5, 0.5);
- startButtonText.x = 60;
- startButtonText.y = 0;
- buttonContainer.addChild(startButtonText);
- // Button entrance animation (book clasp opening)
- buttonContainer.scaleX = 0;
- buttonContainer.scaleY = 0;
- tween(buttonContainer, {
- scaleX: 1,
- scaleY: 1
+ startText.anchor.set(0.5, 0.5);
+ startText.x = 2048 / 2;
+ startText.y = 2100;
+ self.addChild(startText);
+ // Add hover effect for clasp
+ tween(claspMetal, {
+ scaleX: 2.7,
+ scaleY: 1.4
}, {
- duration: 800,
- delay: 1500,
- easing: tween.elasticOut
+ duration: 1500,
+ loop: true,
+ yoyo: true,
+ easing: tween.easeInOut
});
- // Add magical runes around the border like a medieval manuscript
- var runePositions = [{
- x: 300,
- y: 300
- }, {
- x: 1024,
- y: 250
- }, {
- x: 1748,
- y: 300
- }, {
- x: 1800,
- y: 1366
- }, {
- x: 1748,
- y: 2432
- }, {
- x: 1024,
- y: 2482
- }, {
- x: 300,
- y: 2432
- }, {
- x: 248,
- y: 1366
- }];
- for (var i = 0; i < runePositions.length; i++) {
- var rune = self.attachAsset('projectile', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: runePositions[i].x,
- y: runePositions[i].y,
- scaleX: 1.5,
- scaleY: 1.5
- });
- rune.alpha = 0.4;
- rune.tint = 0x8B0000; // Dark red runes
- rune.rotation = Math.PI / 4 * i; // Different rotation for each
- // Slow mystical rotation
- tween(rune, {
- rotation: rune.rotation + Math.PI * 2
- }, {
- duration: 15000 + i * 1000,
- loop: true,
- easing: tween.linear
- });
- }
- // Add medieval page decoration elements
- for (var i = 0; i < 6; i++) {
- var pageDecor = self.attachAsset('coin', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 500 + i * 200,
- y: 2200,
- scaleX: 1.2,
- scaleY: 1.8
- });
- pageDecor.alpha = 0.3;
- pageDecor.tint = 0x8B4513; // Brown decorative elements
- // Gentle bob animation
- tween(pageDecor, {
- y: pageDecor.y - 20,
- rotation: 0.1
- }, {
- duration: 4000 + i * 300,
- loop: true,
- yoyo: true,
- easing: tween.easeInOut
- });
- }
- // Button interaction with book opening effects
+ // Sparkles removed to clean up startup screen
+ // Page edge effect (worn edges)
+ var leftEdge = self.attachAsset('healthBarBg', {
+ anchorX: 0,
+ anchorY: 0.5,
+ x: 380,
+ y: 2732 / 2,
+ scaleX: 0.1,
+ scaleY: 30
+ });
+ leftEdge.tint = 0xF5DEB3; // Wheat color for pages
+ leftEdge.alpha = 0.3;
+ var rightEdge = self.attachAsset('healthBarBg', {
+ anchorX: 1,
+ anchorY: 0.5,
+ x: 1668,
+ y: 2732 / 2,
+ scaleX: 0.1,
+ scaleY: 30
+ });
+ rightEdge.tint = 0xF5DEB3;
+ rightEdge.alpha = 0.3;
+ // Button interaction
self.down = function (x, y, obj) {
- // Check if start button area was clicked
- if (x >= 724 && x <= 1324 && y >= 1650 && y <= 1950) {
- // Create page turning effect
- var pageFlip = self.attachAsset('pathSelector', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- scaleX: 32,
- scaleY: 42
- });
- pageFlip.alpha = 0.8;
- pageFlip.tint = 0xFFFFFF; // White page turning
- // Animate page turning
- tween(pageFlip, {
- scaleX: 0,
+ // Check if clasp/button area was clicked
+ if (x >= 824 && x <= 1224 && y >= 2000 && y <= 2200) {
+ // Book opening effect
+ tween(bookCover, {
+ scaleX: 0.1,
alpha: 0
}, {
- duration: 600,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- pageFlip.destroy();
- }
+ duration: 800,
+ easing: tween.easeIn
});
- // Button press animation
- tween(buttonContainer, {
- scaleX: 0.95,
- scaleY: 0.95
+ tween(self, {
+ rotation: 0.1
}, {
- duration: 150,
+ duration: 400,
yoyo: true,
onFinish: function onFinish() {
self.startGame();
}
});
}
};
- // No update method needed for static book design
+ // Update method for sparkles
self.update = function () {
- // Static book design - minimal animations only
+ // Sparkles are animated via tweens, no update needed
};
self.startGame = function () {
- // Create magical sparkles when opening the tome
- for (var i = 0; i < 20; i++) {
- var sparkle = self.attachAsset('projectile', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2 + (Math.random() - 0.5) * 400,
- y: 1800 + (Math.random() - 0.5) * 200,
- scaleX: 0.3,
- scaleY: 0.3
- });
- sparkle.alpha = 1;
- sparkle.tint = [0xFFD700, 0xFFFFFF, 0xDAA520][i % 3];
- var angle = Math.PI * 2 / 20 * i;
- var speed = 5 + Math.random() * 10;
- tween(sparkle, {
- x: sparkle.x + Math.cos(angle) * speed * 30,
- y: sparkle.y + Math.sin(angle) * speed * 30,
- scaleX: 0,
- scaleY: 0,
- alpha: 0,
- rotation: Math.PI * 2
- }, {
- duration: 1200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- sparkle.destroy();
- }
- });
- }
- // Fade out menu like closing a book
+ // Page turn effect
+ var pageTurn = self.attachAsset('healthBarBg', {
+ anchorX: 0,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2,
+ scaleX: 0,
+ scaleY: 32
+ });
+ pageTurn.tint = 0xF5DEB3;
+ tween(pageTurn, {
+ scaleX: 25,
+ x: 2048
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ pageTurn.destroy();
+ }
+ });
+ // Fade out menu
tween(self, {
- alpha: 0,
- scaleY: 0.1 // Collapse like closing book
+ alpha: 0
}, {
- duration: 800,
- easing: tween.easeInOut,
+ duration: 500,
+ delay: 200,
+ easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
self.alpha = 1;
- self.scaleY = 1;
}
});
gameStarted = true;
// Show all game elements with fade in
@@ -1341,9 +1198,9 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x87CEEB // Celeste (sky blue) background
+ backgroundColor: 0x800080 // Purple background
});
/****
* Game Code