User prompt
La vida que se muestre en la parte superior derecha
User prompt
Muestra las vidas que le quedan a la idol, en forma de imágenes de corazones
User prompt
Haz que los BPM vayan a 120, y que el golpe a los enemigos combine con el ritmo de la música
User prompt
Elimina las letras en los recuadros y botones, solo las letras. Mantén el funcionamiento
User prompt
Haz la hitbox de los botones mas grande, solo la hitbox, no los muevas de posición
User prompt
Haz una animación de movimiento, cuando se derrote a un enemigo, la idol debe moverse un poco hacia la dirección del enemigo y luego debe volver a su posición original ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Haz a la idol y los recuadros a su alrededor un poco mas grandes
User prompt
Haz que el archivo de sonido "miss" suene cuando la idol pierde una vida, y que el sonido "error" suene cuando se falla al golpear un enemigo
User prompt
Haz que el total de vidas aparezca en la parte superior derecha de la pantalla
User prompt
Sube también un poco a la idol, que esté un poco más arriba del centro de la pantalla
User prompt
Sube el conjunto de botones un poco, para que no esté tan pegado a la parte de abajo de la pantalla
User prompt
Sepáralos un poco mas
User prompt
Haz que los botones sean mas grandes
User prompt
Ahora replica la funcionalidad del color rojo pero en color verde, abajo de la idol
User prompt
Desactiva la funcionalidad de que el botón azul se active si presiono la parte derecha de la pantalla, y que el botón amarillo se active si presiono la parte izquierda de la pantalla. Solo que se activen cuando los toque
User prompt
El botón rojo ahora mismo activa el color azul también, solo debe activar el color rojo
User prompt
Al dar click en el botón rojo se debe activar el color rojo
User prompt
Si doy click al botón rojo se activa el botón amarillo, haz que se active el botón rojo
User prompt
Ahora replica la funcionalidad del color azul pero en color rojo, arriba de la idol
User prompt
Ahora replica la funcionalidad del color azul pero en color amarillo, a la derecha de la idol
User prompt
Que desaparezca al darle click una sola vez
User prompt
Haz que cuando el enemigo esté sobre el recuadro azul a la izquierda de la idol y se presione el botón azul, el enemigo desaparezca
User prompt
Desarrollemos un solo botón. Por ahora, haz que solo exista el color azul
User prompt
El botón rojo debe activar el recuadro rojo, y el botón amarillo debe activar el recuadro amarillo
User prompt
Si presiono el botón azul, el enemigo que venga de la izquierda debe desaparecer si se encuentra dentro del recuadro de la izquierda de la idol. Así con las demás direcciones
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ActionButton = Container.expand(function (color, direction, keyText) {
var self = Container.call(this);
var assetName = color + 'Button';
var buttonGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Add invisible larger hitbox
var hitbox = LK.getAsset('beatIndicator', {
anchorX: 0.5,
anchorY: 0.5,
width: 250,
height: 180
});
hitbox.alpha = 0; // Make completely invisible
hitbox.tint = 0x000000; // Ensure it's invisible
self.addChild(hitbox);
// Key text removed - button functions without text display
self.color = color;
self.direction = direction;
self.isPressed = false;
self.activate = function () {
self.isPressed = true;
buttonGraphics.scaleX = 0.9;
buttonGraphics.scaleY = 0.9;
tween(buttonGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
// Button activation visual feedback only - enemy destruction handled in processInput
self.isPressed = false;
};
self.isEnemyInHitZone = function (enemy) {
var hitZoneSize = 200;
var centerX = 1024;
var centerY = 1366;
if (enemy.direction === 'up' && enemy.y > centerY - hitZoneSize && enemy.y < centerY + hitZoneSize) {
return true;
} else if (enemy.direction === 'down' && enemy.y > centerY - hitZoneSize && enemy.y < centerY + hitZoneSize) {
return true;
} else if (enemy.direction === 'left' && enemy.x > centerX - hitZoneSize && enemy.x < centerX + hitZoneSize) {
return true;
} else if (enemy.direction === 'right' && enemy.x > centerX - hitZoneSize && enemy.x < centerX + hitZoneSize) {
return true;
}
return false;
};
self.down = function (x, y, obj) {
self.activate();
processInput(self.direction);
updateUI();
};
return self;
});
var BeatIndicator = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('beatIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
self.pulse = function () {
graphics.scaleX = 1.5;
graphics.scaleY = 1.5;
tween(graphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
};
return self;
});
var Enemy = Container.expand(function (color, direction) {
var self = Container.call(this);
var enemyAsset = color + 'Enemy';
var graphics = self.attachAsset(enemyAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.color = color;
self.direction = direction;
self.health = 3;
self.maxHealth = 3;
self.speed = 4; // Increased base speed
self.baseSpeed = 4;
self.rhythmMultiplier = 1;
self.targetX = 1024; // Center X
self.targetY = 1200; // Center Y (matching idol position)
self.lastY = self.y;
self.lastX = self.x;
self.pulseWithBeat = function () {
tween(graphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: beatInterval / 4,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(graphics, {
scaleX: 1,
scaleY: 1
}, {
duration: beatInterval / 4,
easing: tween.easeIn
});
}
});
};
self.takeDamage = function () {
self.health--;
graphics.alpha = 0.5 + self.health / self.maxHealth * 0.5;
if (self.health <= 0) {
LK.effects.flashObject(self, 0xffffff, 300);
return true; // Enemy defeated
}
return false;
};
self.update = function () {
// Calculate rhythm-based speed - enemies move in sync with beat
var currentTime = Date.now();
var timeSinceLastBeat = (currentTime - lastBeatTime) % beatInterval;
var beatProgress = timeSinceLastBeat / beatInterval;
// Create pulsing movement that syncs with beat (faster on beat, slower between beats)
var beatSyncMultiplier = 0.5 + 0.8 * Math.abs(Math.sin(beatProgress * 2 * Math.PI));
self.rhythmMultiplier = beatSyncMultiplier;
var currentSpeed = self.baseSpeed * self.rhythmMultiplier;
// Move toward center based on direction
if (self.direction === 'up') {
self.y += currentSpeed; // Moving down from top
} else if (self.direction === 'down') {
self.y -= currentSpeed; // Moving up from bottom
} else if (self.direction === 'left') {
self.x += currentSpeed; // Moving right from left
} else if (self.direction === 'right') {
self.x -= currentSpeed; // Moving left from right
}
};
return self;
});
var InputZone = Container.expand(function (color, direction, keyText) {
var self = Container.call(this);
var assetName = color + 'Outline';
var background = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Make background transparent to show only the outline
background.alpha = 0.3;
// Key text removed - zone functions without text display
self.color = color;
self.direction = direction;
self.active = false;
self.activate = function () {
self.active = true;
background.alpha = 0.8;
tween(background, {
alpha: 0.3
}, {
duration: 300
});
};
self.getColorValue = function () {
if (self.color === 'blue') return 0x0066ff;
if (self.color === 'yellow') return 0xffff00;
if (self.color === 'red') return 0xff0000;
if (self.color === 'green') return 0x00ff00;
return 0x0066ff;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a0d33
});
/****
* Game Code
****/
// Game state variables
var gameState = 'playing'; // playing, gameOver
var lives = 3;
var score = 0;
var combo = 0;
var bpm = 120;
var beatInterval = 60 / bpm * 1000; // milliseconds per beat (500ms at 120 BPM)
var lastBeatTime = 0;
var beatTolerance = 100; // ms tolerance for timing - tighter for rhythm gameplay
// Game objects
var idol;
var enemies = [];
var beatIndicator;
var inputZones = [];
var actionButtons = [];
var hearts = [];
var enemySpawnTimer = 0;
var nextBeatTime = 0;
// Enemy configuration - blue, yellow, red and green
var enemyColors = ['blue', 'yellow', 'red', 'green'];
var enemyDirections = ['left', 'right', 'up', 'down'];
var colorDirectionMap = {
'blue': 'left',
// Blue enemies come from left
'yellow': 'right',
// Yellow enemies come from right
'red': 'up',
// Red enemies come from up
'green': 'down' // Green enemies come from down
};
var keyMappings = {
'left': 'A',
'right': 'D',
'up': 'W',
'down': 'S'
};
// Initialize background
var background = game.attachAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Initialize idol character
idol = game.addChild(LK.getAsset('idol', {
anchorX: 0.5,
anchorY: 0.5
}));
idol.x = 1024; // Center horizontally
idol.y = 1200; // Slightly above center vertically
// Initialize beat indicator
beatIndicator = game.addChild(new BeatIndicator());
beatIndicator.x = 1024;
beatIndicator.y = 150;
// Initialize input zones - blue on left, yellow on right, red on top, green on bottom
var zonePositions = [{
x: 824,
y: 1200
}, {
x: 1224,
y: 1200
}, {
x: 1024,
y: 1000
}, {
x: 1024,
y: 1400
}];
for (var i = 0; i < 4; i++) {
var zone = game.addChild(new InputZone(enemyColors[i], enemyDirections[i], keyMappings[enemyDirections[i]]));
zone.x = zonePositions[i].x;
zone.y = zonePositions[i].y;
inputZones.push(zone);
}
// Initialize action buttons at bottom of screen - blue, yellow, red and green buttons
var buttonPositions = [{
x: 824,
y: 2400
}, {
x: 1224,
y: 2400
}, {
x: 1024,
y: 2200
}, {
x: 1024,
y: 2600
}];
for (var i = 0; i < 4; i++) {
var button = game.addChild(new ActionButton(enemyColors[i], enemyDirections[i], keyMappings[enemyDirections[i]]));
button.x = buttonPositions[i].x;
button.y = buttonPositions[i].y;
actionButtons.push(button);
}
// Initialize UI
var scoreText = new Text2('Score: 0', {
size: 48,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreText);
var livesText = new Text2('Lives: 3', {
size: 48,
fill: 0xFF0000
});
livesText.anchor.set(1, 0);
LK.gui.topLeft.addChild(livesText);
var comboText = new Text2('Combo: 0', {
size: 36,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
LK.gui.top.addChild(comboText);
// Initialize hearts display
for (var h = 0; h < lives; h++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 150 + h * 80; // Position hearts horizontally with spacing
heart.y = 150;
game.addChild(heart);
hearts.push(heart);
}
// Input handling
var pressedKeys = {};
var inputBuffer = [];
function processInput(direction) {
// Check if input is on beat for bonus scoring
var currentTime = Date.now();
var timeToBeat = Math.abs((currentTime - lastBeatTime) % beatInterval - beatInterval / 2);
var isOnBeat = timeToBeat < beatTolerance;
var beatMultiplier = isOnBeat ? 2 : 1; // Double points for on-beat hits
// Find enemies of matching color that are in their corresponding color zones
var hitEnemy = null;
var minDistance = Infinity;
var hitZoneSize = 100; // Size of the color zone around center
var blueZoneX = 824; // Left zone X position
var yellowZoneX = 1224; // Right zone X position
var zoneY = 1200; // Zone Y position
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
// Check if enemy color matches the button direction and enemy is coming from correct direction
var colorMatch = false;
if (direction === 'left' && enemy.color === 'blue' && enemy.direction === 'left') colorMatch = true;
if (direction === 'right' && enemy.color === 'yellow' && enemy.direction === 'right') colorMatch = true;
if (direction === 'up' && enemy.color === 'red' && enemy.direction === 'up') colorMatch = true;
if (direction === 'down' && enemy.color === 'green' && enemy.direction === 'down') colorMatch = true;
if (colorMatch) {
// Check if enemy is within the correct color zone boundaries
var zoneX = enemy.color === 'blue' ? blueZoneX : enemy.color === 'yellow' ? yellowZoneX : 1024;
var checkZoneY = enemy.color === 'red' ? 1000 : enemy.color === 'green' ? 1400 : zoneY;
var distanceCheck = enemy.color === 'red' || enemy.color === 'green' ? Math.abs(enemy.x - zoneX) < hitZoneSize && Math.abs(enemy.y - checkZoneY) < hitZoneSize : Math.abs(enemy.x - zoneX) < hitZoneSize && Math.abs(enemy.y - zoneY) < hitZoneSize;
if (distanceCheck) {
var distance = Math.sqrt(Math.pow(enemy.x - zoneX, 2) + Math.pow(enemy.y - checkZoneY, 2));
if (distance < minDistance) {
minDistance = distance;
hitEnemy = enemy;
}
}
}
}
if (hitEnemy) {
// Animate idol movement towards enemy direction
var originalX = idol.x;
var originalY = idol.y;
var moveDistance = 50;
var targetX = originalX;
var targetY = originalY;
// Calculate movement direction based on enemy direction
if (hitEnemy.direction === 'left') {
targetX = originalX - moveDistance;
} else if (hitEnemy.direction === 'right') {
targetX = originalX + moveDistance;
} else if (hitEnemy.direction === 'up') {
targetY = originalY - moveDistance;
} else if (hitEnemy.direction === 'down') {
targetY = originalY + moveDistance;
}
// Move idol towards enemy direction
tween(idol, {
x: targetX,
y: targetY
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return idol to original position
tween(idol, {
x: originalX,
y: originalY
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
// Destroy enemy immediately on hit
var index = enemies.indexOf(hitEnemy);
if (index > -1) {
hitEnemy.destroy();
enemies.splice(index, 1);
var baseScore = 100 * (combo + 1);
score += baseScore * beatMultiplier;
combo++;
// Visual feedback for on-beat hits
if (isOnBeat) {
LK.effects.flashObject(idol, 0xffff00, 200); // Golden flash for perfect timing
}
}
LK.getSound('hit').play();
} else {
// No matching enemy found in color zone
combo = 0;
LK.getSound('error').play();
}
// Find matching input zone and activate
for (var j = 0; j < inputZones.length; j++) {
var zone = inputZones[j];
var shouldActivate = false;
// Map button directions to color zones correctly
if (direction === 'left' && zone.color === 'blue') shouldActivate = true; // Blue button activates blue zone
else if (direction === 'right' && zone.color === 'yellow') shouldActivate = true; // Yellow button activates yellow zone
else if (direction === 'up' && zone.color === 'red') shouldActivate = true; // Red button activates red zone
else if (direction === 'down' && zone.color === 'green') shouldActivate = true; // Green button activates green zone
if (shouldActivate) {
zone.activate();
break;
}
}
// Also activate corresponding action button
for (var k = 0; k < actionButtons.length; k++) {
if (actionButtons[k].direction === direction) {
actionButtons[k].activate();
break;
}
}
updateUI();
}
function updateUI() {
scoreText.setText('Score: ' + score);
livesText.setText('Lives: ' + lives);
comboText.setText('Combo: ' + combo);
// Update hearts display
for (var h = 0; h < hearts.length; h++) {
if (h < lives) {
hearts[h].alpha = 1; // Show heart
} else {
hearts[h].alpha = 0.3; // Dim lost hearts
}
}
}
function spawnEnemy() {
var colorIndex = Math.floor(Math.random() * enemyColors.length);
var color = enemyColors[colorIndex];
var direction = colorDirectionMap[color];
var enemy = game.addChild(new Enemy(color, direction));
// Position enemy at center of each edge based on direction
if (direction === 'up') {
enemy.x = 1024; // Center X of top edge
enemy.y = -100; // Above screen
} else if (direction === 'down') {
enemy.x = 1024; // Center X of bottom edge
enemy.y = 2832; // Below screen
} else if (direction === 'left') {
enemy.x = -100; // Left of screen
enemy.y = 1200; // Center Y of left edge
} else if (direction === 'right') {
enemy.x = 2148; // Right of screen
enemy.y = 1200; // Center Y of right edge
}
enemy.lastY = enemy.y;
enemy.lastX = enemy.x;
enemies.push(enemy);
}
// Touch controls removed - buttons now only activate when directly touched
game.down = function (x, y, obj) {
// Game down handler - buttons handle their own touch events
};
// Main game loop
game.update = function () {
if (gameState !== 'playing') return;
var currentTime = Date.now();
// Beat tracking
if (currentTime >= nextBeatTime) {
lastBeatTime = currentTime;
nextBeatTime = currentTime + beatInterval;
beatIndicator.pulse();
// Make all enemies pulse with the beat
for (var j = 0; j < enemies.length; j++) {
enemies[j].pulseWithBeat();
}
}
// Enemy spawning
enemySpawnTimer++;
if (enemySpawnTimer >= 90) {
// Spawn every ~1.5 seconds at 60fps
spawnEnemy();
enemySpawnTimer = 0;
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Check if enemy reached center (idol position)
var reachedCenter = false;
if (enemy.direction === 'up' && enemy.lastY < 1200 && enemy.y >= 1200) {
reachedCenter = true;
} else if (enemy.direction === 'down' && enemy.lastY > 1200 && enemy.y <= 1200) {
reachedCenter = true;
} else if (enemy.direction === 'left' && enemy.lastX < 1024 && enemy.x >= 1024) {
reachedCenter = true;
} else if (enemy.direction === 'right' && enemy.lastX > 1024 && enemy.x <= 1024) {
reachedCenter = true;
}
if (reachedCenter) {
lives--;
enemy.destroy();
enemies.splice(i, 1);
combo = 0;
LK.getSound('miss').play();
if (lives <= 0) {
gameState = 'gameOver';
LK.showGameOver();
return;
}
updateUI();
LK.effects.flashScreen(0xff0000, 500);
}
enemy.lastY = enemy.y;
enemy.lastX = enemy.x;
}
};
// Touch controls are already implemented above in game.down event handler
// No keyboard input needed for mobile-optimized game
// Start background music
LK.playMusic('bgmusic');
// Initialize beat timing
nextBeatTime = Date.now() + beatInterval;
; ===================================================================
--- original.js
+++ change.js
@@ -203,8 +203,9 @@
var enemies = [];
var beatIndicator;
var inputZones = [];
var actionButtons = [];
+var hearts = [];
var enemySpawnTimer = 0;
var nextBeatTime = 0;
// Enemy configuration - blue, yellow, red and green
var enemyColors = ['blue', 'yellow', 'red', 'green'];
@@ -300,8 +301,19 @@
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
LK.gui.top.addChild(comboText);
+// Initialize hearts display
+for (var h = 0; h < lives; h++) {
+ var heart = LK.getAsset('heart', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ heart.x = 150 + h * 80; // Position hearts horizontally with spacing
+ heart.y = 150;
+ game.addChild(heart);
+ hearts.push(heart);
+}
// Input handling
var pressedKeys = {};
var inputBuffer = [];
function processInput(direction) {
@@ -419,8 +431,16 @@
function updateUI() {
scoreText.setText('Score: ' + score);
livesText.setText('Lives: ' + lives);
comboText.setText('Combo: ' + combo);
+ // Update hearts display
+ for (var h = 0; h < hearts.length; h++) {
+ if (h < lives) {
+ hearts[h].alpha = 1; // Show heart
+ } else {
+ hearts[h].alpha = 0.3; // Dim lost hearts
+ }
+ }
}
function spawnEnemy() {
var colorIndex = Math.floor(Math.random() * enemyColors.length);
var color = enemyColors[colorIndex];
Flecha verde apuntando hacia abajo. In-Game asset. 2d. High contrast. No shadows
Flecha azul apuntando a la izquierda. In-Game asset. 2d. High contrast. No shadows
Flecha roja apuntando hacia arriba, con borde negro. In-Game asset. 2d. High contrast. No shadows
Flecha amarilla apuntando a la derecha. In-Game asset. 2d. High contrast. No shadows
Una mazmorra rocosa, sin contorno y de fondo se vean piedras algo difuminadas y una entrada a una mazmorra. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
Un panel cuadrado con contornos redondos, de color violeta. In-Game asset. 2d. High contrast. No shadows
Letras de color blanco, que digan "IDOL DUNGEON BEAT", que tengan un WordArt animado. En alta resolución para poner en una imagen 100 X 150 In-Game asset. 2d. High contrast. No shadows
espada dorada brillante, que da un toque de guerrera mágica o heroína valiente.. In-Game asset. 2d. High contrast. No shadows
Un recuadro blanco sin relleno interlineado. In-Game asset. 2d. High contrast. No shadows
Micrófono chibi, con un lazo rosado y una estrella como moño en el mango del micrófono. In-Game asset. 2d. High contrast. No shadows
Haz una animación en la que solo se vea su cara recortada, un aura de energía rosada rodeándola, y que aparezca como una viñeta que demuestre que está a punto de hacer su acción definitiva
Haz una animación en la que solo se vea su cara recortada, un aura de energía rosada rodeándola, y que aparezca como una viñeta que demuestre que está a punto de hacer su acción definitiva. Que escriba la palabra TWINKLE! abajo a la derecha. La imagen debe tener un fondo color blanco
Pintarlo de color verde
Recuadro de madera, parecido a un tablón de anuncios, animado. In-Game asset. 2d. High contrast. No shadows
Agrégale detalles en los ojos
Haz una animación simulando que ataca hacia la derecha con su escudo, y su mano y cuerpo debe seguir el movimiento del lanzamiento
Haz una animación simulando que ataca hacia abajo con su escudo, y su mano y cuerpo debe seguir el movimiento del golpe
Haz una animación en la que solo se vea su cara recortada, un aura de energía roja rodeándola, y que aparezca como una viñeta que demuestre que está a punto de hacer su acción definitiva. Que escriba la palabra SMILE! abajo a la derecha. La imagen debe tener un fondo color gris
hit
Sound effect
miss
Sound effect
error
Sound effect
bgmusic
Music
menuSong
Music
kasuminbgmusic
Music
ultimate
Sound effect
kasuminUltimate
Sound effect
IdolSelected
Sound effect
IdolKasuminSelected
Sound effect
maplebgmusic
Music
IdolMapleSelected
Sound effect
IdolMapleUltimate
Sound effect
hitKasumin
Sound effect
hitMaple
Sound effect