/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function () {
var self = Container.call(this);
self.sprite = self.attachAsset('charNormal', {
anchorX: 0.5,
anchorY: 1
});
self.setState = function (state) {
self.removeChildren();
if (state === 'normal') {
self.sprite = self.attachAsset('charNormal', {
anchorX: 0.5,
anchorY: 1
});
} else if (state === 'alert') {
self.sprite = self.attachAsset('charAlert', {
anchorX: 0.5,
anchorY: 1
});
} else if (state === 'worried') {
self.sprite = self.attachAsset('charWorried', {
anchorX: 0.5,
anchorY: 1
});
} else if (state === 'happy') {
self.sprite = self.attachAsset('charHappy', {
anchorX: 0.5,
anchorY: 1
});
}
};
return self;
});
var StopButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('stopButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
stopProduction();
};
return self;
});
var TunaCan = Container.expand(function (isDefective) {
var self = Container.call(this);
self.isDefective = isDefective || false;
self.isClicked = false;
self.speed = 10;
var canGraphics = self.attachAsset(self.isDefective ? 'defectCan' : 'goodCan', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual indicator for defective cans
if (self.isDefective) {
canGraphics.alpha = 0.8;
}
self.update = function () {
self.x += self.speed;
};
self.down = function (x, y, obj) {
if (self.isDefective && !self.isClicked) {
self.isClicked = true;
LK.getSound('click').play();
self.visible = false;
defectsRemoved++;
updateDefectStreak(); // existente
updateDefectsRemovedUI(); // NUEVO: actualiza contador en pantalla
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Game variables
var cans = [];
var currentQuota = 10;
var goodCansProduced = 0;
var defectsRemoved = 0;
var consecutiveDefects = 0;
var gameSpeed = 1;
var spawnTimer = 0;
var spawnRate = 60; // frames between spawns
var isProductionRunning = true;
var level = 1;
var totalDefectiveCount = 0; // cuenta todas las latas defectuosas generadas
var forceDefectiveMode = false; // si es true, solo se generan latas defectuosas
var onlyDefectiveMode = false; // NUEVA variable: indica si está activo el modo solo defectuosas
var defectiveCount = 0; // para contar cuántas latas defectuosas consecutivas aparecieron
/****
* UI Elements
****/
var quotaText = new Text2('Quota: 0/0', {
size: 60,
fill: 0xFFFFFF
});
quotaText.anchor.set(0.5, 0);
LK.gui.top.addChild(quotaText);
var levelText = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 150;
levelText.y = 50;
LK.gui.topLeft.addChild(levelText);
var defectStreakText = new Text2('Consecutive Defects: 0', {
size: 40,
fill: 0xFF6B35
});
defectStreakText.anchor.set(0.5, 0);
defectStreakText.y = 80;
LK.gui.top.addChild(defectStreakText);
// NUEVO: contador de latas defectuosas eliminadas
var defectsRemovedText = new Text2('Defects removed: 0', {
size: 40,
fill: 0xFF6B35
});
defectsRemovedText.anchor.set(0.5, 0);
defectsRemovedText.y = 120; // debajo de defectStreakText
LK.gui.top.addChild(defectsRemovedText);
/****
* Funciones de actualización de UI
****/
function updateUI() {
quotaText.setText('Quota: ' + goodCansProduced + '/' + currentQuota);
levelText.setText('Level: ' + level);
defectStreakText.setText('Consecutive Defects: ' + consecutiveDefects);
}
// NUEVA: actualiza el contador de latas defectuosas eliminadas
function updateDefectsRemovedUI() {
defectsRemovedText.setText('Defects removed: ' + defectsRemoved);
}
// Conveyor belt
var conveyorBelt = game.addChild(LK.getAsset('conveyorBelt', {
anchorX: 0.5,
anchorY: 0.5
}));
conveyorBelt.x = 1024;
conveyorBelt.y = 1400;
// Stop button
var stopButton = game.addChild(new StopButton());
stopButton.x = 1024;
stopButton.y = 1600;
// Stop button label
var stopButtonText = new Text2('STOP PRODUCTION', {
size: 40,
fill: 0xFFFFFF
});
stopButtonText.anchor.set(0.5, 0.5);
stopButtonText.x = stopButton.x;
stopButtonText.y = stopButton.y;
game.addChild(stopButtonText);
var character = game.addChild(new Character());
character.x = 1000; // ajusta según tu canvas
character.y = 1500;
function spawnCan() {
if (!isProductionRunning) {
return;
}
var isDefective;
// Si está activado el modo solo defectuosas, todas las latas son defectuosas
if (onlyDefectiveMode) {
isDefective = true;
} else {
isDefective = Math.random() < 0.3; // 30% de probabilidad de defecto
}
// Contamos cuántas defectuosas seguidas salieron
if (isDefective) {
defectiveCount++;
} else {
defectiveCount = 0;
}
// Si aparecieron 4 defectuosas seguidas, hay 50% de chance de activar el modo solo defectuosas
if (defectiveCount >= 4 && Math.random() < 0.5) {
onlyDefectiveMode = true;
console.log("🔧 Modo solo defectuosas activado");
}
// 🚀 NUEVO: velocidad base aumentada + depende del nivel
var can = new TunaCan(isDefective);
can.x = -100;
can.y = conveyorBelt.y;
// Antes: can.speed = 2 + gameSpeed * 0.5;
// Ahora: aumenta más rápido según el nivel
can.speed = 3 + gameSpeed * 0.6 + level * 0.1;
cans.push(can);
game.addChild(can);
}
function updateDefectStreak() {
consecutiveDefects = 0;
defectStreakText.setText('Consecutive Defects: ' + consecutiveDefects);
}
function checkConsecutiveDefects() {
var recentCans = cans.slice(-3);
if (recentCans.length >= 3) {
var allDefective = true;
for (var i = 0; i < 3; i++) {
if (!recentCans[i].isDefective || recentCans[i].isClicked) {
allDefective = false;
break;
}
}
if (allDefective) {
consecutiveDefects = 3;
defectStreakText.setText('Consecutive Defects: ' + consecutiveDefects);
// Auto-stop production
LK.setTimeout(function () {
if (isProductionRunning) {
stopProduction();
}
}, 100);
}
}
}
function stopProduction() {
if (!isProductionRunning) {
return;
}
isProductionRunning = false;
// Check if quota was met
var quotaMet = goodCansProduced >= currentQuota && goodCansProduced <= currentQuota + 2;
var defectControl = consecutiveDefects >= 3;
// ✅ Permite ganar si está activado el modo solo defectuosas
if (quotaMet || defectControl || onlyDefectiveMode) {
// Éxito
LK.getSound('success').play();
var points = quotaMet ? 100 + level * 10 : 50;
if (defectControl) {
points += 25;
}
LK.setScore(LK.getScore() + points);
// 📈 Aumento progresivo de dificultad
level++;
currentQuota += 5;
gameSpeed += 0.3; // antes 0.2 → ahora aumenta más la velocidad de las latas
spawnRate = Math.max(25, spawnRate - (2 + level)); // antes 30 y -2 → ahora depende del nivel
// ✴️ Efecto visual al pasar de nivel
LK.effects.flashScreen(0x27ae60, 500);
// 🔁 Reset del nivel
LK.setTimeout(function () {
resetLevel();
totalDefectiveCount = 0;
forceDefectiveMode = false;
onlyDefectiveMode = false; // ✅ IMPORTANTE: restablece el modo de latas defectuosas
}, 1000);
} else {
// Fallo
LK.getSound('fail').play();
LK.effects.flashScreen(0xe74c3c, 1000);
LK.showGameOver();
}
}
function resetLevel() {
// Si el modo solo defectuosas estaba activo, lo desactivamos para el nuevo nivel
if (onlyDefectiveMode) {
console.log(" Modo solo defectuosas desactivado al pasar de nivel");
onlyDefectiveMode = false;
defectiveCount = 0; // Reiniciamos el contador de defectuosas seguidas
}
// 🧩 Limpiamos todas las latas del nivel anterior
for (var i = cans.length - 1; i >= 0; i--) {
cans[i].destroy();
}
cans = [];
// 🔁 Reiniciamos contadores de nivel
goodCansProduced = 0;
defectsRemoved = 0;
consecutiveDefects = 0;
isProductionRunning = true;
// 🖥️ Actualizamos la interfaz
updateUI();
}
// Initialize UI
updateUI();
game.update = function () {
if (!isProductionRunning) {
return;
}
// Spawn cans
spawnTimer++;
if (spawnTimer >= spawnRate) {
spawnTimer = 0;
spawnCan();
}
// Update cans and check for removal
for (var i = cans.length - 1; i >= 0; i--) {
var can = cans[i];
// Remove cans that are off screen
if (can.x > 2148) {
if (!can.isDefective && !can.isClicked) {
goodCansProduced++;
}
can.destroy();
cans.splice(i, 1);
continue;
}
// Check if unclicked defective cans passed through
if (can.x > 2048 && can.isDefective && !can.isClicked) {
checkConsecutiveDefects();
}
}
// Update UI
updateUI();
// Check win condition
if (goodCansProduced >= currentQuota + 5) {
// Over-production penalty
LK.getSound('fail').play();
LK.effects.flashScreen(0xe74c3c, 1000);
LK.showGameOver();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function () {
var self = Container.call(this);
self.sprite = self.attachAsset('charNormal', {
anchorX: 0.5,
anchorY: 1
});
self.setState = function (state) {
self.removeChildren();
if (state === 'normal') {
self.sprite = self.attachAsset('charNormal', {
anchorX: 0.5,
anchorY: 1
});
} else if (state === 'alert') {
self.sprite = self.attachAsset('charAlert', {
anchorX: 0.5,
anchorY: 1
});
} else if (state === 'worried') {
self.sprite = self.attachAsset('charWorried', {
anchorX: 0.5,
anchorY: 1
});
} else if (state === 'happy') {
self.sprite = self.attachAsset('charHappy', {
anchorX: 0.5,
anchorY: 1
});
}
};
return self;
});
var StopButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('stopButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
stopProduction();
};
return self;
});
var TunaCan = Container.expand(function (isDefective) {
var self = Container.call(this);
self.isDefective = isDefective || false;
self.isClicked = false;
self.speed = 10;
var canGraphics = self.attachAsset(self.isDefective ? 'defectCan' : 'goodCan', {
anchorX: 0.5,
anchorY: 0.5
});
// Add visual indicator for defective cans
if (self.isDefective) {
canGraphics.alpha = 0.8;
}
self.update = function () {
self.x += self.speed;
};
self.down = function (x, y, obj) {
if (self.isDefective && !self.isClicked) {
self.isClicked = true;
LK.getSound('click').play();
self.visible = false;
defectsRemoved++;
updateDefectStreak(); // existente
updateDefectsRemovedUI(); // NUEVO: actualiza contador en pantalla
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Game variables
var cans = [];
var currentQuota = 10;
var goodCansProduced = 0;
var defectsRemoved = 0;
var consecutiveDefects = 0;
var gameSpeed = 1;
var spawnTimer = 0;
var spawnRate = 60; // frames between spawns
var isProductionRunning = true;
var level = 1;
var totalDefectiveCount = 0; // cuenta todas las latas defectuosas generadas
var forceDefectiveMode = false; // si es true, solo se generan latas defectuosas
var onlyDefectiveMode = false; // NUEVA variable: indica si está activo el modo solo defectuosas
var defectiveCount = 0; // para contar cuántas latas defectuosas consecutivas aparecieron
/****
* UI Elements
****/
var quotaText = new Text2('Quota: 0/0', {
size: 60,
fill: 0xFFFFFF
});
quotaText.anchor.set(0.5, 0);
LK.gui.top.addChild(quotaText);
var levelText = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
levelText.x = 150;
levelText.y = 50;
LK.gui.topLeft.addChild(levelText);
var defectStreakText = new Text2('Consecutive Defects: 0', {
size: 40,
fill: 0xFF6B35
});
defectStreakText.anchor.set(0.5, 0);
defectStreakText.y = 80;
LK.gui.top.addChild(defectStreakText);
// NUEVO: contador de latas defectuosas eliminadas
var defectsRemovedText = new Text2('Defects removed: 0', {
size: 40,
fill: 0xFF6B35
});
defectsRemovedText.anchor.set(0.5, 0);
defectsRemovedText.y = 120; // debajo de defectStreakText
LK.gui.top.addChild(defectsRemovedText);
/****
* Funciones de actualización de UI
****/
function updateUI() {
quotaText.setText('Quota: ' + goodCansProduced + '/' + currentQuota);
levelText.setText('Level: ' + level);
defectStreakText.setText('Consecutive Defects: ' + consecutiveDefects);
}
// NUEVA: actualiza el contador de latas defectuosas eliminadas
function updateDefectsRemovedUI() {
defectsRemovedText.setText('Defects removed: ' + defectsRemoved);
}
// Conveyor belt
var conveyorBelt = game.addChild(LK.getAsset('conveyorBelt', {
anchorX: 0.5,
anchorY: 0.5
}));
conveyorBelt.x = 1024;
conveyorBelt.y = 1400;
// Stop button
var stopButton = game.addChild(new StopButton());
stopButton.x = 1024;
stopButton.y = 1600;
// Stop button label
var stopButtonText = new Text2('STOP PRODUCTION', {
size: 40,
fill: 0xFFFFFF
});
stopButtonText.anchor.set(0.5, 0.5);
stopButtonText.x = stopButton.x;
stopButtonText.y = stopButton.y;
game.addChild(stopButtonText);
var character = game.addChild(new Character());
character.x = 1000; // ajusta según tu canvas
character.y = 1500;
function spawnCan() {
if (!isProductionRunning) {
return;
}
var isDefective;
// Si está activado el modo solo defectuosas, todas las latas son defectuosas
if (onlyDefectiveMode) {
isDefective = true;
} else {
isDefective = Math.random() < 0.3; // 30% de probabilidad de defecto
}
// Contamos cuántas defectuosas seguidas salieron
if (isDefective) {
defectiveCount++;
} else {
defectiveCount = 0;
}
// Si aparecieron 4 defectuosas seguidas, hay 50% de chance de activar el modo solo defectuosas
if (defectiveCount >= 4 && Math.random() < 0.5) {
onlyDefectiveMode = true;
console.log("🔧 Modo solo defectuosas activado");
}
// 🚀 NUEVO: velocidad base aumentada + depende del nivel
var can = new TunaCan(isDefective);
can.x = -100;
can.y = conveyorBelt.y;
// Antes: can.speed = 2 + gameSpeed * 0.5;
// Ahora: aumenta más rápido según el nivel
can.speed = 3 + gameSpeed * 0.6 + level * 0.1;
cans.push(can);
game.addChild(can);
}
function updateDefectStreak() {
consecutiveDefects = 0;
defectStreakText.setText('Consecutive Defects: ' + consecutiveDefects);
}
function checkConsecutiveDefects() {
var recentCans = cans.slice(-3);
if (recentCans.length >= 3) {
var allDefective = true;
for (var i = 0; i < 3; i++) {
if (!recentCans[i].isDefective || recentCans[i].isClicked) {
allDefective = false;
break;
}
}
if (allDefective) {
consecutiveDefects = 3;
defectStreakText.setText('Consecutive Defects: ' + consecutiveDefects);
// Auto-stop production
LK.setTimeout(function () {
if (isProductionRunning) {
stopProduction();
}
}, 100);
}
}
}
function stopProduction() {
if (!isProductionRunning) {
return;
}
isProductionRunning = false;
// Check if quota was met
var quotaMet = goodCansProduced >= currentQuota && goodCansProduced <= currentQuota + 2;
var defectControl = consecutiveDefects >= 3;
// ✅ Permite ganar si está activado el modo solo defectuosas
if (quotaMet || defectControl || onlyDefectiveMode) {
// Éxito
LK.getSound('success').play();
var points = quotaMet ? 100 + level * 10 : 50;
if (defectControl) {
points += 25;
}
LK.setScore(LK.getScore() + points);
// 📈 Aumento progresivo de dificultad
level++;
currentQuota += 5;
gameSpeed += 0.3; // antes 0.2 → ahora aumenta más la velocidad de las latas
spawnRate = Math.max(25, spawnRate - (2 + level)); // antes 30 y -2 → ahora depende del nivel
// ✴️ Efecto visual al pasar de nivel
LK.effects.flashScreen(0x27ae60, 500);
// 🔁 Reset del nivel
LK.setTimeout(function () {
resetLevel();
totalDefectiveCount = 0;
forceDefectiveMode = false;
onlyDefectiveMode = false; // ✅ IMPORTANTE: restablece el modo de latas defectuosas
}, 1000);
} else {
// Fallo
LK.getSound('fail').play();
LK.effects.flashScreen(0xe74c3c, 1000);
LK.showGameOver();
}
}
function resetLevel() {
// Si el modo solo defectuosas estaba activo, lo desactivamos para el nuevo nivel
if (onlyDefectiveMode) {
console.log(" Modo solo defectuosas desactivado al pasar de nivel");
onlyDefectiveMode = false;
defectiveCount = 0; // Reiniciamos el contador de defectuosas seguidas
}
// 🧩 Limpiamos todas las latas del nivel anterior
for (var i = cans.length - 1; i >= 0; i--) {
cans[i].destroy();
}
cans = [];
// 🔁 Reiniciamos contadores de nivel
goodCansProduced = 0;
defectsRemoved = 0;
consecutiveDefects = 0;
isProductionRunning = true;
// 🖥️ Actualizamos la interfaz
updateUI();
}
// Initialize UI
updateUI();
game.update = function () {
if (!isProductionRunning) {
return;
}
// Spawn cans
spawnTimer++;
if (spawnTimer >= spawnRate) {
spawnTimer = 0;
spawnCan();
}
// Update cans and check for removal
for (var i = cans.length - 1; i >= 0; i--) {
var can = cans[i];
// Remove cans that are off screen
if (can.x > 2148) {
if (!can.isDefective && !can.isClicked) {
goodCansProduced++;
}
can.destroy();
cans.splice(i, 1);
continue;
}
// Check if unclicked defective cans passed through
if (can.x > 2048 && can.isDefective && !can.isClicked) {
checkConsecutiveDefects();
}
}
// Update UI
updateUI();
// Check win condition
if (goodCansProduced >= currentQuota + 5) {
// Over-production penalty
LK.getSound('fail').play();
LK.effects.flashScreen(0xe74c3c, 1000);
LK.showGameOver();
}
};