User prompt
Okey quiero que arregles que el texto de arriba de los diálogos se ponga por encima de la barra de ansiedad y credibilidad
User prompt
Así está bien
User prompt
Puedes quitar el cuadro de texto que sale aveces? no me gusta eso
User prompt
Bueno arreglalo jajaj
User prompt
Vuelve a intentar
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'parent')' in or related to this line: 'if (!ansiedadBarBg.parent) {' Line Number: 317
User prompt
bien quiero que los ataques sean un poco más rápidos. Te voy a tratar de comunicar toda la idea de una vez. Quiero que el juego tenga 5 niveles y quiero que sea un estilo narrativo que salgan dialogos de texto antes de empezar el nivel en parte superior de la pantalla, que vaya contanto la historia de un tutor que va avanzando en sus tutorias donde a medida que avanza con los niveles sea más dificiles de esquivar los ataques ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
Perfecto, te decia que quiero que los ataques tengan unos bordes bien definidos, en este caso no lo tienen aún, tambien quiero haya palabras que vengan hacia el jugador pero en color verde y que suban la barra de credibilidad
User prompt
Try again
User prompt
You are UPIT’s AI assistant. I have an existing prototype for a 2D “Undertale‐style” tutor training game in JavaScript using the LK framework. Please refactor and adapt the code to focus exclusively on: 1. **Core Classes** - Keep only the `Heart`, `TextAttack`, and `TechniqueMenu` classes. - Remove all other attack/enemy classes (`CyanAreaAttack`, `LaserAttack`, `Enemy`) and their assets. 2. **Define Constants** - Extract all “magic numbers” into descriptive constants at the top of the file, for example: ```js const ATTACK_INTERVAL = 90; const LEVEL_DIFF = 5; const MENU_INTERVAL = 600; const ANSIEDAD_RATE = 180; const ANSIEDAD_PASSIVE = 2; const MAX_LEVEL = 10; const WIN_CRED = 60; const SCORE_RATE = 60; const SCORE_PER_LEVEL = 50; const LEVEL_CRED_BOOST = 5; const GAME_LEFT = 300; const GAME_RIGHT = 1748; const GAME_TOP = 200; const GAME_BOTTOM = 2732; const GAME_WIDTH = GAME_RIGHT - GAME_LEFT; ``` 3. **UI Initialization** - Retain the UI setup for `ansiedad`, `credibilidad`, level text, and implement `initializeUI()` and `updateBars()` functions as before. 4. **Keyboard Controls** - Add `window.addEventListener('keydown', ...)` and `keyup` handlers for `ArrowLeft` and `ArrowRight` to control the heart movement, in addition to touch input. 5. **Simplify Game Update Loop** - Replace the current multi-attack logic with only `TextAttack` spawning and collision detection: - Spawn a `TextAttack` every `ATTACK_INTERVAL - level * LEVEL_DIFF` ticks. - Move and destroy off-screen attacks. - Detect `heart.intersects(atk)` to call `heart.takeDamage()`. - Show the `TechniqueMenu` every `MENU_INTERVAL` ticks. - Increase `ansiedad` passively every `ANSIEDAD_RATE` ticks by `ANSIEDAD_PASSIVE`. - Update score every `SCORE_RATE` ticks; increment `level` when score ≥ `level * SCORE_PER_LEVEL`, then boost `credibilidad` by `LEVEL_CRED_BOOST`. - Check for game over when `ansiedad >= 100` and win when `level >= MAX_LEVEL && credibilidad >= WIN_CRED`. 6. **Modularize (Optional)** - If possible, separate stats management and attack spawning into `StatsManager` and `AttackSpawner` modules. Provide the complete refactored JavaScript code snippet using the LK framework, with comments explaining each change. All in‐game text and UI labels should remain in Spanish.``` ::contentReference[oaicite:0]{index=0}
Remix started
Copy Undertale
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
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 = 8;
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
if (self.x < GAME_LEFT + 60) {
self.x = GAME_LEFT + 60;
}
if (self.x > GAME_RIGHT - 60) {
self.x = GAME_RIGHT - 60;
}
};
self.takeDamage = function (amount) {
if (amount === undefined) amount = 10;
self.health = Math.max(0, self.health - amount);
// Flash red effect
tween(self, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
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 = 600;
bg.height = 400;
bg.tint = 0x333333;
// Title
var title = self.addChild(new Text2('Técnica de Relajación', {
size: 32,
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: 28,
fill: 0x00ff00
}));
techniqueText.anchor.set(0.5, 0.5);
techniqueText.y = -50;
// Instructions
var instruction = self.addChild(new Text2('Toca para aplicar', {
size: 24,
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: 40,
fill: 0xff0000
}));
textGraphics.anchor.set(0.5, 0.5);
self.speed = 3;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game Constants
var ATTACK_INTERVAL = 90;
var LEVEL_DIFF = 5;
var MENU_INTERVAL = 600;
var ANSIEDAD_RATE = 180;
var ANSIEDAD_PASSIVE = 2;
var MAX_LEVEL = 10;
var WIN_CRED = 60;
var SCORE_RATE = 60;
var SCORE_PER_LEVEL = 50;
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;
// Game state management
var gameState = 'menu'; // 'menu' or 'playing'
var menuContainer = game.addChild(new Container());
// Game variables
var level = 1;
var score = 0;
var ansiedad = 0;
var credibilidad = 50;
// UI Elements
var ansiedadBarBg, ansiedadBar, credibilidadBarBg, credibilidadBar;
var levelText, scoreText;
// Initialize UI
function initializeUI() {
// Ansiedad bar
ansiedadBarBg = LK.gui.topLeft.addChild(LK.getAsset('ansiedadBarBg', {
anchorX: 0,
anchorY: 0
}));
ansiedadBarBg.x = 120;
ansiedadBarBg.y = 50;
ansiedadBar = LK.gui.topLeft.addChild(LK.getAsset('ansiedadBar', {
anchorX: 0,
anchorY: 0
}));
ansiedadBar.x = 120;
ansiedadBar.y = 50;
// Credibilidad bar
credibilidadBarBg = LK.gui.topLeft.addChild(LK.getAsset('credibilidadBarBg', {
anchorX: 0,
anchorY: 0
}));
credibilidadBarBg.x = 120;
credibilidadBarBg.y = 90;
credibilidadBar = LK.gui.topLeft.addChild(LK.getAsset('credibilidadBar', {
anchorX: 0,
anchorY: 0
}));
credibilidadBar.x = 120;
credibilidadBar.y = 90;
// Text labels
var ansiedadLabel = LK.gui.topLeft.addChild(new Text2('Ansiedad', {
size: 20,
fill: 0xffffff
}));
ansiedadLabel.x = 10;
ansiedadLabel.y = 60;
var credibilidadLabel = LK.gui.topLeft.addChild(new Text2('Credibilidad', {
size: 20,
fill: 0xffffff
}));
credibilidadLabel.x = 10;
credibilidadLabel.y = 100;
// Level and score
levelText = LK.gui.topRight.addChild(new Text2('Nivel: 1', {
size: 24,
fill: 0xffffff
}));
levelText.anchor.set(1, 0);
levelText.x = -20;
levelText.y = 50;
scoreText = LK.gui.topRight.addChild(new Text2('Puntos: 0', {
size: 24,
fill: 0xffffff
}));
scoreText.anchor.set(1, 0);
scoreText.x = -20;
scoreText.y = 80;
}
function updateBars() {
// Update bar widths based on values
ansiedadBar.width = ansiedad / 100 * 300;
credibilidadBar.width = credibilidad / 100 * 300;
// Update text
levelText.setText('Nivel: ' + level);
scoreText.setText('Puntos: ' + score);
}
// Create menu elements
var logo = menuContainer.addChild(LK.getAsset('breathingSprite3', {
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.x = 2048 / 2;
playButton.y = 2732 / 2 + 100;
// Play button text
var playText = menuContainer.addChild(new Text2('JUGAR', {
size: 70,
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) {
// Start the game
gameState = 'playing';
menuContainer.visible = false;
// Initialize and show UI
initializeUI();
updateBars();
// Show game elements
heart.visible = true;
};
// Create the heart character
var heart = game.addChild(new Heart());
heart.x = 2048 / 2;
heart.y = GAME_BOTTOM - 100;
heart.visible = false;
// Keyboard controls
window.addEventListener('keydown', function (event) {
if (gameState !== 'playing') return;
switch (event.code) {
case 'ArrowLeft':
heart.isMovingLeft = true;
break;
case 'ArrowRight':
heart.isMovingRight = true;
break;
}
});
window.addEventListener('keyup', function (event) {
if (gameState !== 'playing') return;
switch (event.code) {
case 'ArrowLeft':
heart.isMovingLeft = false;
break;
case 'ArrowRight':
heart.isMovingRight = false;
break;
}
});
// Touch controls for mobile
game.move = function (x, y, obj) {
if (gameState === 'playing') {
// 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 === 'playing') {
heart.isMovingLeft = false;
heart.isMovingRight = false;
}
};
// Game arrays and timers
var textAttacks = [];
var techniqueMenus = [];
var attackTimer = 0;
var menuTimer = 0;
var ansiedadTimer = 0;
var scoreTimer = 0;
// Main game update loop
game.update = function () {
// Only update game logic when playing
if (gameState !== 'playing') return;
// Spawn TextAttack
attackTimer++;
var spawnInterval = ATTACK_INTERVAL - level * LEVEL_DIFF;
if (attackTimer >= spawnInterval) {
var textAttack = new TextAttack();
textAttack.x = GAME_LEFT + Math.random() * GAME_WIDTH;
textAttack.y = GAME_TOP;
textAttacks.push(textAttack);
game.addChild(textAttack);
attackTimer = 0;
}
// Update and check TextAttack collisions
for (var i = textAttacks.length - 1; i >= 0; i--) {
var atk = textAttacks[i];
// Check collision with heart
if (atk.intersects(heart)) {
heart.takeDamage(15);
ansiedad = Math.min(100, ansiedad + 10);
updateBars();
atk.destroy();
textAttacks.splice(i, 1);
continue;
}
// Remove off-screen attacks
if (atk.y > GAME_BOTTOM + 100) {
atk.destroy();
textAttacks.splice(i, 1);
}
}
// Show TechniqueMenu
menuTimer++;
if (menuTimer >= MENU_INTERVAL) {
var techniqueMenu = new TechniqueMenu();
techniqueMenu.x = 2048 / 2;
techniqueMenu.y = 2732 / 2;
techniqueMenus.push(techniqueMenu);
game.addChild(techniqueMenu);
menuTimer = 0;
}
// Update technique menus
for (var j = techniqueMenus.length - 1; j >= 0; j--) {
var menu = techniqueMenus[j];
if (!menu.parent) {
techniqueMenus.splice(j, 1);
}
}
// Increase ansiedad passively
ansiedadTimer++;
if (ansiedadTimer >= ANSIEDAD_RATE) {
ansiedad = Math.min(100, ansiedad + ANSIEDAD_PASSIVE);
updateBars();
ansiedadTimer = 0;
}
// Update score and level
scoreTimer++;
if (scoreTimer >= SCORE_RATE) {
score++;
// Check for level up
if (score >= level * SCORE_PER_LEVEL) {
level++;
credibilidad = Math.min(100, credibilidad + LEVEL_CRED_BOOST);
}
updateBars();
scoreTimer = 0;
}
// Check game over
if (ansiedad >= 100) {
LK.showGameOver();
}
// Check win condition
if (level >= MAX_LEVEL && credibilidad >= WIN_CRED) {
LK.showYouWin();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -5,172 +5,121 @@
/****
* Classes
****/
-var Character = Container.expand(function () {
+var Heart = Container.expand(function () {
var self = Container.call(this);
- var characterGraphics = self.attachAsset('character', {
+ var heartGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
- // Target position for smooth movement
- self.targetX = 0;
- self.targetY = 0;
- // Movement speed factor for smooth following
- self.followSpeed = 0.15;
- // Square boundary limits (centered square area)
- var squareSize = 1200;
- var centerX = 2048 / 2;
- var centerY = 2732 / 2;
- self.boundaryLeft = centerX - squareSize / 2;
- self.boundaryRight = centerX + squareSize / 2;
- self.boundaryTop = centerY - squareSize / 2;
- self.boundaryBottom = centerY + squareSize / 2;
- var characterRadius = 60;
+ // Movement properties
+ self.speed = 8;
+ self.isMovingLeft = false;
+ self.isMovingRight = false;
+ // Health
+ self.health = 100;
self.update = function () {
- // Calculate next position
- var deltaX = self.targetX - self.x;
- var deltaY = self.targetY - self.y;
- var nextX = self.x + deltaX * self.followSpeed;
- var nextY = self.y + deltaY * self.followSpeed;
- // Check wall collisions and prevent movement beyond boundaries
- if (nextX - characterRadius < self.boundaryLeft) {
- nextX = self.boundaryLeft + characterRadius;
+ // Keyboard movement
+ if (self.isMovingLeft) {
+ self.x -= self.speed;
}
- if (nextX + characterRadius > self.boundaryRight) {
- nextX = self.boundaryRight - characterRadius;
+ if (self.isMovingRight) {
+ self.x += self.speed;
}
- if (nextY - characterRadius < self.boundaryTop) {
- nextY = self.boundaryTop + characterRadius;
+ // Boundary checking
+ if (self.x < GAME_LEFT + 60) {
+ self.x = GAME_LEFT + 60;
}
- if (nextY + characterRadius > self.boundaryBottom) {
- nextY = self.boundaryBottom - characterRadius;
+ if (self.x > GAME_RIGHT - 60) {
+ self.x = GAME_RIGHT - 60;
}
- // Apply the constrained position
- self.x = nextX;
- self.y = nextY;
};
- // Method to set target position
- self.setTarget = function (x, y) {
- self.targetX = x;
- self.targetY = y;
+ self.takeDamage = function (amount) {
+ if (amount === undefined) amount = 10;
+ self.health = Math.max(0, self.health - amount);
+ // Flash red effect
+ tween(self, {
+ tint: 0xff0000
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ tween(self, {
+ tint: 0xffffff
+ }, {
+ duration: 200
+ });
+ }
+ });
+ if (self.health <= 0) {
+ LK.showGameOver();
+ }
};
return self;
});
-var CyanAreaAttack = Container.expand(function () {
+var TechniqueMenu = Container.expand(function () {
var self = Container.call(this);
- var attackGraphics = self.attachAsset('cyanAreaAttack', {
- anchorX: 0,
+ // Background
+ var bg = self.addChild(LK.getAsset('playButton', {
+ anchorX: 0.5,
anchorY: 0.5
- });
+ }));
+ bg.width = 600;
+ bg.height = 400;
+ bg.tint = 0x333333;
+ // Title
+ var title = self.addChild(new Text2('Técnica de Relajación', {
+ size: 32,
+ 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: 28,
+ fill: 0x00ff00
+ }));
+ techniqueText.anchor.set(0.5, 0.5);
+ techniqueText.y = -50;
+ // Instructions
+ var instruction = self.addChild(new Text2('Toca para aplicar', {
+ size: 24,
+ fill: 0xcccccc
+ }));
+ instruction.anchor.set(0.5, 0.5);
+ instruction.y = 20;
self.duration = 0;
self.maxDuration = 3000; // 3 seconds
- self.isActive = false;
- self.startX = -600; // Start from left side of combat box
- self.endX = 1200; // End at right side of combat box
- self.speed = 5; // Movement speed from left to right
- // Start with low alpha and fade in
- attackGraphics.alpha = 0;
- // Position at left edge initially
- self.x = self.startX;
self.update = function () {
self.duration += 16.67;
- // Move from left to right across combat box
- if (self.duration > 500 && self.x < self.endX + 600) {
- // Move until completely off screen
- self.x += self.speed;
+ if (self.duration >= self.maxDuration) {
+ self.destroy();
}
- // Fade in effect at the beginning
- if (self.duration < 500) {
- attackGraphics.alpha = self.duration / 500 * 0.6; // Max alpha of 0.6
- } else if (self.x < self.endX + 600) {
- // Stay visible and active while crossing combat box
- attackGraphics.alpha = 0.6;
- self.isActive = true;
- } else {
- // Mark as finished when completely crossed
- self.isActive = false;
- attackGraphics.alpha = 0;
- }
};
- return self;
-});
-var Enemy = Container.expand(function () {
- var self = Container.call(this);
- var enemyGraphics = self.attachAsset('enemy', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- self.speed = 8;
- self.targetX = 0;
- self.targetY = 0;
- self.update = function () {
- // Move toward target (player)
- var deltaX = self.targetX - self.x;
- var deltaY = self.targetY - self.y;
- var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- if (distance > 0) {
- self.x += deltaX / distance * self.speed;
- self.y += deltaY / distance * self.speed;
- }
- // Add rotation effect (visual only, doesn't affect movement)
- enemyGraphics.rotation += 0.1;
+ self.down = function () {
+ // Apply technique - boost credibilidad
+ credibilidad = Math.min(100, credibilidad + 15);
+ updateBars();
+ self.destroy();
};
- self.setTarget = function (x, y) {
- self.targetX = x;
- self.targetY = y;
- };
return self;
});
-var LaserAttack = Container.expand(function () {
+var TextAttack = Container.expand(function () {
var self = Container.call(this);
- var chargerGraphics = self.attachAsset('laserCharger', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- self.targetX = 0;
- self.targetY = 0;
- self.state = 'charging'; // 'charging', 'firing', 'finished'
- self.chargeTime = 0;
- self.fireTime = 0;
- self.laserBeam = null;
- self.hasDealtDamage = false;
+ // 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: 40,
+ fill: 0xff0000
+ }));
+ textGraphics.anchor.set(0.5, 0.5);
+ self.speed = 3;
self.update = function () {
- if (self.state === 'charging') {
- self.chargeTime += 16.67;
- // Charging animation - pulsing effect
- chargerGraphics.alpha = 0.5 + 0.5 * Math.sin(self.chargeTime * 0.01);
- if (self.chargeTime >= 1200) {
- // 1.2 seconds
- self.state = 'firing';
- self.fireLaser();
- }
- } else if (self.state === 'firing') {
- self.fireTime += 16.67;
- if (self.fireTime >= 3000) {
- // 3 seconds
- self.state = 'finished';
- }
- }
+ self.y += self.speed;
};
- self.fireLaser = function () {
- // Hide charger
- chargerGraphics.alpha = 0;
- // Create laser beam
- self.laserBeam = self.addChild(LK.getAsset('laserAttack', {
- anchorX: 0,
- anchorY: 0.5
- }));
- // Position laser to fire across the screen toward target
- var angle = Math.atan2(self.targetY - self.y, self.targetX - self.x);
- self.laserBeam.rotation = angle;
- self.laserBeam.x = 0;
- self.laserBeam.y = 0;
- };
- self.setTarget = function (x, y) {
- self.targetX = x;
- self.targetY = y;
- };
return self;
});
/****
@@ -182,11 +131,100 @@
/****
* Game Code
****/
+// Game Constants
+var ATTACK_INTERVAL = 90;
+var LEVEL_DIFF = 5;
+var MENU_INTERVAL = 600;
+var ANSIEDAD_RATE = 180;
+var ANSIEDAD_PASSIVE = 2;
+var MAX_LEVEL = 10;
+var WIN_CRED = 60;
+var SCORE_RATE = 60;
+var SCORE_PER_LEVEL = 50;
+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;
// Game state management
var gameState = 'menu'; // 'menu' or 'playing'
var menuContainer = game.addChild(new Container());
+// Game variables
+var level = 1;
+var score = 0;
+var ansiedad = 0;
+var credibilidad = 50;
+// UI Elements
+var ansiedadBarBg, ansiedadBar, credibilidadBarBg, credibilidadBar;
+var levelText, scoreText;
+// Initialize UI
+function initializeUI() {
+ // Ansiedad bar
+ ansiedadBarBg = LK.gui.topLeft.addChild(LK.getAsset('ansiedadBarBg', {
+ anchorX: 0,
+ anchorY: 0
+ }));
+ ansiedadBarBg.x = 120;
+ ansiedadBarBg.y = 50;
+ ansiedadBar = LK.gui.topLeft.addChild(LK.getAsset('ansiedadBar', {
+ anchorX: 0,
+ anchorY: 0
+ }));
+ ansiedadBar.x = 120;
+ ansiedadBar.y = 50;
+ // Credibilidad bar
+ credibilidadBarBg = LK.gui.topLeft.addChild(LK.getAsset('credibilidadBarBg', {
+ anchorX: 0,
+ anchorY: 0
+ }));
+ credibilidadBarBg.x = 120;
+ credibilidadBarBg.y = 90;
+ credibilidadBar = LK.gui.topLeft.addChild(LK.getAsset('credibilidadBar', {
+ anchorX: 0,
+ anchorY: 0
+ }));
+ credibilidadBar.x = 120;
+ credibilidadBar.y = 90;
+ // Text labels
+ var ansiedadLabel = LK.gui.topLeft.addChild(new Text2('Ansiedad', {
+ size: 20,
+ fill: 0xffffff
+ }));
+ ansiedadLabel.x = 10;
+ ansiedadLabel.y = 60;
+ var credibilidadLabel = LK.gui.topLeft.addChild(new Text2('Credibilidad', {
+ size: 20,
+ fill: 0xffffff
+ }));
+ credibilidadLabel.x = 10;
+ credibilidadLabel.y = 100;
+ // Level and score
+ levelText = LK.gui.topRight.addChild(new Text2('Nivel: 1', {
+ size: 24,
+ fill: 0xffffff
+ }));
+ levelText.anchor.set(1, 0);
+ levelText.x = -20;
+ levelText.y = 50;
+ scoreText = LK.gui.topRight.addChild(new Text2('Puntos: 0', {
+ size: 24,
+ fill: 0xffffff
+ }));
+ scoreText.anchor.set(1, 0);
+ scoreText.x = -20;
+ scoreText.y = 80;
+}
+function updateBars() {
+ // Update bar widths based on values
+ ansiedadBar.width = ansiedad / 100 * 300;
+ credibilidadBar.width = credibilidad / 100 * 300;
+ // Update text
+ levelText.setText('Nivel: ' + level);
+ scoreText.setText('Puntos: ' + score);
+}
// Create menu elements
var logo = menuContainer.addChild(LK.getAsset('breathingSprite3', {
anchorX: 0.5,
anchorY: 0.5
@@ -227,433 +265,142 @@
playButton.up = function (x, y, obj) {
// Start the game
gameState = 'playing';
menuContainer.visible = false;
+ // Initialize and show UI
+ initializeUI();
+ updateBars();
// Show game elements
- leftWall.visible = true;
- rightWall.visible = true;
- topWall.visible = true;
- bottomWall.visible = true;
- character.visible = true;
- healthBarBackground.visible = true;
- healthLabel.visible = true;
- breathingSprite1.visible = true;
- breathingSprite2.visible = true;
- for (var i = 0; i < healthSegments.length; i++) {
- healthSegments[i].visible = true;
- }
+ heart.visible = true;
};
-// Create visual boundary walls
-var squareSize = 1200;
-var centerX = 2048 / 2;
-var centerY = 2732 / 2;
-var boundaryLeft = centerX - squareSize / 2;
-var boundaryRight = centerX + squareSize / 2;
-var boundaryTop = centerY - squareSize / 2;
-var boundaryBottom = centerY + squareSize / 2;
-// Left wall
-var leftWall = game.addChild(LK.getAsset('wall', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-leftWall.x = boundaryLeft;
-leftWall.y = centerY;
-leftWall.visible = false;
-// Right wall
-var rightWall = game.addChild(LK.getAsset('wall', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-rightWall.x = boundaryRight;
-rightWall.y = centerY;
-rightWall.visible = false;
-// Top wall
-var topWall = game.addChild(LK.getAsset('wallHorizontal', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-topWall.x = centerX;
-topWall.y = boundaryTop;
-topWall.visible = false;
-// Bottom wall
-var bottomWall = game.addChild(LK.getAsset('wallHorizontal', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-bottomWall.x = centerX;
-bottomWall.y = boundaryBottom;
-bottomWall.visible = false;
-// Create the character at center of screen
-var character = game.addChild(new Character());
-character.x = 2048 / 2;
-character.y = 2732 / 2;
-character.visible = false;
-// Set initial target position to character's starting position
-character.setTarget(character.x, character.y);
-// Handle mouse/touch movement
-game.move = function (x, y, obj) {
- if (gameState === 'playing') {
- // Set character target to mouse position
- character.setTarget(x, y);
- }
-};
-// Handle mouse/touch down - also update position immediately
-game.down = function (x, y, obj) {
- if (gameState === 'playing') {
- // Set character target to touch/click position
- character.setTarget(x, y);
- }
-};
-// Create health bar interface below the square
-var healthBarY = boundaryBottom + 100;
-// Health bar background
-var healthBarBackground = game.addChild(LK.getAsset('healthBarBg', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-healthBarBackground.x = centerX;
-healthBarBackground.y = healthBarY;
-healthBarBackground.visible = false;
-// Health bar segments (10 parts)
-var healthSegments = [];
-var segmentWidth = 36;
-var segmentSpacing = 2;
-var totalWidth = (segmentWidth + segmentSpacing) * 10 - segmentSpacing;
-var startX = centerX - totalWidth / 2;
-for (var i = 0; i < 10; i++) {
- var segment = game.addChild(LK.getAsset('healthSegment', {
- anchorX: 0,
- anchorY: 0.5
- }));
- segment.x = startX + i * (segmentWidth + segmentSpacing);
- segment.y = healthBarY;
- segment.tint = 0xffff00; // Yellow by default
- segment.visible = false;
- healthSegments.push(segment);
-}
-// Health bar label
-var healthLabel = new Text2('VIDA', {
- size: 30,
- fill: 0xFFFFFF
-});
-healthLabel.anchor.set(0.5, 1);
-healthLabel.x = centerX;
-healthLabel.y = healthBarY - 30;
-healthLabel.visible = false;
-game.addChild(healthLabel);
-// Health variables
-var maxHealth = 100;
-var currentHealth = 100;
-// Invulnerability system
-var isInvulnerable = false;
-var invulnerabilityDuration = 3000; // 3 seconds
-// Function to update health bar segments
-function updateHealthBar() {
- var healthSegmentsRemaining = Math.ceil(currentHealth / 10);
- for (var i = 0; i < 10; i++) {
- if (i < healthSegmentsRemaining) {
- healthSegments[i].tint = 0xffff00; // Yellow for remaining health
- } else {
- healthSegments[i].tint = 0xff0000; // Red for lost health
- }
- }
-}
-// Initial health bar update
-updateHealthBar();
-// Create breathing sprites above combat box
-var breathingSprite1 = game.addChild(LK.getAsset('breathingSprite1', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-breathingSprite1.x = centerX;
-breathingSprite1.y = boundaryTop - 300;
-breathingSprite1.visible = false;
-var breathingSprite2 = game.addChild(LK.getAsset('breathingSprite2', {
- anchorX: 0.5,
- anchorY: 0.5
-}));
-breathingSprite2.x = centerX;
-// Position sprite2 directly on top of sprite1 to form a tower
-breathingSprite2.y = breathingSprite1.y - (breathingSprite1.height / 2 + breathingSprite2.height / 2) + 200;
-breathingSprite2.visible = false;
-// Start breathing animation for both sprites
-function startBreathingAnimation() {
- // Animate first sprite
- tween(breathingSprite1, {
- y: breathingSprite1.y - 15
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(breathingSprite1, {
- y: breathingSprite1.y + 15
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: startBreathingAnimation
- });
- }
- });
- // Animate second sprite with slight delay
- LK.setTimeout(function () {
- tween(breathingSprite2, {
- y: breathingSprite2.y - 12
- }, {
- duration: 1600,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(breathingSprite2, {
- y: breathingSprite2.y + 12
- }, {
- duration: 1600,
- easing: tween.easeInOut
- });
- }
- });
- }, 200);
-}
-startBreathingAnimation();
-// Player position tracking for laser attacks
-var playerPositions = [];
-var maxStoredPositions = 3;
-// Enemy management
-var enemies = [];
-var enemySpawnTimer = 0;
-var enemySpawnInterval = 2000; // 2 seconds
-// Laser attack management
-var laserAttacks = [];
-var laserAttackTimer = 0;
-var laserAttackInterval = 10000 + Math.random() * 2000; // 10-12 seconds
-// Cyan area attack management
-var cyanAreaAttacks = [];
-var cyanAttackTimer = 0;
-var cyanAttackInterval = 20000; // 20 seconds initial spawn
-// Player movement tracking
-var lastPlayerX = character.x;
-var lastPlayerY = character.y;
-var isPlayerMoving = false;
-// Function to spawn enemy at random position outside the square
-function spawnEnemy() {
- var enemy = new Enemy();
- // Spawn at random position outside the boundary square
- var side = Math.floor(Math.random() * 4);
- switch (side) {
- case 0:
- // Top
- enemy.x = boundaryLeft + Math.random() * squareSize;
- enemy.y = boundaryTop - 100;
+// Create the heart character
+var heart = game.addChild(new Heart());
+heart.x = 2048 / 2;
+heart.y = GAME_BOTTOM - 100;
+heart.visible = false;
+// Keyboard controls
+window.addEventListener('keydown', function (event) {
+ if (gameState !== 'playing') return;
+ switch (event.code) {
+ case 'ArrowLeft':
+ heart.isMovingLeft = true;
break;
- case 1:
- // Right
- enemy.x = boundaryRight + 100;
- enemy.y = boundaryTop + Math.random() * squareSize;
+ case 'ArrowRight':
+ heart.isMovingRight = true;
break;
- case 2:
- // Bottom
- enemy.x = boundaryLeft + Math.random() * squareSize;
- enemy.y = boundaryBottom + 100;
- break;
- case 3:
- // Left
- enemy.x = boundaryLeft - 100;
- enemy.y = boundaryTop + Math.random() * squareSize;
- break;
}
- enemy.setTarget(character.x, character.y);
- enemies.push(enemy);
- game.addChild(enemy);
-}
-// Function to spawn laser attack targeting player's previous positions
-function spawnLaserAttack() {
- if (playerPositions.length === 0) return;
- // Choose a random previous position to target
- var targetIndex = Math.floor(Math.random() * playerPositions.length);
- var targetPos = playerPositions[targetIndex];
- var laserAttack = new LaserAttack();
- // Position laser attack outside the combat box
- var side = Math.floor(Math.random() * 4);
- switch (side) {
- case 0:
- // Top
- laserAttack.x = boundaryLeft + Math.random() * squareSize;
- laserAttack.y = boundaryTop - 150;
+});
+window.addEventListener('keyup', function (event) {
+ if (gameState !== 'playing') return;
+ switch (event.code) {
+ case 'ArrowLeft':
+ heart.isMovingLeft = false;
break;
- case 1:
- // Right
- laserAttack.x = boundaryRight + 150;
- laserAttack.y = boundaryTop + Math.random() * squareSize;
+ case 'ArrowRight':
+ heart.isMovingRight = false;
break;
- case 2:
- // Bottom
- laserAttack.x = boundaryLeft + Math.random() * squareSize;
- laserAttack.y = boundaryBottom + 150;
- break;
- case 3:
- // Left
- laserAttack.x = boundaryLeft - 150;
- laserAttack.y = boundaryTop + Math.random() * squareSize;
- break;
}
- laserAttack.setTarget(targetPos.x, targetPos.y);
- laserAttacks.push(laserAttack);
- game.addChild(laserAttack);
-}
-// Function to spawn cyan area attack covering the entire combat box
-function spawnCyanAreaAttack() {
- var cyanAttack = new CyanAreaAttack();
- cyanAttack.x = boundaryLeft - 600; // Start from left side
- cyanAttack.y = centerY; // Center vertically in combat box
- cyanAreaAttacks.push(cyanAttack);
- game.addChild(cyanAttack);
-}
-// Function to damage player
-function damagePlayer(damage) {
- if (damage === undefined) damage = 10; // Default 10% damage
- currentHealth = Math.max(0, currentHealth - damage);
- updateHealthBar();
- // Camera shake effect for 1.2 seconds
- var originalX = game.x;
- var originalY = game.y;
- var shakeIntensity = 10;
- var shakeDuration = 1200; // 1.2 seconds
- var shakeStartTime = Date.now();
- function shakeCamera() {
- var elapsed = Date.now() - shakeStartTime;
- if (elapsed < shakeDuration) {
- game.x = originalX + (Math.random() - 0.5) * shakeIntensity;
- game.y = originalY + (Math.random() - 0.5) * shakeIntensity;
- LK.setTimeout(shakeCamera, 16); // ~60fps
- } else {
- game.x = originalX;
- game.y = originalY;
+});
+// Touch controls for mobile
+game.move = function (x, y, obj) {
+ if (gameState === 'playing') {
+ // 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;
}
}
- shakeCamera();
- // Activate invulnerability
- isInvulnerable = true;
- // Flash character red when damaged and add blinking effect during invulnerability
- tween(character, {
- tint: 0xff0000
- }, {
- duration: 200,
- onFinish: function onFinish() {
- tween(character, {
- tint: 0xffffff
- }, {
- duration: 200,
- onFinish: function onFinish() {
- // Start blinking effect for remaining invulnerability time
- var blinkCount = 0;
- var maxBlinks = 12; // Blink for about 2.4 seconds (remaining invulnerability time)
- function blink() {
- if (blinkCount < maxBlinks && isInvulnerable) {
- character.alpha = character.alpha === 1 ? 0.3 : 1;
- blinkCount++;
- LK.setTimeout(blink, 200);
- } else {
- character.alpha = 1; // Ensure character is fully visible
- }
- }
- blink();
- }
- });
- }
- });
- // Set timeout to end invulnerability
- LK.setTimeout(function () {
- isInvulnerable = false;
- character.alpha = 1; // Ensure character is fully visible
- }, invulnerabilityDuration);
- // Check game over - when all 10 segments are red (health is 0)
- if (currentHealth <= 0) {
- LK.showGameOver();
+};
+game.up = function (x, y, obj) {
+ if (gameState === 'playing') {
+ heart.isMovingLeft = false;
+ heart.isMovingRight = false;
}
-}
+};
+// Game arrays and timers
+var textAttacks = [];
+var techniqueMenus = [];
+var attackTimer = 0;
+var menuTimer = 0;
+var ansiedadTimer = 0;
+var scoreTimer = 0;
// Main game update loop
game.update = function () {
// Only update game logic when playing
if (gameState !== 'playing') return;
- // Track player movement
- var deltaX = character.x - lastPlayerX;
- var deltaY = character.y - lastPlayerY;
- var movementThreshold = 1; // Minimum movement to consider as "moving"
- isPlayerMoving = Math.abs(deltaX) > movementThreshold || Math.abs(deltaY) > movementThreshold;
- lastPlayerX = character.x;
- lastPlayerY = character.y;
- // Track player positions for laser attacks
- if (LK.ticks % 10 === 0) {
- // Store position every 10 ticks
- playerPositions.push({
- x: character.x,
- y: character.y
- });
- if (playerPositions.length > maxStoredPositions) {
- playerPositions.shift(); // Remove oldest position
+ // Spawn TextAttack
+ attackTimer++;
+ var spawnInterval = ATTACK_INTERVAL - level * LEVEL_DIFF;
+ if (attackTimer >= spawnInterval) {
+ var textAttack = new TextAttack();
+ textAttack.x = GAME_LEFT + Math.random() * GAME_WIDTH;
+ textAttack.y = GAME_TOP;
+ textAttacks.push(textAttack);
+ game.addChild(textAttack);
+ attackTimer = 0;
+ }
+ // Update and check TextAttack collisions
+ for (var i = textAttacks.length - 1; i >= 0; i--) {
+ var atk = textAttacks[i];
+ // Check collision with heart
+ if (atk.intersects(heart)) {
+ heart.takeDamage(15);
+ ansiedad = Math.min(100, ansiedad + 10);
+ updateBars();
+ atk.destroy();
+ textAttacks.splice(i, 1);
+ continue;
}
+ // Remove off-screen attacks
+ if (atk.y > GAME_BOTTOM + 100) {
+ atk.destroy();
+ textAttacks.splice(i, 1);
+ }
}
- // Enemy spawning
- enemySpawnTimer += 16.67; // Approximate milliseconds per frame at 60fps
- if (enemySpawnTimer >= enemySpawnInterval) {
- spawnEnemy();
- enemySpawnTimer = 0;
- enemySpawnInterval = 2000; // Reset to 2 seconds
+ // Show TechniqueMenu
+ menuTimer++;
+ if (menuTimer >= MENU_INTERVAL) {
+ var techniqueMenu = new TechniqueMenu();
+ techniqueMenu.x = 2048 / 2;
+ techniqueMenu.y = 2732 / 2;
+ techniqueMenus.push(techniqueMenu);
+ game.addChild(techniqueMenu);
+ menuTimer = 0;
}
- // Laser attack spawning
- laserAttackTimer += 16.67;
- if (laserAttackTimer >= laserAttackInterval) {
- spawnLaserAttack();
- laserAttackTimer = 0;
- laserAttackInterval = 10000 + Math.random() * 2000; // Random 10-12 seconds
+ // Update technique menus
+ for (var j = techniqueMenus.length - 1; j >= 0; j--) {
+ var menu = techniqueMenus[j];
+ if (!menu.parent) {
+ techniqueMenus.splice(j, 1);
+ }
}
- // Cyan area attack spawning - every 20 seconds
- cyanAttackTimer += 16.67;
- if (cyanAttackTimer >= cyanAttackInterval) {
- spawnCyanAreaAttack();
- cyanAttackTimer = 0;
- cyanAttackInterval = 20000; // Every 20 seconds
+ // Increase ansiedad passively
+ ansiedadTimer++;
+ if (ansiedadTimer >= ANSIEDAD_RATE) {
+ ansiedad = Math.min(100, ansiedad + ANSIEDAD_PASSIVE);
+ updateBars();
+ ansiedadTimer = 0;
}
- // Update cyan area attacks and check collisions
- for (var k = cyanAreaAttacks.length - 1; k >= 0; k--) {
- var cyanAttack = cyanAreaAttacks[k];
- // Check collision with player only if player is moving and attack is active
- if (cyanAttack.isActive && cyanAttack.intersects(character) && isPlayerMoving && !isInvulnerable) {
- damagePlayer(10); // 10% damage
+ // Update score and level
+ scoreTimer++;
+ if (scoreTimer >= SCORE_RATE) {
+ score++;
+ // Check for level up
+ if (score >= level * SCORE_PER_LEVEL) {
+ level++;
+ credibilidad = Math.min(100, credibilidad + LEVEL_CRED_BOOST);
}
- // Remove finished cyan area attacks when they've crossed the combat box
- if (cyanAttack.x >= cyanAttack.endX + 600) {
- cyanAttack.destroy();
- cyanAreaAttacks.splice(k, 1);
- }
+ updateBars();
+ scoreTimer = 0;
}
- // Update laser attacks and check collisions
- for (var j = laserAttacks.length - 1; j >= 0; j--) {
- var laserAttack = laserAttacks[j];
- // Check collision with player during firing state
- if (laserAttack.state === 'firing' && laserAttack.laserBeam && !laserAttack.hasDealtDamage) {
- if (laserAttack.laserBeam.intersects(character)) {
- if (!isInvulnerable) {
- damagePlayer(20); // 20% damage
- laserAttack.hasDealtDamage = true;
- }
- }
- }
- // Remove finished laser attacks
- if (laserAttack.state === 'finished') {
- laserAttack.destroy();
- laserAttacks.splice(j, 1);
- }
+ // Check game over
+ if (ansiedad >= 100) {
+ LK.showGameOver();
}
- // Update enemies and check collisions
- for (var i = enemies.length - 1; i >= 0; i--) {
- var enemy = enemies[i];
- enemy.setTarget(character.x, character.y);
- // Check collision with player
- if (enemy.intersects(character)) {
- if (!isInvulnerable) {
- damagePlayer();
- }
- // Destroy enemy regardless of invulnerability state
- enemy.destroy();
- enemies.splice(i, 1);
- }
+ // Check win condition
+ if (level >= MAX_LEVEL && credibilidad >= WIN_CRED) {
+ LK.showYouWin();
}
};
\ No newline at end of file