User prompt
quita de las reglas el cuadro verde
User prompt
más abajo el boton y cuadrado de fondo, quitalo de las reglas
User prompt
Quiero qiue el botón de empezar este masa abajo y que el cuadro veré sea un poco más grande
User prompt
Quieor qiue el botn de mepzar este m;as abajo y que el cuadro vere sea un poco más grande
User prompt
Ahora, quiero que agregues antes del primer texto un sistema de reglas que le diga al jugador como jugar
User prompt
Bien ahora quiero que cambies los ataques del enemigo a preguntas sorpresivas e interrupciones
User prompt
Quiero que el botón de continuar este más abajo
User prompt
Los texto se están saliendo, puedes ajustar eso?
User prompt
SI
User prompt
Genial, ahora haremos un cambio. Quiero que los cuadros de texto de cuando se gana un nivel aparezcan en la mitad de la pantalla
User prompt
Si me gustaria
User prompt
SI está bien
User prompt
Pero creo que ya está demasiado sencillo que sea en punto medio entre la anterior dificultad y la nueva dificultad
User prompt
SI, implementea la más efectiva
User prompt
Hay bug pequeño, y es que el jugador está muriendo de forma ramdom
User prompt
la que te parezca más efectiva ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
La que te parezca más efectiva
User prompt
arregla el boton de reset
User prompt
Pero se perdió el boton de reset
User prompt
Ouhhhh entiendo
User prompt
Perfecto, un detallito quiero que la palabra Reset esté bien centrada en el bontón de la esquina superior
User prompt
Mmm no pero quiero que el fondo del cuadrado sea negro y tenga un contorno, ese contorno quiero que sea de color blanco
User prompt
Genial está perfecto, ahora quiero que el delimitador del jugaador tenga un cortorno color blanco
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Determine enemy image based on level
var enemyAssetId = 'enemigo'; // Default for level 1
if (level === 2) enemyAssetId = 'enemigo2';else if (level === 3) enemyAssetId = 'enemigo3';else if (level === 4) enemyAssetId = 'enemigo4';else if (level === 5) enemyAssetId = 'enemigo5';
var enemyGraphics = self.attachAsset(enemyAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Health properties
self.health = 100;
self.maxHealth = 100;
// Health bar will be created in GUI instead of attached to enemy
self.healthBarBg = null;
self.healthBar = null;
// Subtle animation properties
self.animTimer = 0;
self.baseX = 0;
self.update = function () {
// Subtle side-to-side movement
self.animTimer += 0.05;
self.x = self.baseX + Math.sin(self.animTimer) * 30;
};
// Method to show attack effect
self.showAttackEffect = function () {
// Flash effect when attacking
tween(enemyGraphics, {
tint: 0xff4444
}, {
duration: 150,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xffffff
}, {
duration: 150
});
}
});
// Play attack sound effect
LK.getSound('blaster_spawn').play();
};
// Method to take damage
self.takeDamage = function (amount) {
if (amount === undefined) amount = 20;
self.health = Math.max(0, self.health - amount);
self.updateHealthBar();
// Flash red effect when taking damage
tween(enemyGraphics, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Check if enemy is defeated
if (self.health <= 0) {
// Hide enemy
self.visible = false;
// Hide health bar elements
if (self.healthBar) self.healthBar.visible = false;
if (self.healthBarBg) self.healthBarBg.visible = false;
// Enemy defeated - advance level
level++;
if (level > maxLevel) {
// Stop music and prepare for victory
LK.stopMusic();
LK.setTimeout(function () {
LK.showYouWin();
}, 500);
} else {
// Play level completion sound effect
LK.getSound('blaster_spawn').play();
// Reset enemy health for next level
self.health = self.maxHealth;
// Update enemy graphics for new level
self.updateEnemyGraphics();
// Show next level dialogue
showDialogue(levelNarratives[level - 1]);
}
}
};
// Method to initialize health bar in GUI
self.initHealthBar = function () {
if (!self.healthBarBg) {
// Health bar background - top center
self.healthBarBg = LK.gui.top.addChild(LK.getAsset('enemyHealthBarBg', {
anchorX: 0.5,
anchorY: 0
}));
self.healthBarBg.y = 130;
self.healthBarBg.visible = true;
// Health bar - top center
self.healthBar = LK.gui.top.addChild(LK.getAsset('enemyHealthBar', {
anchorX: 0.5,
anchorY: 0
}));
self.healthBar.y = 130;
self.healthBar.visible = true;
// Force immediate red color - the asset already has red color but we ensure it's applied
self.healthBar.tint = 0xff0000;
self.healthBar.tintAlpha = 1.0;
self.healthBar.alpha = 1.0;
// Force a visual update by setting width to current health percentage
var healthPercentage = self.health / self.maxHealth;
self.healthBar.width = 400 * healthPercentage;
// Enemy health label
var enemyHealthLabel = LK.gui.top.addChild(new Text2('Vida del Enemigo', {
size: 36,
fill: 0xffffff
}));
enemyHealthLabel.anchor.set(0.5, 0);
enemyHealthLabel.y = 70;
// Initialize health bar display immediately after creation
self.updateHealthBar();
}
};
// Method to update health bar visual
self.updateHealthBar = function () {
if (!self.healthBar || !self.healthBarBg) return;
// Make sure health bar is visible
self.healthBar.visible = true;
self.healthBarBg.visible = true;
self.healthBar.alpha = 1.0;
var healthPercentage = self.health / self.maxHealth;
self.healthBar.width = 400 * healthPercentage;
// Always set red color for consistency (enemy health bar should be red)
self.healthBar.tint = 0xff0000; // Always red for enemy
// Ensure tint is fully applied
self.healthBar.tintAlpha = 1.0;
};
// Method to update enemy graphics when level changes
self.updateEnemyGraphics = function () {
// Remove current graphics
if (enemyGraphics && enemyGraphics.parent) {
enemyGraphics.parent.removeChild(enemyGraphics);
}
// Determine new enemy image based on level
var enemyAssetId = 'enemigo'; // Default for level 1
if (level === 2) enemyAssetId = 'enemigo2';else if (level === 3) enemyAssetId = 'enemigo3';else if (level === 4) enemyAssetId = 'enemigo4';else if (level === 5) enemyAssetId = 'enemigo5';
// Create new graphics with updated asset
enemyGraphics = self.attachAsset(enemyAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
return self;
});
var GreenTextAttack = Container.expand(function () {
var self = Container.call(this);
// Create random positive text
var positiveTexts = ['CALMA', 'PAZ', 'FUERZA', 'ESPERANZA', 'CONFIANZA'];
var randomText = positiveTexts[Math.floor(Math.random() * positiveTexts.length)];
var textGraphics = self.addChild(new Text2(randomText, {
size: getTextSize(true, level),
fill: 0x00ff00,
stroke: 0x000000,
strokeThickness: 3
}));
textGraphics.anchor.set(0.5, 0.5);
self.speed = 5;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement properties
self.speed = HEART_SPEED;
self.isMovingLeft = false;
self.isMovingRight = false;
// Health
self.health = 100;
self.update = function () {
// Keyboard movement
if (self.isMovingLeft) {
self.x -= self.speed;
}
if (self.isMovingRight) {
self.x += self.speed;
}
// Boundary checking - constrain to boundary box
if (self.x < BOUNDARY_LEFT + HEART_MARGIN) {
self.x = BOUNDARY_LEFT + HEART_MARGIN;
}
if (self.x > BOUNDARY_RIGHT - HEART_MARGIN) {
self.x = BOUNDARY_RIGHT - HEART_MARGIN;
}
if (self.y < BOUNDARY_TOP + HEART_MARGIN) {
self.y = BOUNDARY_TOP + HEART_MARGIN;
}
if (self.y > BOUNDARY_BOTTOM - HEART_MARGIN) {
self.y = BOUNDARY_BOTTOM - HEART_MARGIN;
}
};
self.takeDamage = function (amount) {
if (amount === undefined) amount = 10;
self.health = Math.max(0, self.health - amount);
// Play hurt sound effect
LK.getSound('Damage').play();
// Flash red effect
tween(heartGraphics, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(heartGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
if (self.health <= 0) {
LK.showGameOver();
}
};
return self;
});
var TechniqueMenu = Container.expand(function () {
var self = Container.call(this);
// Background
var bg = self.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
}));
bg.width = 700;
bg.height = 480;
bg.tint = 0x333333;
// Title
var title = self.addChild(new Text2('Técnica de Relajación', {
size: 48,
fill: 0xffffff
}));
title.anchor.set(0.5, 0.5);
title.y = -120;
// Techniques
var techniques = ['Respiración Profunda', 'Mindfulness', 'Relajación Muscular'];
var selectedTechnique = techniques[Math.floor(Math.random() * techniques.length)];
var techniqueText = self.addChild(new Text2(selectedTechnique, {
size: 42,
fill: 0x00ff00
}));
techniqueText.anchor.set(0.5, 0.5);
techniqueText.y = -50;
// Instructions
var instruction = self.addChild(new Text2('Toca para aplicar', {
size: 36,
fill: 0xcccccc
}));
instruction.anchor.set(0.5, 0.5);
instruction.y = 20;
self.duration = 0;
self.maxDuration = 3000; // 3 seconds
self.update = function () {
self.duration += 16.67;
if (self.duration >= self.maxDuration) {
self.destroy();
}
};
self.down = function () {
// Apply technique - boost credibilidad
credibilidad = Math.min(100, credibilidad + 15);
updateBars();
self.destroy();
};
return self;
});
var TextAttack = Container.expand(function () {
var self = Container.call(this);
// Create random attack text
var attackTexts = ['ESTRÉS', 'MIEDO', 'PÁNICO', 'DUDAS', 'CRÍTICAS'];
var randomText = attackTexts[Math.floor(Math.random() * attackTexts.length)];
var textGraphics = self.addChild(new Text2(randomText, {
size: getTextSize(false, level),
fill: 0xff0000,
stroke: 0x000000,
strokeThickness: 3
}));
textGraphics.anchor.set(0.5, 0.5);
// Enhanced movement properties based on level - moderate difficulty
self.baseSpeed = getAttackSpeed(level);
self.speed = self.baseSpeed;
self.acceleration = 0.08 + (level - 1) * 0.03; // Moderate acceleration
self.maxSpeed = self.baseSpeed * 1.8; // Can accelerate up to 1.8x base speed
// Movement pattern selection (more predictable patterns at lower levels)
self.movementPattern = Math.floor(Math.random() * Math.min(3, level)); // Reduced max patterns
// 0: Basic straight, 1: Zigzag, 2: Pursuit, 3: Spiral (removed erratic)
// Pattern-specific properties
self.speedX = (Math.random() - 0.5) * (3 + level * 1.5); // Moderate horizontal movement
self.speedY = self.speed;
self.waveAmplitude = Math.random() * (15 + level * 8) + 8; // Moderate wave amplitude
self.waveFrequency = Math.random() * 0.06 + 0.03 + level * 0.015; // Moderate wave frequency
self.animTimer = Math.random() * Math.PI * 2;
self.directionChangeTimer = Math.random() * (1000 - level * 60) + 350; // Moderate direction changes
self.maxDirectionChangeTimer = self.directionChangeTimer;
self.pursuitStrength = 0.25 + (level - 1) * 0.12; // Moderate pursuit strength
self.lastHeartX = heart.x;
self.lastHeartY = heart.y;
self.update = function () {
// Get current heart position for pursuit calculations
var heartX = heart.x;
var heartY = heart.y;
// Accelerate over time (attacks get faster)
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
self.speedY = self.speed;
}
// Movement pattern execution - simplified and less aggressive
switch (self.movementPattern) {
case 0:
// Basic straight movement with moderate tracking
self.y += self.speedY;
// Moderate horizontal drift toward heart
var heartDirection = heartX > self.x ? 1 : -1;
self.x += heartDirection * (level * 0.35); // Moderate tracking
break;
case 1:
// Zigzag with moderate pursuit
self.y += self.speedY;
self.animTimer += self.waveFrequency;
self.x += Math.sin(self.animTimer) * self.waveAmplitude * 0.15; // Moderate zigzag intensity
// Moderate pursuit element
var pursuitX = (heartX - self.x) * self.pursuitStrength * 0.08; // Moderate pursuit
self.x += pursuitX;
break;
case 2:
// Moderate pursuit - balanced aggression
var deltaX = heartX - self.x;
var deltaY = heartY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
self.x += deltaX / distance * self.speed * self.pursuitStrength * 0.7; // Moderate pursuit
self.y += deltaY / distance * self.speed * self.pursuitStrength * 0.45; // Moderate vertical pursuit
}
// Still move generally downward but less predictable
self.y += self.speedY * 0.75; // Moderate downward movement
break;
case 3:
// Spiral pattern with moderate pursuit
self.y += self.speedY * 0.85; // Moderate downward movement
self.animTimer += self.waveFrequency;
var spiralRadius = 25 + Math.sin(self.animTimer * 0.3) * 15; // Moderate spiral
self.x += Math.cos(self.animTimer) * spiralRadius * 0.12; // Moderate spiral intensity
// Moderate drift toward heart
var driftX = (heartX - self.x) * 0.035; // Moderate drift
self.x += driftX;
break;
}
// Enhanced boundary behavior - some attacks can bounce
if (self.x < BOUNDARY_LEFT - 50) {
if (level >= 3 && Math.random() < 0.4) {
// Bounce off left wall
self.speedX = Math.abs(self.speedX) * 1.2;
} else {
self.speedX = Math.abs(self.speedX);
}
}
if (self.x > BOUNDARY_RIGHT + 50) {
if (level >= 3 && Math.random() < 0.4) {
// Bounce off right wall
self.speedX = -Math.abs(self.speedX) * 1.2;
} else {
self.speedX = -Math.abs(self.speedX);
}
}
// Store last heart position for next frame
self.lastHeartX = heartX;
self.lastHeartY = heartY;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Turn-based constants
// Game Constants
var ENEMY_ATTACK_DURATION = 3000; // 3 seconds for enemy attack phase
var PLAYER_ATTACK_DURATION = 3000; // 3 seconds for player attack phase
var ATTACKS_PER_TURN = 3; // Number of attacks enemy launches per turn
var LEVEL_DIFF = 5;
var MAX_LEVEL = 10;
var WIN_CRED = 60;
var LEVEL_CRED_BOOST = 5;
var GAME_LEFT = 300;
var GAME_RIGHT = 1748;
var GAME_TOP = 200;
var GAME_BOTTOM = 2732;
var GAME_WIDTH = GAME_RIGHT - GAME_LEFT;
// Heart movement constants
var HEART_SPEED = 8;
var HEART_MARGIN = 60;
// Boundary box constants
var BOUNDARY_WIDTH = 800;
var BOUNDARY_HEIGHT = 400;
var BOUNDARY_LEFT = (2048 - BOUNDARY_WIDTH) / 2;
var BOUNDARY_RIGHT = BOUNDARY_LEFT + BOUNDARY_WIDTH;
var BOUNDARY_TOP = GAME_BOTTOM - 900;
var BOUNDARY_BOTTOM = BOUNDARY_TOP + BOUNDARY_HEIGHT;
// Text size scaling function
function getTextSize(isGreen, currentLevel) {
var baseSize = 20;
var sizeMultiplier = 10;
var scale;
if (isGreen) {
// Green words: size 5 at level 1, size 1 at level 5
scale = 6 - currentLevel;
} else {
// Red words: size 1 at level 1, size 5 at level 5
scale = currentLevel;
}
// Ensure scale is between 1 and 5
scale = Math.max(1, Math.min(5, scale));
return baseSize + scale * sizeMultiplier;
}
// Attack difficulty scaling function
function getAttackSpeed(currentLevel) {
// Base speed increases more gradually with level - reduced difficulty
return 4 + (currentLevel - 1) * 2; // Level 1: 4, Level 5: 12
}
function getAttackFrequency(currentLevel) {
// Attack interval decreases (more frequent attacks) with level
return Math.max(300, 1000 - (currentLevel - 1) * 175); // Level 1: 1000ms, Level 5: 300ms
}
function getMaxSimultaneousAttacks(currentLevel) {
// More attacks on screen at once as level increases
return Math.min(8, 2 + currentLevel); // Level 1: 3, Level 5: 7
}
// Game state management
var gameState = 'menu'; // 'menu', 'dialogue', 'enemyTurn', 'playerTurn', 'transition'
var menuContainer = game.addChild(new Container());
// Turn-based variables
var currentTurn = 'enemy'; // 'enemy' or 'player'
var turnTimer = 0;
var attacksLaunched = 0;
var attackTimer = 0;
// Game variables
var level = 1;
var maxLevel = 5;
var dialogueContainer = game.addChild(new Container());
dialogueContainer.visible = false;
// Level narratives
var levelNarratives = ["Nivel 1: Bienvenido a tu primera sesión de tutoría. Los pensamientos negativos comenzarán lentamente.", "Nivel 2: Bien hecho. Ahora los ataques serán más frecuentes. Mantén la calma y usa las técnicas.", "Nivel 3: Excelente progreso. Los pensamientos llegan más rápido, pero ya tienes más experiencia.", "Nivel 4: Casi terminas tu entrenamiento. Los ataques son intensos, confía en tu preparación.", "Nivel 5: Nivel final. Domina completamente las técnicas contra los ataques más desafiantes."];
var score = 0;
var ansiedad = 0;
var credibilidad = 50;
// UI Elements
var ansiedadBarBg = null,
ansiedadBar = null,
credibilidadBarBg = null,
credibilidadBar = null;
var levelText = null,
scoreText = null;
// Initialize UI
function initializeUI() {
// Ansiedad bar - bottom left
ansiedadBarBg = LK.gui.bottomLeft.addChild(LK.getAsset('ansiedadBarBg', {
anchorX: 0,
anchorY: 1
}));
ansiedadBarBg.x = 120;
ansiedadBarBg.y = -150;
ansiedadBar = LK.gui.bottomLeft.addChild(LK.getAsset('ansiedadBar', {
anchorX: 0,
anchorY: 1
}));
ansiedadBar.x = 120;
ansiedadBar.y = -150;
// Credibilidad bar - bottom right
credibilidadBarBg = LK.gui.bottomRight.addChild(LK.getAsset('credibilidadBarBg', {
anchorX: 1,
anchorY: 1
}));
credibilidadBarBg.x = -120;
credibilidadBarBg.y = -150;
credibilidadBar = LK.gui.bottomRight.addChild(LK.getAsset('credibilidadBar', {
anchorX: 1,
anchorY: 1
}));
credibilidadBar.x = -120;
credibilidadBar.y = -150;
// Text labels
var ansiedadLabel = LK.gui.bottomLeft.addChild(new Text2('Ansiedad', {
size: 30,
fill: 0xffffff
}));
ansiedadLabel.x = 120;
ansiedadLabel.y = -110;
var credibilidadLabel = LK.gui.bottomRight.addChild(new Text2('Credibilidad', {
size: 30,
fill: 0xffffff
}));
credibilidadLabel.anchor.set(1, 1);
credibilidadLabel.x = -120;
credibilidadLabel.y = -110;
// Level and score - keep at top
levelText = LK.gui.topRight.addChild(new Text2('Nivel: 1', {
size: 36,
fill: 0xffffff
}));
levelText.anchor.set(1, 0);
levelText.x = -20;
levelText.y = 50;
}
function updateBars() {
// Update bar widths based on values
var ansiedadWidth = ansiedad / 100 * 300;
var credibilidadWidth = credibilidad / 100 * 300;
ansiedadBar.width = ansiedadWidth;
credibilidadBar.width = credibilidadWidth;
// Adjust credibilidad bar position since it's right-anchored
credibilidadBar.x = -120 - (300 - credibilidadWidth);
// Update text
levelText.setText('Nivel: ' + level);
}
function showDialogue(text) {
gameState = 'dialogue';
dialogueContainer.visible = true;
// Clear previous dialogue
dialogueContainer.removeChildren();
// Dialogue background
var dialogueBg = dialogueContainer.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0
}));
dialogueBg.width = 1900;
dialogueBg.height = 280;
dialogueBg.tint = 0x333333;
dialogueBg.x = 1024;
dialogueBg.y = 180;
// Dialogue text
var dialogueText = dialogueContainer.addChild(new Text2(text, {
size: 40,
fill: 0xffffff
}));
dialogueText.anchor.set(0.5, 0.5);
dialogueText.x = 1024;
dialogueText.y = 280;
// Continue button
var continueBtn = dialogueContainer.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
}));
continueBtn.width = 380;
continueBtn.height = 100;
continueBtn.tint = 0x00aa00;
continueBtn.x = 1024;
continueBtn.y = 410;
var continueText = dialogueContainer.addChild(new Text2('Continuar', {
size: 48,
fill: 0xffffff
}));
continueText.anchor.set(0.5, 0.5);
continueText.x = continueBtn.x;
continueText.y = continueBtn.y;
continueBtn.down = function () {
dialogueContainer.visible = false;
gameState = 'enemyTurn'; // Start with enemy turn
// Initialize and show UI if not already done
if (!ansiedadBarBg || ansiedadBarBg && !ansiedadBarBg.parent) {
initializeUI();
}
// Initialize enemy health bar
enemy.initHealthBar();
// Show enemy and health bar again
enemy.visible = true;
// Ensure health bar is visible and properly updated
enemy.updateHealthBar();
updateBars();
heart.visible = true;
boundaryBox.visible = true;
boundaryBoxBorder.visible = true;
// Adjust music volume based on level intensity
var musicVolume = 0.4 + level * 0.1; // Volume increases with level
LK.playMusic('fondo', {
fade: {
start: LK.getCurrentMusicVolume ? LK.getCurrentMusicVolume() : 0.6,
end: musicVolume,
duration: 800
}
});
};
}
// Reset button functionality
function resetGame() {
// Stop all current music
LK.stopMusic();
// Reset all game variables to initial state
level = 1;
ansiedad = 0;
credibilidad = 50;
score = 0;
gameState = 'menu';
currentTurn = 'enemy';
turnTimer = 0;
attacksLaunched = 0;
attackTimer = 0;
greenAttackTimer = 0;
ansiedadTimer = 0;
scoreTimer = 0;
// Destroy all active attacks
for (var i = textAttacks.length - 1; i >= 0; i--) {
textAttacks[i].destroy();
}
textAttacks = [];
for (var j = greenTextAttacks.length - 1; j >= 0; j--) {
greenTextAttacks[j].destroy();
}
greenTextAttacks = [];
// Reset enemy to initial state
if (enemy) {
enemy.visible = false;
enemy.health = enemy.maxHealth;
// Reset enemy graphics to level 1
enemy.updateEnemyGraphics();
}
// Hide heart character
if (heart) {
heart.visible = false;
heart.health = 100;
heart.x = 2048 / 2;
heart.y = BOUNDARY_TOP + BOUNDARY_HEIGHT / 2;
heart.isMovingLeft = false;
heart.isMovingRight = false;
}
// Hide boundary box
if (boundaryBox) {
boundaryBox.visible = false;
}
// Hide boundary box border
if (boundaryBoxBorder) {
boundaryBoxBorder.visible = false;
}
// Hide dialogue
dialogueContainer.visible = false;
// Hide player turn menu
hidePlayerTurnMenu();
// Hide and reset UI bars
if (ansiedadBarBg) {
ansiedadBarBg.visible = false;
ansiedadBarBg.parent.removeChild(ansiedadBarBg);
ansiedadBarBg = null;
}
if (ansiedadBar) {
ansiedadBar.visible = false;
ansiedadBar.parent.removeChild(ansiedadBar);
ansiedadBar = null;
}
if (credibilidadBarBg) {
credibilidadBarBg.visible = false;
credibilidadBarBg.parent.removeChild(credibilidadBarBg);
credibilidadBarBg = null;
}
if (credibilidadBar) {
credibilidadBar.visible = false;
credibilidadBar.parent.removeChild(credibilidadBar);
credibilidadBar = null;
}
if (levelText) {
levelText.visible = false;
levelText.parent.removeChild(levelText);
levelText = null;
}
// Hide enemy health bar
if (enemy && enemy.healthBar) {
enemy.healthBar.visible = false;
enemy.healthBar.parent.removeChild(enemy.healthBar);
enemy.healthBar = null;
}
if (enemy && enemy.healthBarBg) {
enemy.healthBarBg.visible = false;
enemy.healthBarBg.parent.removeChild(enemy.healthBarBg);
enemy.healthBarBg = null;
}
// Show main menu
menuContainer.visible = true;
// Start menu music from beginning
LK.playMusic('menumusic');
}
// Start menu music
LK.playMusic('menumusic');
// Create reset button
var resetButton = LK.gui.topRight.addChild(LK.getAsset('resetButton', {
anchorX: 1,
anchorY: 0
}));
resetButton.x = -20;
resetButton.y = 120;
var resetText = LK.gui.topRight.addChild(new Text2('RESET', {
size: 24,
fill: 0xffffff
}));
resetText.anchor.set(0.5, 0.5);
resetText.x = resetButton.x - resetButton.width / 2;
resetText.y = resetButton.y + resetButton.height / 2;
// Reset button interaction
resetButton.down = function () {
// Flash button on press
tween(resetButton, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(resetButton, {
tint: 0xffffff
}, {
duration: 100
});
}
});
// Reset the game
resetGame();
};
// Create menu elements
var logo = menuContainer.addChild(LK.getAsset('gameLogo', {
anchorX: 0.5,
anchorY: 0.5
}));
logo.x = 2048 / 2;
logo.y = 2732 / 2 - 250;
// Create play button
var playButton = menuContainer.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
}));
playButton.width = 500;
playButton.height = 150;
playButton.x = 2048 / 2;
playButton.y = 2732 / 2 + 100;
// Play button text
var playText = menuContainer.addChild(new Text2('JUGAR', {
size: 90,
fill: 0xFFFFFF
}));
playText.anchor.set(0.5, 0.5);
playText.x = playButton.x;
playText.y = playButton.y;
// Play button interaction
playButton.down = function (x, y, obj) {
// Flash button on press
tween(playButton, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(playButton, {
tint: 0xffffff
}, {
duration: 100
});
}
});
};
playButton.up = function (x, y, obj) {
// Switch to background music
LK.playMusic('fondo', {
fade: {
start: 0,
end: 0.6,
duration: 1000
}
});
// Show level dialogue first
menuContainer.visible = false;
showDialogue(levelNarratives[level - 1]);
};
// Create the enemy
var enemy = game.addChild(new Enemy());
enemy.x = 2048 / 2;
enemy.baseX = enemy.x;
enemy.y = GAME_TOP + 300; // Moved down further to avoid health bar overlap
enemy.visible = false;
// Create boundary box with white border (border first, then main box on top)
var boundaryBoxBorder = game.addChild(LK.getAsset('boundaryBoxBorder', {
anchorX: 0.5,
anchorY: 0.5
}));
boundaryBoxBorder.x = 2048 / 2;
boundaryBoxBorder.y = BOUNDARY_TOP + BOUNDARY_HEIGHT / 2;
boundaryBoxBorder.alpha = 1.0; // Fully visible white border
boundaryBoxBorder.visible = false;
// Create boundary box visual (black box on top of white border)
var boundaryBox = game.addChild(LK.getAsset('boundaryBox', {
anchorX: 0.5,
anchorY: 0.5
}));
boundaryBox.x = 2048 / 2;
boundaryBox.y = BOUNDARY_TOP + BOUNDARY_HEIGHT / 2;
boundaryBox.alpha = 1.0; // Fully opaque black background
boundaryBox.visible = false;
// Create the heart character
var heart = game.addChild(new Heart());
heart.x = 2048 / 2;
heart.y = BOUNDARY_TOP + BOUNDARY_HEIGHT / 2; // Position centered in boundary box
heart.visible = false;
// Keyboard controls - using LK event system instead of window
LK.on('keydown', function (event) {
if (gameState !== 'enemyTurn') return;
if (event.key === 'ArrowLeft') {
heart.isMovingLeft = true;
}
if (event.key === 'ArrowRight') {
heart.isMovingRight = true;
}
});
LK.on('keyup', function (event) {
if (gameState !== 'enemyTurn') return;
if (event.key === 'ArrowLeft') {
heart.isMovingLeft = false;
}
if (event.key === 'ArrowRight') {
heart.isMovingRight = false;
}
});
// Touch controls for mobile
game.move = function (x, y, obj) {
if (gameState === 'enemyTurn') {
// Move heart towards touch position
if (x < heart.x) {
heart.isMovingLeft = true;
heart.isMovingRight = false;
} else if (x > heart.x) {
heart.isMovingRight = true;
heart.isMovingLeft = false;
}
}
};
game.up = function (x, y, obj) {
if (gameState === 'enemyTurn') {
heart.isMovingLeft = false;
heart.isMovingRight = false;
}
};
// Game arrays and timers
var textAttacks = [];
var greenTextAttacks = [];
var attackTimer = 0;
var greenAttackTimer = 0;
var ansiedadTimer = 0;
var scoreTimer = 0;
// Player turn menu
var playerTurnMenu = null;
function showPlayerTurnMenu() {
if (playerTurnMenu) return; // Already showing
playerTurnMenu = game.addChild(new Container());
playerTurnMenu.x = 1024;
playerTurnMenu.y = 1800;
// Background
var menuBg = playerTurnMenu.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
}));
menuBg.width = 1600;
menuBg.height = 600;
menuBg.tint = 0x333333;
// Title
var title = playerTurnMenu.addChild(new Text2('Tu Turno - Técnicas de Tutoría', {
size: 40,
fill: 0xffffff
}));
title.anchor.set(0.5, 0.5);
title.y = -100;
// Technique buttons
var techniques = [{
text: 'Respiración Profunda',
effect: function effect() {
credibilidad += 20;
ansiedad = Math.max(0, ansiedad - 15);
enemy.takeDamage(15);
}
}, {
text: 'Palabras de Aliento',
effect: function effect() {
credibilidad += 25;
enemy.takeDamage(25);
}
}, {
text: 'Mindfulness',
effect: function effect() {
ansiedad = Math.max(0, ansiedad - 20);
enemy.takeDamage(20);
}
}];
for (var i = 0; i < techniques.length; i++) {
var btn = playerTurnMenu.addChild(LK.getAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5
}));
btn.width = 450;
btn.height = 120;
btn.tint = 0x00aa00;
btn.x = (i - 1) * 420;
btn.y = 40;
btn.techniqueIndex = i;
var btnText = playerTurnMenu.addChild(new Text2(techniques[i].text, {
size: 38,
fill: 0xffffff
}));
btnText.anchor.set(0.5, 0.5);
btnText.x = btn.x;
btnText.y = btn.y;
btn.down = function () {
var technique = techniques[this.techniqueIndex];
technique.effect();
credibilidad = Math.min(100, credibilidad);
ansiedad = Math.max(0, ansiedad);
updateBars();
// Flash effect
tween(this, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(this, {
tint: 0x00aa00
}, {
duration: 100
});
}
});
// End player turn and prepare for enemy turn
hidePlayerTurnMenu();
// Set a brief delay before enemy turn starts
LK.setTimeout(function () {
gameState = 'enemyTurn';
turnTimer = 0;
attacksLaunched = 0;
attackTimer = 0;
}, 500); // 500ms delay before enemy can start attacking
};
}
}
function hidePlayerTurnMenu() {
if (playerTurnMenu) {
playerTurnMenu.destroy();
playerTurnMenu = null;
}
}
// Main game update loop
game.update = function () {
// Only update game logic when in turn-based states
if (gameState !== 'enemyTurn' && gameState !== 'playerTurn') return;
// Allow heart movement during gameplay
if (gameState === 'enemyTurn' || gameState === 'playerTurn') {
heart.update();
}
// Turn-based system
if (gameState === 'enemyTurn') {
// Only allow enemy attacks if enemy is alive (visible)
if (enemy.visible) {
// Enemy's turn - launch attacks
turnTimer += 16.67; // Add frame time
attackTimer += 16.67;
// Enhanced attack system with level-based difficulty
var attackInterval = getAttackFrequency(level);
var maxAttacksPerTurn = getMaxSimultaneousAttacks(level);
var maxSimultaneousAttacks = getMaxSimultaneousAttacks(level);
if (attackTimer >= attackInterval && attacksLaunched < maxAttacksPerTurn && textAttacks.length < maxSimultaneousAttacks) {
// Launch multiple attacks in formation for higher levels
var attacksToLaunch = level >= 3 ? Math.floor(Math.random() * 2) + 1 : 1;
for (var attackIndex = 0; attackIndex < attacksToLaunch && attacksLaunched < maxAttacksPerTurn; attackIndex++) {
var textAttack = new TextAttack();
// Varied spawn positions based on level
if (level >= 4) {
// Higher levels: attacks can spawn from sides too
var spawnSide = Math.random();
if (spawnSide < 0.6) {
// From above (normal)
textAttack.x = enemy.x + (Math.random() - 0.5) * 200;
textAttack.y = enemy.y + 50;
} else if (spawnSide < 0.8) {
// From left side
textAttack.x = BOUNDARY_LEFT - 50;
textAttack.y = BOUNDARY_TOP + Math.random() * BOUNDARY_HEIGHT;
} else {
// From right side
textAttack.x = BOUNDARY_RIGHT + 50;
textAttack.y = BOUNDARY_TOP + Math.random() * BOUNDARY_HEIGHT;
}
} else {
// Lower levels: spawn from above only
textAttack.x = enemy.x + (Math.random() - 0.5) * (100 + level * 50);
textAttack.y = enemy.y + 50;
}
textAttacks.push(textAttack);
game.addChild(textAttack);
attacksLaunched++;
}
enemy.showAttackEffect();
attackTimer = 0;
}
// End enemy turn only when all attacks are launched AND all attacks are processed (hit or missed)
if (attacksLaunched >= maxAttacksPerTurn && textAttacks.length === 0) {
gameState = 'playerTurn';
turnTimer = 0;
// Show player turn interface
showPlayerTurnMenu();
}
}
} else if (gameState === 'playerTurn') {
// Player's turn - wait for player action or timeout
turnTimer += 16.67;
// Player turn ends only when technique is selected (handled in showPlayerTurnMenu)
// No automatic timeout - player must make a choice
}
// Update and check TextAttack collisions
for (var i = textAttacks.length - 1; i >= 0; i--) {
var atk = textAttacks[i];
// Initialize collision tracking if not present
if (atk.lastIntersecting === undefined) {
atk.lastIntersecting = false;
}
// Check for NEW collision with heart (transition from not intersecting to intersecting)
var currentIntersecting = atk.intersects(heart);
if (!atk.lastIntersecting && currentIntersecting) {
// Only damage on the first frame of collision
heart.takeDamage(15);
ansiedad = Math.min(100, ansiedad + 15);
credibilidad = Math.max(0, credibilidad - 10);
// Play hurt sound when anxiety increases
LK.getSound('Damage').play();
updateBars();
atk.destroy();
textAttacks.splice(i, 1);
continue;
}
// Update last intersection state
atk.lastIntersecting = currentIntersecting;
// Remove off-screen attacks
if (atk.y > GAME_BOTTOM + 100) {
atk.destroy();
textAttacks.splice(i, 1);
}
}
// Update and check GreenTextAttack collisions
for (var k = greenTextAttacks.length - 1; k >= 0; k--) {
var greenAtk = greenTextAttacks[k];
// Initialize collision tracking if not present
if (greenAtk.lastIntersecting === undefined) {
greenAtk.lastIntersecting = false;
}
// Check for NEW collision with heart (transition from not intersecting to intersecting)
var currentIntersecting = greenAtk.intersects(heart);
if (!greenAtk.lastIntersecting && currentIntersecting) {
// Only give benefit on the first frame of collision
credibilidad = Math.min(100, credibilidad + 8);
updateBars();
greenAtk.destroy();
greenTextAttacks.splice(k, 1);
continue;
}
// Update last intersection state
greenAtk.lastIntersecting = currentIntersecting;
// Remove off-screen green attacks
if (greenAtk.y > GAME_BOTTOM + 100) {
greenAtk.destroy();
greenTextAttacks.splice(k, 1);
}
}
// Check game over conditions
if (ansiedad >= 100 || credibilidad <= 0) {
// Fade out music before game over
LK.playMusic('fondo', {
fade: {
start: LK.getCurrentMusicVolume ? LK.getCurrentMusicVolume() : 0.6,
end: 0,
duration: 500
}
});
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
// Check win condition
if (level >= maxLevel && credibilidad >= WIN_CRED) {
LK.showYouWin();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -295,25 +295,25 @@
stroke: 0x000000,
strokeThickness: 3
}));
textGraphics.anchor.set(0.5, 0.5);
- // Enhanced movement properties based on level - reduced difficulty
+ // Enhanced movement properties based on level - moderate difficulty
self.baseSpeed = getAttackSpeed(level);
self.speed = self.baseSpeed;
- self.acceleration = 0.05 + (level - 1) * 0.02; // Much slower acceleration
- self.maxSpeed = self.baseSpeed * 1.5; // Can only accelerate up to 1.5x base speed instead of 2x
+ self.acceleration = 0.08 + (level - 1) * 0.03; // Moderate acceleration
+ self.maxSpeed = self.baseSpeed * 1.8; // Can accelerate up to 1.8x base speed
// Movement pattern selection (more predictable patterns at lower levels)
self.movementPattern = Math.floor(Math.random() * Math.min(3, level)); // Reduced max patterns
// 0: Basic straight, 1: Zigzag, 2: Pursuit, 3: Spiral (removed erratic)
// Pattern-specific properties
- self.speedX = (Math.random() - 0.5) * (2 + level * 1); // Reduced horizontal movement
+ self.speedX = (Math.random() - 0.5) * (3 + level * 1.5); // Moderate horizontal movement
self.speedY = self.speed;
- self.waveAmplitude = Math.random() * (10 + level * 5) + 5; // Smaller wave amplitude
- self.waveFrequency = Math.random() * 0.04 + 0.02 + level * 0.01; // Slower wave frequency
+ self.waveAmplitude = Math.random() * (15 + level * 8) + 8; // Moderate wave amplitude
+ self.waveFrequency = Math.random() * 0.06 + 0.03 + level * 0.015; // Moderate wave frequency
self.animTimer = Math.random() * Math.PI * 2;
- self.directionChangeTimer = Math.random() * (1200 - level * 50) + 400; // Less frequent direction changes
+ self.directionChangeTimer = Math.random() * (1000 - level * 60) + 350; // Moderate direction changes
self.maxDirectionChangeTimer = self.directionChangeTimer;
- self.pursuitStrength = 0.15 + (level - 1) * 0.08; // Much weaker pursuit
+ self.pursuitStrength = 0.25 + (level - 1) * 0.12; // Moderate pursuit strength
self.lastHeartX = heart.x;
self.lastHeartY = heart.y;
self.update = function () {
// Get current heart position for pursuit calculations
@@ -326,43 +326,43 @@
}
// Movement pattern execution - simplified and less aggressive
switch (self.movementPattern) {
case 0:
- // Basic straight movement with minimal tracking
+ // Basic straight movement with moderate tracking
self.y += self.speedY;
- // Very slight horizontal drift toward heart - reduced
+ // Moderate horizontal drift toward heart
var heartDirection = heartX > self.x ? 1 : -1;
- self.x += heartDirection * (level * 0.2); // Reduced from 0.5 to 0.2
+ self.x += heartDirection * (level * 0.35); // Moderate tracking
break;
case 1:
- // Simple zigzag with less pursuit
+ // Zigzag with moderate pursuit
self.y += self.speedY;
self.animTimer += self.waveFrequency;
- self.x += Math.sin(self.animTimer) * self.waveAmplitude * 0.1; // Reduced from 0.2 to 0.1
- // Minimal pursuit element
- var pursuitX = (heartX - self.x) * self.pursuitStrength * 0.05; // Reduced from 0.1 to 0.05
+ self.x += Math.sin(self.animTimer) * self.waveAmplitude * 0.15; // Moderate zigzag intensity
+ // Moderate pursuit element
+ var pursuitX = (heartX - self.x) * self.pursuitStrength * 0.08; // Moderate pursuit
self.x += pursuitX;
break;
case 2:
- // Gentler pursuit - less aggressive
+ // Moderate pursuit - balanced aggression
var deltaX = heartX - self.x;
var deltaY = heartY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
- self.x += deltaX / distance * self.speed * self.pursuitStrength * 0.5; // Reduced pursuit by half
- self.y += deltaY / distance * self.speed * self.pursuitStrength * 0.3; // Reduced vertical pursuit
+ self.x += deltaX / distance * self.speed * self.pursuitStrength * 0.7; // Moderate pursuit
+ self.y += deltaY / distance * self.speed * self.pursuitStrength * 0.45; // Moderate vertical pursuit
}
- // Still move generally downward - more predictable
- self.y += self.speedY * 0.8; // Increased from 0.7 to 0.8 for more predictable downward movement
+ // Still move generally downward but less predictable
+ self.y += self.speedY * 0.75; // Moderate downward movement
break;
case 3:
- // Simple spiral pattern with minimal pursuit
- self.y += self.speedY * 0.9; // More predictable downward movement
+ // Spiral pattern with moderate pursuit
+ self.y += self.speedY * 0.85; // Moderate downward movement
self.animTimer += self.waveFrequency;
- var spiralRadius = 20 + Math.sin(self.animTimer * 0.3) * 10; // Smaller spiral
- self.x += Math.cos(self.animTimer) * spiralRadius * 0.08; // Reduced spiral intensity
- // Very minimal drift toward heart
- var driftX = (heartX - self.x) * 0.02; // Reduced from 0.05 to 0.02
+ var spiralRadius = 25 + Math.sin(self.animTimer * 0.3) * 15; // Moderate spiral
+ self.x += Math.cos(self.animTimer) * spiralRadius * 0.12; // Moderate spiral intensity
+ // Moderate drift toward heart
+ var driftX = (heartX - self.x) * 0.035; // Moderate drift
self.x += driftX;
break;
}
// Enhanced boundary behavior - some attacks can bounce