Code edit (1 edits merged)
Please save this source code
User prompt
Torre Zen 3D - Endless Tower Builder
Initial prompt
Crea un juego móvil casual offline en 3D estilo endless tower builder minimalista y adictivo. El objetivo es construir una torre lo más alta posible apilando bloques rectangulares (cuadros 3D) uno encima del otro con precisión perfecta. Estilo visual: Gráficos 3D low-poly limpios. Bloques en tonos de verde degradado (verde lima brillante arriba, verde oliva oscuro abajo para efecto de sombra). Fondo con gradiente suave: amarillo claro en la parte superior (cielo luminoso) a azul celeste en la inferior (horizonte sereno). Cámara fija frontal o isométrica, zoom out gradual al crecer la torre. Contador de niveles en texto blanco flotante simple encima del bloque superior (fuente sans-serif). Partículas blancas mínimas al apilar perfecto. Sin texturas complejas, enfoque en simplicidad y profundidad 3D con sombras suaves. Mecánica detallada: Torre inicia con un bloque base ancho (100% ancho de pantalla horizontal). Nuevo bloque aparece arriba y oscila horizontalmente (izquierda-derecha como péndulo, velocidad inicial lenta). Jugador toca pantalla cuando bloque está centrado para dropearlo verticalmente sobre la torre. Si no alineado perfecto, parte sobrante se corta ('mocha') y cae al vacío con animación (solo queda la superposición). Próximo bloque llega del tamaño reducido del último apilado. Cada apilado suma 1 punto/nivel (contador flotante aumenta). Apilados perfectos dan bonos (partículas o sonido extra). Pierdes si bloque cae sin superposición (torre colapsa con animación de bloques cayendo). Dificultad: Oscilación acelera cada 10 niveles. Power-ups ocasionales (bloque lento o reset ancho). Controles: Toque simple para dropear. Sonidos: 'whoosh' oscilando, 'thud' apilando bien, 'crack' cortando. Música ambiental electrónica que acelera con altura. Modo offline: Gameplay core sin internet. Leaderboard global online TOP 50: Accesible desde menú (botón 'Ranking'). Muestra posición (círculo dorado), avatar pequeño, username negrita blanca, score verde ('Nivel X'), 'Estado' cursiva gris-azul (editable máx. 50 chars, ej. '¡Traten de bajarme de aquí jaja!'). Editable solo por TOP 50 via popup. Diseño: Lista vertical con fondo gradiente azul-verde, fade-in animado. Usa Firebase para sync. Todo en español: menús, tutorial ('Toca cuando el bloque esté centrado para apilarlo perfecto. ¡No dejes que se corte!'). Exporta como proyecto Unity listo para App Store: offline default, online opcional para ranking. Hazlo adictivo con logros diarios y tutorial corto.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Block = Container.expand(function () {
var self = Container.call(this);
self.blockWidth = 200;
self.isMoving = true;
self.direction = 1;
self.speed = 2;
self.baseY = 0;
// Create the main block
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
// Create shadow for 3D effect
var shadowGraphics = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
scaleX: 1.1,
scaleY: 0.3
});
shadowGraphics.y = 35; // Offset shadow below block
self.setWidth = function (newWidth) {
self.blockWidth = newWidth;
blockGraphics.width = newWidth;
shadowGraphics.width = newWidth * 1.1;
};
self.setColor = function (color) {
blockGraphics.tint = color;
};
self.stopMoving = function () {
self.isMoving = false;
};
self.getOverlap = function (targetX, targetWidth) {
var leftEdge = self.x - self.blockWidth / 2;
var rightEdge = self.x + self.blockWidth / 2;
var targetLeft = targetX - targetWidth / 2;
var targetRight = targetX + targetWidth / 2;
var overlapLeft = Math.max(leftEdge, targetLeft);
var overlapRight = Math.min(rightEdge, targetRight);
if (overlapLeft >= overlapRight) {
return {
width: 0,
centerX: 0
};
}
return {
width: overlapRight - overlapLeft,
centerX: (overlapLeft + overlapRight) / 2
};
};
self.update = function () {
if (self.isMoving) {
self.x += self.speed * self.direction;
// Bounce off screen edges
if (self.x <= self.blockWidth / 2) {
self.direction = 1;
self.x = self.blockWidth / 2;
} else if (self.x >= 2048 - self.blockWidth / 2) {
self.direction = -1;
self.x = 2048 - self.blockWidth / 2;
}
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particle = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
particle.tint = 0xFFD700; // Gold color
self.velocityX = (Math.random() - 0.5) * 10;
self.velocityY = -Math.random() * 8 - 2;
self.gravity = 0.3;
self.life = 60; // 1 second at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += self.gravity;
self.life--;
self.alpha = self.life / 60;
if (self.life <= 0) {
self.destroy();
particles.splice(particles.indexOf(self), 1);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue
});
/****
* Game Code
****/
// Game state variables
var tower = [];
var currentBlock = null;
var gameRunning = true;
var level = 1;
var baseBlockWidth = 200;
var currentBlockWidth = baseBlockWidth;
var particles = [];
var perfectCount = 0;
var cameraY = 2732 / 2;
// Create gradient sky background
game.setBackgroundColor(0x87CEEB);
// UI Elements
var scoreText = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var perfectText = new Text2('', {
size: 60,
fill: 0xFFD700
});
perfectText.anchor.set(0.5, 0);
perfectText.y = 100;
LK.gui.top.addChild(perfectText);
// Create base block
function createBaseBlock() {
var baseBlock = new Block();
baseBlock.x = 2048 / 2;
baseBlock.y = 2400;
baseBlock.stopMoving();
baseBlock.setColor(0x2E7D32); // Darker green for base
tower.push({
x: baseBlock.x,
y: baseBlock.y,
width: baseBlock.blockWidth,
block: baseBlock
});
game.addChild(baseBlock);
}
// Create new moving block
function createNewBlock() {
if (!gameRunning) return;
currentBlock = new Block();
currentBlock.setWidth(currentBlockWidth);
// Position above the last block
var lastBlock = tower[tower.length - 1];
currentBlock.x = 100; // Start from left side
currentBlock.y = lastBlock.y - 80;
// Increase speed every 10 levels
var speedMultiplier = 1 + Math.floor(level / 10) * 0.5;
currentBlock.speed = 2 * speedMultiplier;
// Color gradient based on level
var greenShade = 0x4CAF50 + level % 10 * 0x001100;
currentBlock.setColor(greenShade);
game.addChild(currentBlock);
}
// Handle block placement
function placeBlock() {
if (!currentBlock || !gameRunning) return;
currentBlock.stopMoving();
var lastBlock = tower[tower.length - 1];
var overlap = currentBlock.getOverlap(lastBlock.x, lastBlock.width);
if (overlap.width <= 0) {
// No overlap - game over
gameOver();
return;
}
// Check if placement is perfect (within 10 pixels of center)
var isPerfect = Math.abs(currentBlock.x - lastBlock.x) < 10;
if (isPerfect) {
// Perfect placement
perfectCount++;
LK.getSound('perfect').play();
// Create particles
for (var i = 0; i < 8; i++) {
var particle = new Particle();
particle.x = currentBlock.x;
particle.y = currentBlock.y;
particles.push(particle);
game.addChild(particle);
}
// Show perfect text
perfectText.setText('PERFECT!');
tween(perfectText, {
alpha: 0
}, {
duration: 1000
});
// Keep same width for perfect placement
currentBlockWidth = lastBlock.width;
} else {
// Cut the block
currentBlockWidth = overlap.width;
currentBlock.setWidth(currentBlockWidth);
currentBlock.x = overlap.centerX;
LK.getSound('cut').play();
// Reset perfect text
perfectText.alpha = 1;
perfectText.setText('');
}
LK.getSound('place').play();
// Add to tower
tower.push({
x: currentBlock.x,
y: currentBlock.y,
width: currentBlockWidth,
block: currentBlock
});
// Update score
level++;
LK.setScore(level - 1);
scoreText.setText('Level: ' + level);
// Update camera position
updateCamera();
// Check for minimum width
if (currentBlockWidth < 20) {
gameOver();
return;
}
// Create next block after short delay
LK.setTimeout(function () {
createNewBlock();
}, 300);
}
// Update camera to follow tower
function updateCamera() {
if (tower.length > 0) {
var targetY = tower[tower.length - 1].y + 400;
tween(game, {
y: -targetY + 2732 / 2
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Game over
function gameOver() {
gameRunning = false;
// Flash screen red
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Touch controls
game.down = function (x, y, obj) {
if (gameRunning && currentBlock) {
placeBlock();
}
};
// Initialize game
createBaseBlock();
createNewBlock();
// Main game loop
game.update = function () {
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
// Particles update themselves and remove from array when done
}
// Check if block fell too far (safety check)
if (currentBlock && currentBlock.y > 3000) {
gameOver();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,277 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var Block = Container.expand(function () {
+ var self = Container.call(this);
+ self.blockWidth = 200;
+ self.isMoving = true;
+ self.direction = 1;
+ self.speed = 2;
+ self.baseY = 0;
+ // Create the main block
+ var blockGraphics = self.attachAsset('block', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Create shadow for 3D effect
+ var shadowGraphics = self.attachAsset('shadow', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.3,
+ scaleX: 1.1,
+ scaleY: 0.3
+ });
+ shadowGraphics.y = 35; // Offset shadow below block
+ self.setWidth = function (newWidth) {
+ self.blockWidth = newWidth;
+ blockGraphics.width = newWidth;
+ shadowGraphics.width = newWidth * 1.1;
+ };
+ self.setColor = function (color) {
+ blockGraphics.tint = color;
+ };
+ self.stopMoving = function () {
+ self.isMoving = false;
+ };
+ self.getOverlap = function (targetX, targetWidth) {
+ var leftEdge = self.x - self.blockWidth / 2;
+ var rightEdge = self.x + self.blockWidth / 2;
+ var targetLeft = targetX - targetWidth / 2;
+ var targetRight = targetX + targetWidth / 2;
+ var overlapLeft = Math.max(leftEdge, targetLeft);
+ var overlapRight = Math.min(rightEdge, targetRight);
+ if (overlapLeft >= overlapRight) {
+ return {
+ width: 0,
+ centerX: 0
+ };
+ }
+ return {
+ width: overlapRight - overlapLeft,
+ centerX: (overlapLeft + overlapRight) / 2
+ };
+ };
+ self.update = function () {
+ if (self.isMoving) {
+ self.x += self.speed * self.direction;
+ // Bounce off screen edges
+ if (self.x <= self.blockWidth / 2) {
+ self.direction = 1;
+ self.x = self.blockWidth / 2;
+ } else if (self.x >= 2048 - self.blockWidth / 2) {
+ self.direction = -1;
+ self.x = 2048 - self.blockWidth / 2;
+ }
+ }
+ };
+ return self;
+});
+var Particle = Container.expand(function () {
+ var self = Container.call(this);
+ var particle = self.attachAsset('block', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.1,
+ scaleY: 0.1
+ });
+ particle.tint = 0xFFD700; // Gold color
+ self.velocityX = (Math.random() - 0.5) * 10;
+ self.velocityY = -Math.random() * 8 - 2;
+ self.gravity = 0.3;
+ self.life = 60; // 1 second at 60fps
+ self.update = function () {
+ self.x += self.velocityX;
+ self.y += self.velocityY;
+ self.velocityY += self.gravity;
+ self.life--;
+ self.alpha = self.life / 60;
+ if (self.life <= 0) {
+ self.destroy();
+ particles.splice(particles.indexOf(self), 1);
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x87CEEB // Sky blue
+});
+
+/****
+* Game Code
+****/
+// Game state variables
+var tower = [];
+var currentBlock = null;
+var gameRunning = true;
+var level = 1;
+var baseBlockWidth = 200;
+var currentBlockWidth = baseBlockWidth;
+var particles = [];
+var perfectCount = 0;
+var cameraY = 2732 / 2;
+// Create gradient sky background
+game.setBackgroundColor(0x87CEEB);
+// UI Elements
+var scoreText = new Text2('Level: 1', {
+ size: 80,
+ fill: 0xFFFFFF
+});
+scoreText.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreText);
+var perfectText = new Text2('', {
+ size: 60,
+ fill: 0xFFD700
+});
+perfectText.anchor.set(0.5, 0);
+perfectText.y = 100;
+LK.gui.top.addChild(perfectText);
+// Create base block
+function createBaseBlock() {
+ var baseBlock = new Block();
+ baseBlock.x = 2048 / 2;
+ baseBlock.y = 2400;
+ baseBlock.stopMoving();
+ baseBlock.setColor(0x2E7D32); // Darker green for base
+ tower.push({
+ x: baseBlock.x,
+ y: baseBlock.y,
+ width: baseBlock.blockWidth,
+ block: baseBlock
+ });
+ game.addChild(baseBlock);
+}
+// Create new moving block
+function createNewBlock() {
+ if (!gameRunning) return;
+ currentBlock = new Block();
+ currentBlock.setWidth(currentBlockWidth);
+ // Position above the last block
+ var lastBlock = tower[tower.length - 1];
+ currentBlock.x = 100; // Start from left side
+ currentBlock.y = lastBlock.y - 80;
+ // Increase speed every 10 levels
+ var speedMultiplier = 1 + Math.floor(level / 10) * 0.5;
+ currentBlock.speed = 2 * speedMultiplier;
+ // Color gradient based on level
+ var greenShade = 0x4CAF50 + level % 10 * 0x001100;
+ currentBlock.setColor(greenShade);
+ game.addChild(currentBlock);
+}
+// Handle block placement
+function placeBlock() {
+ if (!currentBlock || !gameRunning) return;
+ currentBlock.stopMoving();
+ var lastBlock = tower[tower.length - 1];
+ var overlap = currentBlock.getOverlap(lastBlock.x, lastBlock.width);
+ if (overlap.width <= 0) {
+ // No overlap - game over
+ gameOver();
+ return;
+ }
+ // Check if placement is perfect (within 10 pixels of center)
+ var isPerfect = Math.abs(currentBlock.x - lastBlock.x) < 10;
+ if (isPerfect) {
+ // Perfect placement
+ perfectCount++;
+ LK.getSound('perfect').play();
+ // Create particles
+ for (var i = 0; i < 8; i++) {
+ var particle = new Particle();
+ particle.x = currentBlock.x;
+ particle.y = currentBlock.y;
+ particles.push(particle);
+ game.addChild(particle);
+ }
+ // Show perfect text
+ perfectText.setText('PERFECT!');
+ tween(perfectText, {
+ alpha: 0
+ }, {
+ duration: 1000
+ });
+ // Keep same width for perfect placement
+ currentBlockWidth = lastBlock.width;
+ } else {
+ // Cut the block
+ currentBlockWidth = overlap.width;
+ currentBlock.setWidth(currentBlockWidth);
+ currentBlock.x = overlap.centerX;
+ LK.getSound('cut').play();
+ // Reset perfect text
+ perfectText.alpha = 1;
+ perfectText.setText('');
+ }
+ LK.getSound('place').play();
+ // Add to tower
+ tower.push({
+ x: currentBlock.x,
+ y: currentBlock.y,
+ width: currentBlockWidth,
+ block: currentBlock
+ });
+ // Update score
+ level++;
+ LK.setScore(level - 1);
+ scoreText.setText('Level: ' + level);
+ // Update camera position
+ updateCamera();
+ // Check for minimum width
+ if (currentBlockWidth < 20) {
+ gameOver();
+ return;
+ }
+ // Create next block after short delay
+ LK.setTimeout(function () {
+ createNewBlock();
+ }, 300);
+}
+// Update camera to follow tower
+function updateCamera() {
+ if (tower.length > 0) {
+ var targetY = tower[tower.length - 1].y + 400;
+ tween(game, {
+ y: -targetY + 2732 / 2
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ }
+}
+// Game over
+function gameOver() {
+ gameRunning = false;
+ // Flash screen red
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 1000);
+}
+// Touch controls
+game.down = function (x, y, obj) {
+ if (gameRunning && currentBlock) {
+ placeBlock();
+ }
+};
+// Initialize game
+createBaseBlock();
+createNewBlock();
+// Main game loop
+game.update = function () {
+ // Update particles
+ for (var i = particles.length - 1; i >= 0; i--) {
+ // Particles update themselves and remove from array when done
+ }
+ // Check if block fell too far (safety check)
+ if (currentBlock && currentBlock.y > 3000) {
+ gameOver();
+ }
+};
\ No newline at end of file