User prompt
pero quiero que agregues efectos del sonido al saltar, al disparar, al atacar y cuando una música épica en el voz final y que agregues como música ambiental los distintos niveles y que se pueda configurar a partir de de condiciones ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Pero que las balas sean teledirigidas hacia los enemigos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pero las balas van como en diagonal, necesito que vayan recto.
User prompt
Quiero que le agregues a Warrior un arco pero que el sprite del arco no se vea sino que cuando uno presione el botón de donde tenga un arco o sea no sé si me hago entender que uno presione un símbolo de un arco al lado del símbolo de attack que cuando uno lo presione aparezca un arco y que tiene una flecha para uno poder atacar a los enemigos a distancia ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: checkCollisions is not defined' in or related to this line: 'checkCollisions(player, platforms);' Line Number: 2020
User prompt
Please fix the bug: 'ReferenceError: leftPressed is not defined' in or related to this line: 'if (leftPressed) {' Line Number: 2009
User prompt
Please fix the bug: 'ReferenceError: leftPressed is not defined' in or related to this line: 'if (leftPressed) {' Line Number: 2012
User prompt
Please fix the bug: 'ReferenceError: leftPressed is not defined' in or related to this line: 'if (leftPressed) {' Line Number: 2011
User prompt
Mira te voy a pedir varias cosas primero que agreguen más enemigos segundo que agregues varios mapas y que en la interfaz que hagas al juego quiero que le agregues como la opción de seleccionar el mapa que quieras el mundo por así decirlo que lo como dice que agregues varios mundos y cae le agregas una interfaz al juego y efectos de sonido y que la interfaz uno pueda configurar la música y los efectos ↪💡 Consider importing and using the following plugins: @upit/storage.v1, @upit/tween.v1
User prompt
Ubicarla porque no me da para atacar a los enemigos
User prompt
Ubica mejor la hit-box del ataque q hace Warrior
User prompt
Necesito que ubiques un poco mejor los controles. Están muy... Mueh... Necesito que los... Como dice... Que sean más cómodos al utilizarlos.
User prompt
Please fix the bug: 'ReferenceError: sword is not defined' in or related to this line: 'sword.rotation = 0.2;' Line Number: 181
User prompt
Quiero q en ves de utilizar una espada pegue a los enemigos para matarlos y que arriba de los enemigos haya una barra que diga la olla que le queda que uno tenga que matar a los enemigos dependiendo de qué tan fuerte sean y ubica la barra de estamina del personaje warrior un poco más arriba ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Necesito q ubiques la espada del "Warrior" un poco más a la derecha ubicarla en la mano del asset ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: warrior is not defined' in or related to this line: 'tween(warrior, {' Line Number: 432
User prompt
Pero as el asset de Warriors como un guerrero pero q tenga animaciones de correr saltar caminar pero detalladas ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
¿Sabes algo? Agregale al Stickman el asset que tú quieras, pero que tenga animaciones por favor, que tenga animaciones al caminar, al correr, al saltar, al atacarte y todo, y que la espada esté detallada, por favor. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pero q las animaciones sean para el asset "Stickman" ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hasme lo q te acabo de pedir hace un momento ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mira quiero q las piernas del personaje se muevan porque sino parece muy tieso ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pero quiero q mueva la espada no el personaje entero en concreto la espada ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Pero quiero q el personaje utilize la espada q tiene el asset "Stickman" incluida con el asset y q le des animaciones más detalladas ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Necesito q cambies al personaje por el asset q dice Stickman
User prompt
Sigue cambiando lo q te falta porfavor ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
selectedMap: 0,
musicVolume: 1,
soundVolume: 1,
highScore: 0
});
/****
* Classes
****/
var Arrow = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 240; // 4 seconds at 60fps
self.damage = 20;
self.update = function () {
// Homing behavior - track nearest enemy
var nearestEnemy = null;
var nearestDistance = Infinity;
// Find nearest enemy
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
// Adjust velocity towards nearest enemy if found
if (nearestEnemy && nearestDistance > 50) {
var dx = nearestEnemy.x - self.x;
var dy = nearestEnemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize direction vector
var dirX = dx / distance;
var dirY = dy / distance;
// Homing strength (how aggressively it turns)
var homingStrength = 0.3;
var arrowSpeed = 12;
// Blend current velocity with target direction using tween for smooth turning
self.velocityX += (dirX * arrowSpeed - self.velocityX) * homingStrength;
self.velocityY += (dirY * arrowSpeed - self.velocityY) * homingStrength;
// Maintain consistent speed
var currentSpeed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (currentSpeed > 0) {
self.velocityX = self.velocityX / currentSpeed * arrowSpeed;
self.velocityY = self.velocityY / currentSpeed * arrowSpeed;
}
}
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
// Rotate arrow to match trajectory
if (self.velocityX !== 0) {
graphics.rotation = Math.atan2(self.velocityY, self.velocityX);
}
// Remove if lifetime expired or off screen
if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y > 2800) {
self.destroy();
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 1.0
});
// Health bar
var healthBarBg = self.attachAsset('platform', {
width: 160,
height: 20,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -220,
tint: 0x000000
});
var healthBarFill = self.attachAsset('platform', {
width: 156,
height: 16,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -220,
tint: 0xFF0000
});
self.health = 150;
self.maxHealth = 150;
self.velocityX = 0;
self.velocityY = 0;
self.onGround = false;
self.speed = 3;
self.direction = 1;
self.attackCooldown = 0;
self.animationTick = 0;
self.phase = 1; // Boss has different phases
self.epicMusicTriggered = false;
self.update = function () {
// Apply gravity
if (!self.onGround) {
self.velocityY += 0.8;
}
// Boss AI - different behavior based on health
var distanceToPlayer = Math.abs(self.x - player.x);
var healthPercent = self.health / self.maxHealth;
if (healthPercent > 0.5) {
// Phase 1: Basic chase and attack
if (distanceToPlayer > 100) {
if (player.x > self.x) {
self.direction = 1;
self.velocityX = self.speed;
} else {
self.direction = -1;
self.velocityX = -self.speed;
}
} else {
self.velocityX = 0;
if (self.attackCooldown <= 0) {
self.groundSlam();
self.attackCooldown = 120;
}
}
} else {
// Phase 2: Faster, more aggressive - trigger epic music transition
if (!self.epicMusicTriggered) {
self.epicMusicTriggered = true;
// Play boss music with higher intensity for final phase
LK.playMusic('boss_music', {
fade: {
start: storage.musicVolume,
end: storage.musicVolume * 1.2,
duration: 500
}
});
}
self.speed = 4;
if (distanceToPlayer > 150) {
if (player.x > self.x) {
self.direction = 1;
self.velocityX = self.speed;
} else {
self.direction = -1;
self.velocityX = -self.speed;
}
} else {
self.velocityX = 0;
if (self.attackCooldown <= 0) {
self.multiAttack();
self.attackCooldown = 180;
}
}
}
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
self.onGround = false;
// Update cooldowns
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
self.animationTick++;
// Face direction
graphics.scaleX = self.direction > 0 ? 1 : -1;
// Breathing animation
var breathCycle = Math.sin(self.animationTick * 0.05);
graphics.scaleY = 1 + breathCycle * 0.05;
};
self.groundSlam = function () {
// Ground slam attack
tween(graphics, {
scaleY: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
tween(graphics, {
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(graphics, {
scaleY: 1
}, {
duration: 200
});
// Damage player if close
if (Math.abs(self.x - player.x) < 120) {
player.takeDamage(20);
player.velocityX += (player.x > self.x ? 1 : -1) * 15;
player.velocityY = -10;
}
}
});
}
});
LK.getSound('attack').play();
};
self.multiAttack = function () {
// Multiple projectiles in different directions
for (var i = 0; i < 5; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y - 100;
var angle = (i - 2) * 0.5; // Spread shots
bullet.velocityX = Math.cos(angle) * 8 * self.direction;
bullet.velocityY = Math.sin(angle) * 8 - 2;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('attack').play();
};
self.takeDamage = function (damage) {
self.health -= damage;
// Update health bar
var healthPercent = Math.max(0, self.health / self.maxHealth);
healthBarFill.width = 156 * healthPercent;
// Flash effect
tween(graphics, {
tint: 0xFFFFFF
}, {
duration: 150,
onFinish: function onFinish() {
tween(graphics, {
tint: 0x800080
}, {
duration: 150
});
}
});
LK.getSound('enemy_hit').play();
if (self.health <= 0) {
LK.getSound('enemy_death').play();
self.destroy();
return true;
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 180;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
// Remove if lifetime expired or off screen
if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y > 2800 || self.y < -100) {
self.destroy();
}
};
return self;
});
var FlyingEnemy = Container.expand(function () {
var self = Container.call(this);
// Create flying enemy body parts
var body = self.attachAsset('enemy_body', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
width: 40,
height: 40,
tint: 0x8B4513
});
var leftWing = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: 0,
width: 20,
height: 8,
tint: 0x654321
});
var rightWing = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: 0,
width: 20,
height: 8,
tint: 0x654321
});
// Health bar
var healthBarBg = self.attachAsset('platform', {
width: 60,
height: 8,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -35,
tint: 0x000000
});
var healthBarFill = self.attachAsset('platform', {
width: 56,
height: 6,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -35,
tint: 0x00FF00
});
self.health = 30;
self.maxHealth = 30;
self.speed = 2;
self.direction = 1;
self.attackRange = 120;
self.attackCooldown = 0;
self.animationTick = 0;
self.floatOffset = 0;
self.shootCooldown = 0;
self.update = function () {
// Floating movement
self.floatOffset += 0.1;
self.y += Math.sin(self.floatOffset) * 0.5;
// Wing flapping animation
var flapSpeed = 0.3;
var flapCycle = Math.sin(self.animationTick * flapSpeed);
leftWing.rotation = flapCycle * 0.8;
rightWing.rotation = -flapCycle * 0.8;
leftWing.y = Math.sin(self.animationTick * flapSpeed * 2) * 2;
rightWing.y = Math.sin(self.animationTick * flapSpeed * 2) * 2;
// AI behavior - chase player and shoot
var distanceToPlayer = Math.abs(self.x - player.x);
var verticalDistance = Math.abs(self.y - player.y);
if (distanceToPlayer < 300 && verticalDistance < 150) {
// Chase player
if (player.x > self.x) {
self.direction = 1;
self.x += self.speed;
} else {
self.direction = -1;
self.x -= self.speed;
}
// Shoot projectiles at player
if (self.shootCooldown <= 0 && distanceToPlayer < 200) {
self.shootAtPlayer();
self.shootCooldown = 90; // 1.5 seconds
}
} else {
// Patrol movement
self.x += self.speed * self.direction;
if (self.x < 50 || self.x > 1998) {
self.direction *= -1;
}
}
// Update cooldowns
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
self.animationTick++;
// Face direction
if (self.direction > 0) {
body.scaleX = 1;
leftWing.scaleX = 1;
rightWing.scaleX = 1;
} else {
body.scaleX = -1;
leftWing.scaleX = -1;
rightWing.scaleX = -1;
}
};
self.shootAtPlayer = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction to player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
bullet.velocityX = dx / distance * 6;
bullet.velocityY = dy / distance * 6;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('attack').play();
};
self.takeDamage = function (damage) {
self.health -= damage;
// Update health bar
var healthPercent = Math.max(0, self.health / self.maxHealth);
healthBarFill.width = 56 * healthPercent;
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00FF00;
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xFFFF00;
} else {
healthBarFill.tint = 0xFF0000;
}
// Flash effect
tween(body, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(body, {
tint: 0x8B4513
}, {
duration: 100
});
}
});
LK.getSound('enemy_hit').play();
if (self.health <= 0) {
LK.getSound('enemy_death').play();
self.destroy();
return true;
}
return false;
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
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--;
// Remove if lifetime expired or off screen
if (self.lifetime <= 0 || self.x < -50 || self.x > 2098 || self.y > 2800) {
self.destroy();
}
};
return self;
});
var Stickman = Container.expand(function () {
var self = Container.call(this);
// Create detailed warrior with body parts for enhanced animations
var warriorBody = self.attachAsset('warrior', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0
});
// Create separate limbs for detailed animation
var leftArm = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: -15,
y: -80,
tint: 0x8B4513
});
var rightArm = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: 15,
y: -80,
tint: 0x8B4513
});
var leftLeg = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: -8,
y: -40,
height: 40,
tint: 0x654321
});
var rightLeg = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: 8,
y: -40,
height: 40,
tint: 0x654321
});
// No sword - warrior fights with hands
// Movement properties
self.velocityX = 0;
self.velocityY = 0;
self.onGround = false;
self.speed = 8;
self.jumpPower = -18;
self.health = 100;
self.maxHealth = 100;
self.facingRight = true;
// Combat properties
self.canAttack = true;
self.attackCooldown = 0;
self.lastAttackTime = 0;
// Animation properties
self.animationTick = 0;
self.isAttacking = false;
self.isJumping = false;
self.wasOnGround = true;
self.update = function () {
// Apply gravity
if (!self.onGround) {
self.velocityY += 0.8;
}
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction
self.velocityX *= 0.85;
// Reset ground detection
self.onGround = false;
// Reset double jump when touching ground later in collision detection
// Update attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Animation updates
self.animationTick++;
// Check if jumping state changed
if (!self.onGround && self.wasOnGround) {
self.isJumping = true;
}
if (self.onGround && !self.wasOnGround) {
self.isJumping = false;
}
self.wasOnGround = self.onGround;
// Handle enhanced animations with detailed warrior body parts and sword movements
if (self.isAttacking) {
// Attack animation is handled in attack method - keep sword position
} else if (self.isJumping || !self.onGround) {
// Enhanced jump animation with dynamic rotation and detailed limb movement
var jumpPhase = self.velocityY < 0 ? 0 : 1; // 0 for going up, 1 for falling
if (jumpPhase === 0) {
// Going up - dynamic backward tilt based on jump velocity
var tiltAmount = Math.min(Math.abs(self.velocityY) * 0.02, 0.4);
warriorBody.rotation = -tiltAmount;
// Slight scale animation for jump power
warriorBody.scaleY = 1.1 - Math.abs(self.velocityY) * 0.005;
// Detailed leg positioning during upward jump - legs bent for power
leftLeg.rotation = -0.3;
rightLeg.rotation = -0.2;
leftLeg.y = -35;
rightLeg.y = -35;
// Arm positioning during jump - spread for balance
leftArm.rotation = -0.4;
rightArm.rotation = 0.2;
// No sword - hands positioned during jump for balance
} else {
// Falling down - forward tilt increases with fall speed
var fallTilt = Math.min(self.velocityY * 0.01, 0.3);
warriorBody.rotation = fallTilt;
// Slight stretch when falling fast
warriorBody.scaleY = 1 + self.velocityY * 0.002;
// Detailed leg positioning during fall - preparing for landing
leftLeg.rotation = 0.2;
rightLeg.rotation = 0.1;
leftLeg.y = -38;
rightLeg.y = -38;
// Arm positioning for landing preparation
leftArm.rotation = -0.2;
rightArm.rotation = 0.3;
// No sword - hands positioned for landing
// Add landing preparation animation when close to ground
if (self.velocityY > 8) {
tween(warriorBody, {
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
tween(leftLeg, {
rotation: 0.4,
y: -42
}, {
duration: 100,
easing: tween.easeOut
});
tween(rightLeg, {
rotation: 0.3,
y: -42
}, {
duration: 100,
easing: tween.easeOut
});
}
}
} else if (Math.abs(self.velocityX) > 0.1) {
// Enhanced walking/running animation with detailed warrior body parts and realistic limb movement
var walkSpeed = Math.abs(self.velocityX) > 4 ? 0.4 : 0.3; // Faster animation for running
var walkCycle = Math.sin(self.animationTick * walkSpeed);
var walkCycleDouble = Math.sin(self.animationTick * walkSpeed * 2);
var walkCycleOffset = Math.sin(self.animationTick * walkSpeed + Math.PI);
// Dynamic rotation based on movement speed
var speedFactor = Math.min(Math.abs(self.velocityX) / self.speed, 1);
var isRunning = Math.abs(self.velocityX) > 4;
warriorBody.rotation = walkCycle * (isRunning ? 0.12 : 0.08) * speedFactor;
// Vertical bob with speed-based intensity - more pronounced when running
warriorBody.y = Math.abs(walkCycleDouble) * (isRunning ? 6 : 4) * speedFactor;
// Subtle scale animation for dynamic feel
warriorBody.scaleY = 1 - Math.abs(walkCycleDouble) * (isRunning ? 0.03 : 0.02) * speedFactor;
// Slight horizontal sway
warriorBody.x = walkCycle * (isRunning ? 3 : 2) * speedFactor;
// Detailed leg animation - alternating steps with realistic movement
var leftLegCycle = Math.sin(self.animationTick * walkSpeed);
var rightLegCycle = Math.sin(self.animationTick * walkSpeed + Math.PI);
// Left leg movement
leftLeg.rotation = leftLegCycle * (isRunning ? 0.6 : 0.4);
leftLeg.y = -40 + Math.abs(leftLegCycle) * (isRunning ? 8 : 5);
// Right leg movement (opposite phase)
rightLeg.rotation = rightLegCycle * (isRunning ? 0.6 : 0.4);
rightLeg.y = -40 + Math.abs(rightLegCycle) * (isRunning ? 8 : 5);
// Detailed arm animation - natural swinging motion opposite to legs
leftArm.rotation = rightLegCycle * (isRunning ? 0.5 : 0.3);
leftArm.y = -80 + Math.abs(rightLegCycle) * (isRunning ? 4 : 2);
rightArm.rotation = leftLegCycle * (isRunning ? 0.3 : 0.2); // Right arm holds sword, less movement
rightArm.y = -80 + Math.abs(leftLegCycle) * (isRunning ? 3 : 1);
// Both arms swing naturally during movement
// Add realistic stride animation using tween for smoother transitions
if (Math.floor(self.animationTick * walkSpeed) !== Math.floor((self.animationTick - 1) * walkSpeed)) {
// Trigger on each step cycle for enhanced leg animation
var stepDirection = leftLegCycle > 0 ? 1 : -1;
tween(warriorBody, {
scaleY: isRunning ? 0.96 : 0.98
}, {
duration: isRunning ? 80 : 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(warriorBody, {
scaleY: isRunning ? 1.04 : 1.02
}, {
duration: isRunning ? 80 : 100,
easing: tween.easeIn
});
}
});
}
// Add slight lean forward when walking/running
var leanDirection = self.facingRight ? 1 : -1;
warriorBody.rotation += leanDirection * speedFactor * (isRunning ? 0.08 : 0.05);
} else {
// Enhanced idle animation with breathing effect and detailed body part movement
var breathCycle = Math.sin(self.animationTick * 0.05);
var idleCycle = Math.sin(self.animationTick * 0.03);
var weightShiftCycle = Math.sin(self.animationTick * 0.02);
warriorBody.rotation = breathCycle * 0.01;
warriorBody.y = breathCycle * 1;
warriorBody.scaleY = 1 + breathCycle * 0.01;
warriorBody.x = 0;
// Detailed idle leg positioning with subtle weight shifting
leftLeg.rotation = weightShiftCycle * 0.08;
rightLeg.rotation = -weightShiftCycle * 0.06;
leftLeg.y = -40 + Math.abs(idleCycle) * 1;
rightLeg.y = -40 + Math.abs(weightShiftCycle) * 1;
// Detailed idle arm positioning with breathing
leftArm.rotation = breathCycle * 0.03;
leftArm.y = -80 + breathCycle * 0.5;
rightArm.rotation = breathCycle * 0.02; // Right arm holds sword
rightArm.y = -80 + breathCycle * 0.3;
// Arms in natural idle position with breathing
// Add periodic subtle repositioning animation
if (self.animationTick % 180 === 0) {
// Every 3 seconds - subtle weight shift
var shiftDirection = Math.random() > 0.5 ? 1 : -1;
tween(leftLeg, {
rotation: shiftDirection * 0.1
}, {
duration: 300,
easing: tween.easeInOut
});
tween(rightLeg, {
rotation: -shiftDirection * 0.08
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(leftLeg, {
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
tween(rightLeg, {
rotation: 0
}, {
duration: 500,
easing: tween.easeOut
});
}
});
}
}
// Face direction with smooth transition for all body parts
if (self.facingRight) {
warriorBody.scaleX = 1;
leftArm.scaleX = 1;
rightArm.scaleX = 1;
leftLeg.scaleX = 1;
rightLeg.scaleX = 1;
} else {
warriorBody.scaleX = -1;
leftArm.scaleX = -1;
rightArm.scaleX = -1;
leftLeg.scaleX = -1;
rightLeg.scaleX = -1;
}
// Keep player in bounds
if (self.x < 30) self.x = 30;
if (self.x > 2018) self.x = 2018;
// Reset skew if character is not moving or attacking
if (Math.abs(self.velocityX) < 0.1 && !self.isAttacking && !self.isJumping) {
// Smoothly reset skew values
if (Math.abs(warriorBody.skewX) > 0.001) {
warriorBody.skewX *= 0.9;
}
if (Math.abs(warriorBody.skewY) > 0.001) {
warriorBody.skewY *= 0.9;
}
}
};
self.moveLeft = function () {
self.velocityX = -self.speed;
if (self.facingRight) {
// Add quick turn animation when changing direction
self.facingRight = false;
tween(warriorBody, {
scaleX: -1.2,
skewX: 0.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(warriorBody, {
scaleX: -1,
skewX: 0
}, {
duration: 100
});
}
});
// No sword position changes needed
} else {
self.facingRight = false;
}
// Add quick leg push animation for movement start
tween(warriorBody, {
skewY: -0.05
}, {
duration: 50,
onFinish: function onFinish() {
tween(warriorBody, {
skewY: 0
}, {
duration: 100
});
}
});
};
self.moveRight = function () {
self.velocityX = self.speed;
if (!self.facingRight) {
// Add quick turn animation when changing direction
self.facingRight = true;
tween(warriorBody, {
scaleX: 1.2,
skewX: -0.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(warriorBody, {
scaleX: 1,
skewX: 0
}, {
duration: 100
});
}
});
// No sword position changes needed
} else {
self.facingRight = true;
}
// Add quick leg push animation for movement start
tween(warriorBody, {
skewY: 0.05
}, {
duration: 50,
onFinish: function onFinish() {
tween(warriorBody, {
skewY: 0
}, {
duration: 100
});
}
});
};
self.jump = function () {
console.log("Jump called! onGround:", self.onGround, "velocityY:", self.velocityY);
if (self.onGround || Math.abs(self.velocityY) < 2) {
// First jump with squash animation
self.velocityY = self.jumpPower;
self.onGround = false;
LK.getSound('jump').play();
// Enhanced squash and stretch animation for jump with sword movement
tween(warriorBody, {
scaleY: 0.7,
scaleX: self.facingRight ? 1.3 : -1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(warriorBody, {
scaleY: 1.2,
scaleX: self.facingRight ? 0.9 : -0.9
}, {
duration: 150,
onFinish: function onFinish() {
tween(warriorBody, {
scaleY: 1,
scaleX: self.facingRight ? 1 : -1
}, {
duration: 200
});
}
});
}
});
// Arms raised during jump for balance
tween(leftArm, {
y: -85,
rotation: -0.4
}, {
duration: 100,
onFinish: function onFinish() {
tween(leftArm, {
y: -80,
rotation: 0
}, {
duration: 300
});
}
});
console.log("Jump executed! New velocityY:", self.velocityY);
} else if (self.canDoubleJump && !self.hasUsedDoubleJump) {
// Double jump with spin animation
self.velocityY = self.jumpPower * 0.8;
self.hasUsedDoubleJump = true;
self.canDoubleJump = false;
LK.getSound('jump').play();
// Enhanced spin animation for double jump with sword trail effect
var startRotation = warriorBody.rotation;
tween(warriorBody, {
rotation: startRotation + (self.facingRight ? Math.PI * 2 : -Math.PI * 2)
}, {
duration: 400,
onFinish: function onFinish() {
warriorBody.rotation = 0;
}
});
// Arms spinning during double jump
tween(leftArm, {
rotation: leftArm.rotation + (self.facingRight ? Math.PI * 2 : -Math.PI * 2)
}, {
duration: 400,
onFinish: function onFinish() {
leftArm.rotation = 0;
}
});
tween(rightArm, {
rotation: rightArm.rotation + (self.facingRight ? Math.PI * 2 : -Math.PI * 2)
}, {
duration: 400,
onFinish: function onFinish() {
rightArm.rotation = 0;
}
});
console.log("Double jump executed!");
} else {
console.log("Cannot jump - not on ground and no double jump available");
}
};
self.attack = function () {
if (self.attackCooldown <= 0) {
self.attackCooldown = 30;
self.isAttacking = true;
LK.getSound('attack').play();
// Hand-to-hand combat - punch animation
var originalWarriorRotation = warriorBody.rotation;
// Wind up phase - pull right arm back for powerful punch
tween(rightArm, {
rotation: -0.8,
x: self.facingRight ? 5 : -5,
y: -75
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Powerful punch forward
tween(rightArm, {
rotation: 0.6,
x: self.facingRight ? 25 : -25,
y: -80
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
// Recovery - return arm to normal position
tween(rightArm, {
rotation: 0,
x: self.facingRight ? 15 : -15,
y: -80
}, {
duration: 250,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isAttacking = false;
}
});
}
});
// Warrior body movement during punch
tween(warriorBody, {
rotation: originalWarriorRotation + (self.facingRight ? 0.2 : -0.2),
skewY: self.facingRight ? 0.1 : -0.1
}, {
duration: 150,
onFinish: function onFinish() {
tween(warriorBody, {
rotation: originalWarriorRotation - (self.facingRight ? 0.1 : -0.1),
skewY: self.facingRight ? -0.05 : 0.05
}, {
duration: 200,
onFinish: function onFinish() {
tween(warriorBody, {
rotation: originalWarriorRotation,
skewY: 0
}, {
duration: 250
});
}
});
}
});
}
});
// Add warrior body lean and step forward during punch
LK.setTimeout(function () {
// Dynamic body movement during attack
tween(warriorBody, {
scaleX: self.facingRight ? 1.1 : -1.1,
x: self.facingRight ? 8 : -8
}, {
duration: 100,
onFinish: function onFinish() {
tween(warriorBody, {
scaleX: self.facingRight ? 1 : -1,
x: 0
}, {
duration: 150
});
}
});
}, 150);
// Check for enemy hits during forward punch
LK.setTimeout(function () {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Calculate punch position based on warrior's facing direction and arm extension
var punchReach = 80; // Increased reach for better hit detection
var punchX = self.x + (self.facingRight ? punchReach : -punchReach);
var punchY = self.y - 60; // Adjusted height to match enemy center
// Calculate distance from punch position to enemy
var distanceToEnemy = Math.abs(punchX - enemy.x);
var verticalDistance = Math.abs(punchY - enemy.y);
// Improved hit-box - larger rectangular area in front of warrior
var hitBoxWidth = 70; // Increased width of punch hit area
var hitBoxHeight = 80; // Increased height of punch hit area
if (distanceToEnemy < hitBoxWidth && verticalDistance < hitBoxHeight) {
// Additional check: enemy must be in front of warrior
var enemyInFront = self.facingRight ? enemy.x > self.x : enemy.x < self.x;
if (enemyInFront) {
if (enemy.takeDamage(25)) {
// Enemy damaged - check if destroyed
enemies.splice(i, 1);
LK.setScore(LK.getScore() + 100);
scoreText.setText('Score: ' + LK.getScore());
}
// Enhanced knockback effect based on punch direction
var knockbackDirection = self.facingRight ? 1 : -1;
enemy.velocityX += knockbackDirection * 10;
enemy.velocityY = -4; // Slightly stronger upward knockback
}
}
}
}, 120);
}
};
self.shootArrow = function () {
if (self.attackCooldown <= 0) {
self.attackCooldown = 20; // Shorter cooldown for ranged attacks
LK.getSound('bow_shoot').play();
// Create arrow
var arrow = new Arrow();
arrow.x = self.x + (self.facingRight ? 40 : -40);
arrow.y = self.y - 80;
// Set arrow velocity based on facing direction
var arrowSpeed = 12;
arrow.velocityX = self.facingRight ? arrowSpeed : -arrowSpeed;
arrow.velocityY = 0; // Straight horizontal trajectory
// Add arrow to game
arrows.push(arrow);
game.addChild(arrow);
// Bow shooting animation - pull left arm back then forward
var originalLeftArmX = leftArm.x;
var originalLeftArmY = leftArm.y;
var originalLeftArmRotation = leftArm.rotation;
// Pull back animation (drawing the bow)
tween(leftArm, {
rotation: -0.5,
x: self.facingRight ? -20 : 20,
y: -85
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Release animation (shooting the arrow)
tween(leftArm, {
rotation: 0.3,
x: self.facingRight ? -10 : 10,
y: -75
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
// Return to normal position
tween(leftArm, {
rotation: originalLeftArmRotation,
x: originalLeftArmX,
y: originalLeftArmY
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
}
});
// Slight body lean during bow shot
var originalWarriorRotation = warriorBody.rotation;
tween(warriorBody, {
rotation: originalWarriorRotation + (self.facingRight ? -0.1 : 0.1),
x: self.facingRight ? -5 : 5
}, {
duration: 100,
onFinish: function onFinish() {
tween(warriorBody, {
rotation: originalWarriorRotation,
x: 0
}, {
duration: 200
});
}
});
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.getSound('hit').play();
// Enhanced damage flash effect on warrior and sword
tween(warriorBody, {
tint: 0xFF0066
}, {
duration: 150,
onFinish: function onFinish() {
tween(warriorBody, {
tint: 0xFFFFFF
}, {
duration: 150
});
}
});
// Flash arms as well
tween(leftArm, {
tint: 0xFF0066
}, {
duration: 150,
onFinish: function onFinish() {
tween(leftArm, {
tint: 0x8B4513
}, {
duration: 150
});
}
});
tween(rightArm, {
tint: 0xFF0066
}, {
duration: 150,
onFinish: function onFinish() {
tween(rightArm, {
tint: 0x8B4513
}, {
duration: 150
});
}
});
if (self.health <= 0) {
LK.showGameOver();
}
};
return self;
});
var StickmanEnemy = Container.expand(function () {
var self = Container.call(this);
// Create stickman body parts
var head = self.attachAsset('enemy_head', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -65
});
var body = self.attachAsset('enemy_body', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: -50
});
var leftArm = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: -10,
y: -40
});
var rightArm = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: 10,
y: -40
});
var leftLeg = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: -5,
y: -20
});
var rightLeg = self.attachAsset('enemy_limb', {
anchorX: 0.5,
anchorY: 0,
x: 5,
y: -20
});
var sword = self.attachAsset('enemy_sword', {
anchorX: 0.5,
anchorY: 1,
x: 15,
y: -30
});
self.velocityX = 0;
self.velocityY = 0;
self.health = 50;
self.maxHealth = 50;
// Create health bar background
var healthBarBg = self.attachAsset('platform', {
width: 60,
height: 8,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -90,
tint: 0x000000
});
// Create health bar fill
var healthBarFill = self.attachAsset('platform', {
width: 56,
height: 6,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -90,
tint: 0x00FF00
});
self.speed = 1.5;
self.direction = 1;
self.onGround = false;
self.attackRange = 80;
self.attackCooldown = 0;
self.animationTick = 0;
self.isAttacking = false;
self.lastPlayerDistance = 999;
self.update = function () {
// Apply gravity
if (!self.onGround) {
self.velocityY += 0.8;
}
// AI behavior - chase player if close enough
var distanceToPlayer = Math.abs(self.x - player.x);
var verticalDistance = Math.abs(self.y - player.y);
if (distanceToPlayer < 200 && verticalDistance < 100) {
// Chase player
if (player.x > self.x) {
self.direction = 1;
self.velocityX = self.speed;
} else {
self.direction = -1;
self.velocityX = -self.speed;
}
// Attack if in range
if (distanceToPlayer < self.attackRange && self.attackCooldown <= 0) {
self.attackPlayer();
}
} else {
// Simple patrol movement
self.velocityX = self.speed * self.direction;
}
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Reset ground detection
self.onGround = false;
// Reverse direction at edges
if (self.x < 50 || self.x > 1998) {
self.direction *= -1;
}
// Update attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Animation
self.animationTick++;
if (!self.isAttacking) {
// Walking animation with more realistic movement
var walkSpeed = Math.abs(self.velocityX) > 0.1 ? 0.25 : 0.1;
var walkCycle = Math.sin(self.animationTick * walkSpeed);
var walkCycleOffset = Math.sin(self.animationTick * walkSpeed + Math.PI);
// Leg animation - alternate walking
leftLeg.rotation = walkCycle * 0.4;
rightLeg.rotation = walkCycleOffset * 0.4;
// Arm animation - opposite to legs (natural walking)
leftArm.rotation = walkCycleOffset * 0.3;
rightArm.rotation = walkCycle * 0.3;
// Body bob animation when walking
if (Math.abs(self.velocityX) > 0.1) {
body.y = -50 + Math.abs(Math.sin(self.animationTick * walkSpeed * 2)) * 2;
head.y = -65 + Math.abs(Math.sin(self.animationTick * walkSpeed * 2)) * 2;
} else {
// Return to normal position when not walking
body.y = -50;
head.y = -65;
}
}
// Face direction
if (self.direction > 0) {
head.scaleX = 1;
body.scaleX = 1;
leftArm.scaleX = 1;
rightArm.scaleX = 1;
leftLeg.scaleX = 1;
rightLeg.scaleX = 1;
sword.scaleX = 1;
sword.x = 15;
} else {
head.scaleX = -1;
body.scaleX = -1;
leftArm.scaleX = -1;
rightArm.scaleX = -1;
leftLeg.scaleX = -1;
rightLeg.scaleX = -1;
sword.scaleX = -1;
sword.x = -15;
}
self.lastPlayerDistance = distanceToPlayer;
};
self.attackPlayer = function () {
if (self.attackCooldown <= 0) {
self.attackCooldown = 120; // 2 seconds at 60fps
self.isAttacking = true;
// Sword attack animation - swing from back to front
tween(sword, {
rotation: -1.8
}, {
duration: 150,
onFinish: function onFinish() {
// Swing forward
tween(sword, {
rotation: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
// Return to normal position
tween(sword, {
rotation: 0
}, {
duration: 250,
onFinish: function onFinish() {
self.isAttacking = false;
}
});
}
});
// Check if player is hit during forward swing (after 150ms delay)
LK.setTimeout(function () {
var distanceToPlayer = Math.abs(self.x - player.x);
if (distanceToPlayer < self.attackRange) {
player.takeDamage(10);
// Knockback effect
var knockbackDirection = player.x > self.x ? 1 : -1;
player.velocityX += knockbackDirection * 8;
}
}, 150);
}
});
}
};
self.takeDamage = function (damage) {
self.health -= damage;
// Update health bar
var healthPercent = Math.max(0, self.health / self.maxHealth);
healthBarFill.width = 56 * healthPercent;
// Change health bar color based on health
if (healthPercent > 0.6) {
healthBarFill.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
healthBarFill.tint = 0xFFFF00; // Yellow
} else {
healthBarFill.tint = 0xFF0000; // Red
}
// Damage flash effect on all body parts
var bodyParts = [head, body, leftArm, rightArm, leftLeg, rightLeg];
for (var i = 0; i < bodyParts.length; i++) {
var part = bodyParts[i];
tween(part, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
tween(part, {
tint: 0xFF0000
}, {
duration: 100
});
}
});
}
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122 // Dark digital blue background
});
/****
* Game Code
****/
// Game state management
var gameState = 'menu'; // 'menu', 'mapSelect', 'settings', 'playing'
var currentMap = 0;
var enemyBullets = [];
// Input state variables
var leftPressed = false;
var rightPressed = false;
var currentTouchId = null;
// Map definitions
var mapConfigs = [{
name: "Forest Plains",
backgroundColor: 0x228B22,
musicTrack: 'forest_music',
platforms: [{
x: 300,
y: 2500
}, {
x: 600,
y: 2300
}, {
x: 1000,
y: 2400
}, {
x: 1400,
y: 2200
}, {
x: 1700,
y: 2500
}],
enemies: [{
type: 'stickman',
x: 700,
y: 2250
}, {
type: 'stickman',
x: 1200,
y: 2350
}, {
type: 'stickman',
x: 1500,
y: 2150
}]
}, {
name: "Sky Temple",
backgroundColor: 0x4169E1,
musicTrack: 'sky_music',
platforms: [{
x: 200,
y: 2400
}, {
x: 500,
y: 2200
}, {
x: 800,
y: 2000
}, {
x: 1200,
y: 1800
}, {
x: 1600,
y: 2000
}, {
x: 1900,
y: 2200
}],
enemies: [{
type: 'flying',
x: 400,
y: 2100
}, {
type: 'flying',
x: 1000,
y: 1700
}, {
type: 'stickman',
x: 800,
y: 1950
}, {
type: 'flying',
x: 1400,
y: 1900
}]
}, {
name: "Boss Arena",
backgroundColor: 0x8B0000,
musicTrack: 'boss_music',
platforms: [{
x: 500,
y: 2400
}, {
x: 1000,
y: 2500
}, {
x: 1500,
y: 2400
}],
enemies: [{
type: 'boss',
x: 1024,
y: 2450
}, {
type: 'stickman',
x: 600,
y: 2350
}, {
type: 'stickman',
x: 1400,
y: 2350
}]
}];
// Game arrays
var platforms = [];
var enemies = [];
var projectiles = [];
var arrows = [];
// UI Elements
var menuContainer, mapSelectContainer, settingsContainer;
// Game objects (will be created when starting game)
var ground, player, staminaBarBackground, staminaBar;
function createMenu() {
menuContainer = new Container();
game.addChild(menuContainer);
// Title
var title = new Text2('STICKMAN WARRIOR', {
size: 80,
fill: 0xFFFFFF
});
title.anchor.set(0.5, 0.5);
title.x = 1024;
title.y = 400;
menuContainer.addChild(title);
// Play button
var playButton = LK.getAsset('platform', {
width: 300,
height: 80,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x4444FF
});
playButton.x = 1024;
playButton.y = 800;
playButton.interactive = true;
playButton.buttonMode = true;
menuContainer.addChild(playButton);
var playText = new Text2('PLAY', {
size: 40,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playText.x = playButton.x;
playText.y = playButton.y;
menuContainer.addChild(playText);
playButton.down = function () {
LK.getSound('button_click').play();
gameState = 'mapSelect';
menuContainer.visible = false;
createMapSelect();
};
// Settings button
var settingsButton = LK.getAsset('platform', {
width: 300,
height: 80,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x44FF44
});
settingsButton.x = 1024;
settingsButton.y = 920;
settingsButton.interactive = true;
settingsButton.buttonMode = true;
menuContainer.addChild(settingsButton);
var settingsText = new Text2('SETTINGS', {
size: 40,
fill: 0xFFFFFF
});
settingsText.anchor.set(0.5, 0.5);
settingsText.x = settingsButton.x;
settingsText.y = settingsButton.y;
menuContainer.addChild(settingsText);
settingsButton.down = function () {
LK.getSound('button_click').play();
gameState = 'settings';
menuContainer.visible = false;
createSettings();
};
// High score display
var highScoreText = new Text2('High Score: ' + storage.highScore, {
size: 35,
fill: 0xFFD700
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 1024;
highScoreText.y = 1100;
menuContainer.addChild(highScoreText);
}
function createMapSelect() {
mapSelectContainer = new Container();
game.addChild(mapSelectContainer);
// Title
var title = new Text2('SELECT MAP', {
size: 60,
fill: 0xFFFFFF
});
title.anchor.set(0.5, 0.5);
title.x = 1024;
title.y = 300;
mapSelectContainer.addChild(title);
// Map buttons
for (var i = 0; i < mapConfigs.length; i++) {
var mapButton = LK.getAsset('platform', {
width: 250,
height: 150,
anchorX: 0.5,
anchorY: 0.5,
tint: mapConfigs[i].backgroundColor
});
mapButton.x = 400 + i * 300;
mapButton.y = 700;
mapButton.interactive = true;
mapButton.buttonMode = true;
mapButton.mapIndex = i;
mapSelectContainer.addChild(mapButton);
var mapText = new Text2(mapConfigs[i].name, {
size: 30,
fill: 0xFFFFFF
});
mapText.anchor.set(0.5, 0.5);
mapText.x = mapButton.x;
mapText.y = mapButton.y;
mapSelectContainer.addChild(mapText);
mapButton.down = function () {
LK.getSound('button_click').play();
currentMap = this.mapIndex;
storage.selectedMap = currentMap;
startGame();
};
}
// Back button
var backButton = LK.getAsset('platform', {
width: 200,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
backButton.x = 1024;
backButton.y = 1000;
backButton.interactive = true;
backButton.buttonMode = true;
mapSelectContainer.addChild(backButton);
var backText = new Text2('BACK', {
size: 30,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = backButton.x;
backText.y = backButton.y;
mapSelectContainer.addChild(backText);
backButton.down = function () {
LK.getSound('button_click').play();
gameState = 'menu';
mapSelectContainer.visible = false;
menuContainer.visible = true;
};
}
function createSettings() {
settingsContainer = new Container();
game.addChild(settingsContainer);
// Title
var title = new Text2('SETTINGS', {
size: 60,
fill: 0xFFFFFF
});
title.anchor.set(0.5, 0.5);
title.x = 1024;
title.y = 300;
settingsContainer.addChild(title);
// Music volume
var musicLabel = new Text2('Music Volume: ' + Math.round(storage.musicVolume * 100) + '%', {
size: 40,
fill: 0xFFFFFF
});
musicLabel.anchor.set(0.5, 0.5);
musicLabel.x = 1024;
musicLabel.y = 500;
settingsContainer.addChild(musicLabel);
var musicDown = LK.getAsset('platform', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
musicDown.x = 700;
musicDown.y = 550;
musicDown.interactive = true;
musicDown.buttonMode = true;
settingsContainer.addChild(musicDown);
var musicDownText = new Text2('-', {
size: 40,
fill: 0xFFFFFF
});
musicDownText.anchor.set(0.5, 0.5);
musicDownText.x = musicDown.x;
musicDownText.y = musicDown.y;
settingsContainer.addChild(musicDownText);
var musicUp = LK.getAsset('platform', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x44FF44
});
musicUp.x = 1348;
musicUp.y = 550;
musicUp.interactive = true;
musicUp.buttonMode = true;
settingsContainer.addChild(musicUp);
var musicUpText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
musicUpText.anchor.set(0.5, 0.5);
musicUpText.x = musicUp.x;
musicUpText.y = musicUp.y;
settingsContainer.addChild(musicUpText);
musicDown.down = function () {
storage.musicVolume = Math.max(0, storage.musicVolume - 0.1);
musicLabel.setText('Music Volume: ' + Math.round(storage.musicVolume * 100) + '%');
LK.getSound('button_click').play();
};
musicUp.down = function () {
storage.musicVolume = Math.min(1, storage.musicVolume + 0.1);
musicLabel.setText('Music Volume: ' + Math.round(storage.musicVolume * 100) + '%');
LK.getSound('button_click').play();
};
// Sound volume
var soundLabel = new Text2('Sound Volume: ' + Math.round(storage.soundVolume * 100) + '%', {
size: 40,
fill: 0xFFFFFF
});
soundLabel.anchor.set(0.5, 0.5);
soundLabel.x = 1024;
soundLabel.y = 700;
settingsContainer.addChild(soundLabel);
var soundDown = LK.getAsset('platform', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
soundDown.x = 700;
soundDown.y = 750;
soundDown.interactive = true;
soundDown.buttonMode = true;
settingsContainer.addChild(soundDown);
var soundDownText = new Text2('-', {
size: 40,
fill: 0xFFFFFF
});
soundDownText.anchor.set(0.5, 0.5);
soundDownText.x = soundDown.x;
soundDownText.y = soundDown.y;
settingsContainer.addChild(soundDownText);
var soundUp = LK.getAsset('platform', {
width: 60,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x44FF44
});
soundUp.x = 1348;
soundUp.y = 750;
soundUp.interactive = true;
soundUp.buttonMode = true;
settingsContainer.addChild(soundUp);
var soundUpText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
soundUpText.anchor.set(0.5, 0.5);
soundUpText.x = soundUp.x;
soundUpText.y = soundUp.y;
settingsContainer.addChild(soundUpText);
soundDown.down = function () {
storage.soundVolume = Math.max(0, storage.soundVolume - 0.1);
soundLabel.setText('Sound Volume: ' + Math.round(storage.soundVolume * 100) + '%');
LK.getSound('button_click').play();
};
soundUp.down = function () {
storage.soundVolume = Math.min(1, storage.soundVolume + 0.1);
soundLabel.setText('Sound Volume: ' + Math.round(storage.soundVolume * 100) + '%');
LK.getSound('button_click').play();
};
// Back button
var backButton = LK.getAsset('platform', {
width: 200,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF4444
});
backButton.x = 1024;
backButton.y = 1000;
backButton.interactive = true;
backButton.buttonMode = true;
settingsContainer.addChild(backButton);
var backText = new Text2('BACK', {
size: 30,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = backButton.x;
backText.y = backButton.y;
settingsContainer.addChild(backText);
backButton.down = function () {
LK.getSound('button_click').play();
gameState = 'menu';
settingsContainer.visible = false;
menuContainer.visible = true;
};
}
function startGame() {
gameState = 'playing';
// Hide menu containers
if (mapSelectContainer) mapSelectContainer.visible = false;
// Set background color for selected map
game.setBackgroundColor(mapConfigs[currentMap].backgroundColor);
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 1.0,
x: 1024,
y: 2732
}));
// Create platforms based on selected map
platforms = [];
var platformData = mapConfigs[currentMap].platforms;
for (var i = 0; i < platformData.length; i++) {
var platform = new Platform();
platform.x = platformData[i].x;
platform.y = platformData[i].y;
platforms.push(platform);
game.addChild(platform);
}
// Create player
player = new Stickman();
player.x = 1024;
player.y = 2600;
player.canDoubleJump = true;
player.hasUsedDoubleJump = false;
game.addChild(player);
// Create stamina bar
staminaBarBackground = LK.getAsset('platform', {
width: 120,
height: 20,
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000
});
game.addChild(staminaBarBackground);
staminaBar = LK.getAsset('platform', {
width: 110,
height: 14,
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFFFFF
});
game.addChild(staminaBar);
// Clear arrows array
arrows = [];
// Create enemies based on selected map
enemies = [];
var enemyData = mapConfigs[currentMap].enemies;
for (var i = 0; i < enemyData.length; i++) {
var enemy;
switch (enemyData[i].type) {
case 'stickman':
enemy = new StickmanEnemy();
break;
case 'flying':
enemy = new FlyingEnemy();
break;
case 'boss':
enemy = new Boss();
break;
}
enemy.x = enemyData[i].x;
enemy.y = enemyData[i].y;
enemies.push(enemy);
game.addChild(enemy);
}
// Play level-specific music with configurable volume
var currentMusicTrack = mapConfigs[currentMap].musicTrack;
LK.playMusic(currentMusicTrack, {
fade: {
start: 0,
end: storage.musicVolume,
duration: 1000
}
});
// Show game UI
createGameUI();
}
function createGameUI() {
// UI Elements
healthText = new Text2('Health: 100', {
size: 40,
fill: 0x00FF00
});
healthText.anchor.set(0, 0);
LK.gui.left.addChild(healthText);
healthText.y = 200; // Position below top-left menu area
scoreText = new Text2('Score: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Map name display
var mapNameText = new Text2(mapConfigs[currentMap].name, {
size: 35,
fill: 0xFFD700
});
mapNameText.anchor.set(1, 0);
mapNameText.x = LK.gui.right.x - 20;
mapNameText.y = 200;
LK.gui.addChild(mapNameText);
}
// Global UI variables
var healthText, scoreText;
function createGameControls() {
// Mobile Controls UI - Improved for better ergonomics
leftButton = LK.getAsset('platform', {
width: 220,
height: 220,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0x4444FF
});
leftButton.x = 140;
leftButton.y = LK.gui.bottom.y - 140;
leftButton.interactive = true;
leftButton.buttonMode = true;
LK.gui.addChild(leftButton);
var leftIcon = LK.getAsset('warrior', {
width: 60,
height: 70,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
scaleX: -1
});
leftIcon.x = leftButton.x;
leftIcon.y = leftButton.y;
LK.gui.addChild(leftIcon);
rightButton = LK.getAsset('platform', {
width: 220,
height: 220,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0x4444FF
});
rightButton.x = 400;
rightButton.y = LK.gui.bottom.y - 140;
rightButton.interactive = true;
rightButton.buttonMode = true;
LK.gui.addChild(rightButton);
var rightIcon = LK.getAsset('warrior', {
width: 60,
height: 70,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
rightIcon.x = rightButton.x;
rightIcon.y = rightButton.y;
LK.gui.addChild(rightIcon);
jumpButton = LK.getAsset('platform', {
width: 240,
height: 240,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0x44FF44
});
jumpButton.x = LK.gui.right.x - 140;
jumpButton.y = LK.gui.bottom.y - 140;
jumpButton.interactive = true;
jumpButton.buttonMode = true;
LK.gui.addChild(jumpButton);
var jumpIcon = LK.getAsset('warrior', {
width: 70,
height: 80,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
rotation: -0.3
});
jumpIcon.x = jumpButton.x;
jumpIcon.y = jumpButton.y - 10;
LK.gui.addChild(jumpIcon);
attackButton = LK.getAsset('platform', {
width: 180,
height: 180,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0xFF4444
});
attackButton.x = LK.gui.right.x - 320;
attackButton.y = LK.gui.bottom.y - 140;
attackButton.interactive = true;
attackButton.buttonMode = true;
LK.gui.addChild(attackButton);
var attackLabel = new Text2('ATK', {
size: 35,
fill: 0xFFFFFF
});
attackLabel.anchor.set(0.5, 0.5);
attackLabel.x = attackButton.x;
attackLabel.y = attackButton.y;
LK.gui.addChild(attackLabel);
// Bow button
bowButton = LK.getAsset('platform', {
width: 180,
height: 180,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
tint: 0xFF8844
});
bowButton.x = LK.gui.right.x - 480;
bowButton.y = LK.gui.bottom.y - 140;
bowButton.interactive = true;
bowButton.buttonMode = true;
LK.gui.addChild(bowButton);
var bowIcon = LK.getAsset('arrow', {
width: 50,
height: 12,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
bowIcon.x = bowButton.x;
bowIcon.y = bowButton.y;
LK.gui.addChild(bowIcon);
setupControlEvents();
}
// Global control variables
var leftButton, rightButton, jumpButton, attackButton, bowButton;
// Collision detection function
function checkCollisions(obj, platforms) {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (obj.intersects(platform)) {
// Landing on top of platform
if (obj.velocityY > 0 && obj.y - 40 < platform.y) {
obj.y = platform.y - 40;
obj.velocityY = 0;
obj.onGround = true;
// Reset double jump when landing
if (obj === player) {
obj.canDoubleJump = true;
obj.hasUsedDoubleJump = false;
}
}
}
}
// Ground collision
if (obj.y > 2632) {
obj.y = 2632;
obj.velocityY = 0;
obj.onGround = true;
// Reset double jump when landing on ground
if (obj === player) {
obj.canDoubleJump = true;
obj.hasUsedDoubleJump = false;
}
}
}
function setupControlEvents() {
// Input handling - variables moved to global scope
game.down = function (x, y, obj) {
// Fallback touch handling for areas outside buttons
};
game.up = function (x, y, obj) {
// Fallback touch release handling
};
// Input state variables already declared in global scope
// Control event handlers
leftButton.down = function (x, y, obj) {
leftPressed = true;
currentTouchId = 'left';
tween(leftButton, {
alpha: 0.9
}, {
duration: 100
});
LK.getSound('button_click').play();
};
leftButton.up = function (x, y, obj) {
leftPressed = false;
if (currentTouchId === 'left') currentTouchId = null;
tween(leftButton, {
alpha: 0.6
}, {
duration: 100
});
};
rightButton.down = function (x, y, obj) {
rightPressed = true;
currentTouchId = 'right';
tween(rightButton, {
alpha: 0.9
}, {
duration: 100
});
LK.getSound('button_click').play();
};
rightButton.up = function (x, y, obj) {
rightPressed = false;
if (currentTouchId === 'right') currentTouchId = null;
tween(rightButton, {
alpha: 0.6
}, {
duration: 100
});
};
jumpButton.down = function (x, y, obj) {
player.jump();
tween(jumpButton, {
alpha: 0.9
}, {
duration: 100
});
};
jumpButton.up = function (x, y, obj) {
tween(jumpButton, {
alpha: 0.6
}, {
duration: 100
});
};
attackButton.down = function (x, y, obj) {
player.attack();
tween(attackButton, {
alpha: 0.9
}, {
duration: 100
});
};
attackButton.up = function (x, y, obj) {
tween(attackButton, {
alpha: 0.6
}, {
duration: 100
});
};
bowButton.down = function (x, y, obj) {
player.shootArrow();
tween(bowButton, {
alpha: 0.9
}, {
duration: 100
});
};
bowButton.up = function (x, y, obj) {
tween(bowButton, {
alpha: 0.6
}, {
duration: 100
});
};
}
// Initialize menu system
LK.playMusic('menu_music', {
volume: storage.musicVolume || 0.6
});
createMenu();
game.update = function () {
if (gameState !== 'playing') {
return; // Don't update game logic if not playing
}
// Handle input
if (leftPressed) {
player.moveLeft();
}
if (rightPressed) {
player.moveRight();
}
// Check collisions for player
checkCollisions(player, platforms);
// Check collisions for enemies
for (var i = 0; i < enemies.length; i++) {
checkCollisions(enemies[i], platforms);
}
// Update arrows and check enemy hits
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Check if arrow hits enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (arrow.intersects(enemy)) {
if (enemy.takeDamage(arrow.damage)) {
// Enemy destroyed
enemies.splice(j, 1);
LK.setScore(LK.getScore() + 150); // More points for ranged kills
scoreText.setText('Score: ' + LK.getScore());
}
// Remove arrow
arrow.destroy();
arrows.splice(i, 1);
break;
}
}
// Remove destroyed arrows
if (arrow.parent === null) {
arrows.splice(i, 1);
}
}
// Update projectiles and check enemy hits
for (var i = projectiles.length - 1; i >= 0; i--) {
var projectile = projectiles[i];
// Check if projectile hits enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (projectile.intersects(enemy)) {
if (enemy.takeDamage(25)) {
// Enemy destroyed
enemies.splice(j, 1);
LK.setScore(LK.getScore() + 100);
scoreText.setText('Score: ' + LK.getScore());
}
// Remove projectile
projectile.destroy();
projectiles.splice(i, 1);
break;
}
}
// Remove destroyed projectiles
if (projectile.parent === null) {
projectiles.splice(i, 1);
}
}
// Update enemy bullets and check player hits
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check if bullet hits player
if (bullet.intersects(player)) {
player.takeDamage(10);
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Remove destroyed bullets
if (bullet.parent === null) {
enemyBullets.splice(i, 1);
}
}
// Check player-enemy collisions
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (player.intersects(enemy)) {
// Simple knockback and damage
var dx = player.x - enemy.x;
player.velocityX += dx > 0 ? 5 : -5;
player.takeDamage(1);
// Update health display
healthText.setText('Health: ' + Math.max(0, player.health));
healthText.tint = player.health < 30 ? 0xFF0000 : 0x00FF00;
}
}
// Win condition - defeat all enemies
if (enemies.length === 0) {
// Update high score
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
LK.showYouWin();
}
// Update stamina bar position and appearance - moved higher up
staminaBarBackground.x = player.x;
staminaBarBackground.y = player.y - 130;
staminaBar.x = player.x;
staminaBar.y = player.y - 130;
// Update stamina bar color based on double jump availability
if (player.canDoubleJump && !player.hasUsedDoubleJump) {
staminaBar.tint = 0x00FF00; // Bright green when available
} else {
staminaBar.tint = 0x444444; // Dark gray when used
}
// Camera follow player (simple)
var targetY = Math.max(-1366, Math.min(0, -(player.y - 1366)));
game.y += (targetY - game.y) * 0.1;
// Apply volume settings to all sounds dynamically
var soundEffects = ['attack', 'bow_shoot', 'hit', 'jump', 'enemy_hit', 'button_click', 'enemy_death'];
for (var s = 0; s < soundEffects.length; s++) {
var sound = LK.getSound(soundEffects[s]);
if (sound && sound.volume !== undefined) {
sound.volume = storage.soundVolume;
}
}
};
// Create controls when game starts
createGameControls(); ===================================================================
--- original.js
+++ change.js
@@ -106,8 +106,9 @@
self.direction = 1;
self.attackCooldown = 0;
self.animationTick = 0;
self.phase = 1; // Boss has different phases
+ self.epicMusicTriggered = false;
self.update = function () {
// Apply gravity
if (!self.onGround) {
self.velocityY += 0.8;
@@ -132,9 +133,20 @@
self.attackCooldown = 120;
}
}
} else {
- // Phase 2: Faster, more aggressive
+ // Phase 2: Faster, more aggressive - trigger epic music transition
+ if (!self.epicMusicTriggered) {
+ self.epicMusicTriggered = true;
+ // Play boss music with higher intensity for final phase
+ LK.playMusic('boss_music', {
+ fade: {
+ start: storage.musicVolume,
+ end: storage.musicVolume * 1.2,
+ duration: 500
+ }
+ });
+ }
self.speed = 4;
if (distanceToPlayer > 150) {
if (player.x > self.x) {
self.direction = 1;
@@ -998,9 +1010,9 @@
};
self.shootArrow = function () {
if (self.attackCooldown <= 0) {
self.attackCooldown = 20; // Shorter cooldown for ranged attacks
- LK.getSound('attack').play();
+ LK.getSound('bow_shoot').play();
// Create arrow
var arrow = new Arrow();
arrow.x = self.x + (self.facingRight ? 40 : -40);
arrow.y = self.y - 80;
@@ -1372,8 +1384,9 @@
// Map definitions
var mapConfigs = [{
name: "Forest Plains",
backgroundColor: 0x228B22,
+ musicTrack: 'forest_music',
platforms: [{
x: 300,
y: 2500
}, {
@@ -1404,8 +1417,9 @@
}]
}, {
name: "Sky Temple",
backgroundColor: 0x4169E1,
+ musicTrack: 'sky_music',
platforms: [{
x: 200,
y: 2400
}, {
@@ -1443,8 +1457,9 @@
}]
}, {
name: "Boss Arena",
backgroundColor: 0x8B0000,
+ musicTrack: 'boss_music',
platforms: [{
x: 500,
y: 2400
}, {
@@ -1850,10 +1865,11 @@
enemy.y = enemyData[i].y;
enemies.push(enemy);
game.addChild(enemy);
}
- // Play game music
- LK.playMusic('game_music', {
+ // Play level-specific music with configurable volume
+ var currentMusicTrack = mapConfigs[currentMap].musicTrack;
+ LK.playMusic(currentMusicTrack, {
fade: {
start: 0,
end: storage.musicVolume,
duration: 1000
@@ -2254,14 +2270,15 @@
}
// Camera follow player (simple)
var targetY = Math.max(-1366, Math.min(0, -(player.y - 1366)));
game.y += (targetY - game.y) * 0.1;
- // Apply volume settings to sounds
- LK.getSound('attack').volume = storage.soundVolume;
- LK.getSound('hit').volume = storage.soundVolume;
- LK.getSound('jump').volume = storage.soundVolume;
- LK.getSound('enemy_hit').volume = storage.soundVolume;
- LK.getSound('button_click').volume = storage.soundVolume;
- LK.getSound('enemy_death').volume = storage.soundVolume;
+ // Apply volume settings to all sounds dynamically
+ var soundEffects = ['attack', 'bow_shoot', 'hit', 'jump', 'enemy_hit', 'button_click', 'enemy_death'];
+ for (var s = 0; s < soundEffects.length; s++) {
+ var sound = LK.getSound(soundEffects[s]);
+ if (sound && sound.volume !== undefined) {
+ sound.volume = storage.soundVolume;
+ }
+ }
};
// Create controls when game starts
createGameControls();
\ No newline at end of file
Crea un personaje estilo pixel art, un guerrero simple y fácil de animar. No debe tener manos ni piernas visibles, solo un cuerpo principal con forma redonda u ovalada. El diseño debe sugerir que es un guerrero usando colores llamativos, ojos brillantes o una armadura pixelada pegada al cuerpo. Puede tener una espada flotando al lado o en la espalda como decoración. Debe verse como un personaje de videojuego, pero sin partes que necesiten animación compleja.. In-Game asset. 2d. High contrast. No shadows
Diseña una espada estilo pixel art, sencilla pero llamativa. Debe ser fácil de animar o colocar junto a un personaje. El mango debe ser corto y simple, y la hoja puede ser recta o con un brillo digital. Usa colores llamativos como azul neón, rojo fuego o plateado con detalles pixelados. El diseño debe parecer futurista o mágico, como si fuera un arma especial de un guerrero digital.. In-Game asset. 2d. High contrast. No shadows