User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'easeInOut')' in or related to this line: '_tween(btn, {' Line Number: 289
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(catcher, {' Line Number: 476
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(catcher, {' Line Number: 474
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(catcher, {' Line Number: 476 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Haz que al dar a persecucion salga facil normal y dificil en un nuevo menu
User prompt
Haz que el botón este arriba de fácil y que aparezca un poco lejos tinky winky
User prompt
Haz que tenga un modo llamado persecución en el que hay un mapa extenso y con dar click te mueves a gran velocidad escapando de tinky winky
User prompt
Haz que en el menú se pueda guardar y acumular la cantidad de papillas con las que se puede comprar skins de teletubie rojo,verde,morado y amarillo ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
añade el modo extremo
User prompt
Añadele un menú en el que puedes escojer nivel de dificultad entre fácil normal y difícil
User prompt
Haz el fondo verde
User prompt
Haz que el personaje que es el círculo azul pueda moverse
Code edit (1 edits merged)
Please save this source code
User prompt
Papilla Catcher
Initial prompt
Trata de agarrar papillas
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
papillaCurrency: 0,
ownedSkins: {
rojo: false,
verde: false,
morado: false,
amarillo: false
},
selectedSkin: "rojo"
});
/****
* Classes
****/
// Catcher class (player character)
var Catcher = Container.expand(function () {
var self = Container.call(this);
var catcherAsset = self.attachAsset('catcher', {
anchorX: 0.5,
anchorY: 0.5
});
// Optionally, add a face or smile with another shape or text (not required for MVP)
// No update needed; position is set by player input
return self;
});
// Optionally, play background music (commented out for MVP)
// LK.playMusic('bgmusic', {fade: {start: 0, end: 1, duration: 1000}});
// Enemy class (Tinky Winky)
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyAsset = self.attachAsset('catcher', {
anchorX: 0.5,
anchorY: 0.5
});
enemyAsset.tint = 0x8800ff; // Purple tint for Tinky Winky
self.speed = 6;
self.targetX = self.x;
self.targetY = self.y;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > self.speed) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
} else {
self.x = self.targetX;
self.y = self.targetY;
}
};
return self;
});
// Ground class (for missed detection)
var Ground = Container.expand(function () {
var self = Container.call(this);
var groundAsset = self.attachAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Papilla class (falling object)
var Papilla = Container.expand(function () {
var self = Container.call(this);
var papillaAsset = self.attachAsset('papilla', {
anchorX: 0.5,
anchorY: 0.5
});
// Falling speed (pixels per frame)
self.speed = 8;
// Used for tracking if already counted as missed/caught
self.caught = false;
// Called every tick
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x00b140 // Green background
});
/****
* Game Code
****/
// Game constants
/****
* Papilla Catcher - Source Code
****/
// Papilla (baby food jar) - ellipse, yellow
// Character - box, blue
// Ground - box, brown
// Sound for catching
// Sound for miss
// Music (optional, will not play by default)
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var GROUND_HEIGHT = 40;
var MAX_MISSES = 3;
// Difficulty settings
var DIFFICULTY_SETTINGS = [{
name: "Fácil",
spawnInterval: 70,
papillaSpeed: 7
}, {
name: "Normal",
spawnInterval: 48,
papillaSpeed: 10
}, {
name: "Difícil",
spawnInterval: 28,
papillaSpeed: 16
}, {
name: "Extremo",
spawnInterval: 12,
papillaSpeed: 28
}, {
name: "Persecución",
type: "chase"
}];
var selectedDifficulty = null;
// Game state
var papillas = [];
var score = 0;
var misses = 0;
var spawnInterval = 60; // Frames between spawns (will decrease)
var papillaSpeed = 8; // Initial speed (will increase)
var lastSpawnTick = 0;
var isDragging = false;
var dragOffsetX = 0;
var isChaseMode = false;
var chaseCameraX = 0;
var chaseCameraY = 0;
var chaseMapWidth = 6144;
var chaseMapHeight = 8196;
var enemy = null;
var chaseContainer = null;
// --- Difficulty Menu UI ---
var menuContainer = new Container();
menuContainer.x = GAME_WIDTH / 2;
menuContainer.y = GAME_HEIGHT / 2;
game.addChild(menuContainer);
// Papilla currency display
var papillaCurrencyTxt = new Text2("Papillas: " + (storage.papillaCurrency || 0), {
size: 90,
fill: 0xB8B031
});
papillaCurrencyTxt.anchor.set(0.5, 1);
papillaCurrencyTxt.y = -320;
menuContainer.addChild(papillaCurrencyTxt);
// Skin shop UI
var skinNames = ["rojo", "verde", "morado", "amarillo"];
var skinColors = [0xff0000, 0x00ff00, 0x8000ff, 0xffff00];
var skinPrices = [20, 20, 20, 20];
var skinButtons = [];
var skinShopTitle = new Text2("Skins Teletubie", {
size: 100,
fill: "#444"
});
skinShopTitle.anchor.set(0.5, 1);
skinShopTitle.y = -200;
menuContainer.addChild(skinShopTitle);
for (var s = 0; s < skinNames.length; s++) {
var skinBtn = new Container();
skinBtn.x = -420 + s * 280;
skinBtn.y = -60;
// Visual skin preview (colored circle)
var skinPreview = LK.getAsset('centerCircle', {
width: 120,
height: 120,
color: skinColors[s],
anchorX: 0.5,
anchorY: 0.5
});
skinBtn.addChild(skinPreview);
// Price or owned indicator
var owned = storage.ownedSkins && storage.ownedSkins[skinNames[s]];
var priceOrOwned = new Text2(owned ? "Usar" : skinPrices[s] + " 🍼", {
size: 50,
fill: owned ? "#00b140" : "#b8b031"
});
priceOrOwned.anchor.set(0.5, 0);
priceOrOwned.y = 70;
skinBtn.addChild(priceOrOwned);
// Touch event for buying/selecting
(function (skinIdx) {
skinBtn.down = function (x, y, obj) {
var skin = skinNames[skinIdx];
var owned = storage.ownedSkins && storage.ownedSkins[skin];
if (owned) {
storage.selectedSkin = skin;
updateSkinShopUI();
} else if ((storage.papillaCurrency || 0) >= skinPrices[skinIdx]) {
storage.papillaCurrency -= skinPrices[skinIdx];
storage.ownedSkins[skin] = true;
storage.selectedSkin = skin;
papillaCurrencyTxt.setText("Papillas: " + storage.papillaCurrency);
updateSkinShopUI();
}
};
})(s);
menuContainer.addChild(skinBtn);
skinButtons.push({
btn: skinBtn,
priceOrOwned: priceOrOwned,
idx: s
});
}
// Helper to update skin shop UI
function updateSkinShopUI() {
papillaCurrencyTxt.setText("Papillas: " + (storage.papillaCurrency || 0));
for (var i = 0; i < skinButtons.length; i++) {
var skin = skinNames[i];
var owned = storage.ownedSkins && storage.ownedSkins[skin];
var selected = storage.selectedSkin === skin;
skinButtons[i].priceOrOwned.setText(owned ? selected ? "Usando" : "Usar" : skinPrices[i] + " 🍼");
skinButtons[i].btn.alpha = selected ? 1 : 0.8;
skinButtons[i].btn.scaleX = skinButtons[i].btn.scaleY = selected ? 1.15 : 1;
}
}
updateSkinShopUI();
// Difficulty menu
var menuTitle = new Text2("Elige dificultad", {
size: 160,
fill: 0x00B140
});
menuTitle.anchor.set(0.5, 1);
menuTitle.y = 120;
menuContainer.addChild(menuTitle);
var menuButtons = [];
var buttonHeight = 200;
var buttonSpacing = 60;
for (var i = 0; i < DIFFICULTY_SETTINGS.length; i++) {
var btn = new Container();
btn.y = i * (buttonHeight + buttonSpacing);
var btnBg = LK.getAsset('ground', {
width: 700,
height: buttonHeight,
color: 0x00b140,
anchorX: 0.5,
anchorY: 0.5
});
btn.addChild(btnBg);
var btnText = new Text2(DIFFICULTY_SETTINGS[i].name, {
size: 110,
fill: "#fff"
});
btnText.anchor.set(0.5, 0.5);
btnText.y = 0;
btn.addChild(btnText);
// Touch event
(function (idx) {
btn.down = function (x, y, obj) {
selectDifficulty(idx);
};
})(i);
menuContainer.addChild(btn);
menuButtons.push(btn);
}
// Reorder buttons: move Persecución (last) to first position
var reorderedButtons = [menuButtons[4], menuButtons[0], menuButtons[1], menuButtons[2], menuButtons[3]];
for (var i = 0; i < reorderedButtons.length; i++) {
reorderedButtons[i].x = 0;
reorderedButtons[i].y = i * (buttonHeight + buttonSpacing) + 320;
// Highlight "Extremo" button for fun
if (DIFFICULTY_SETTINGS[i].name === "Extremo" || i > 0 && DIFFICULTY_SETTINGS[i - 1].name === "Extremo") {
var extBtn = reorderedButtons[i];
// Animate color or scale for visibility
tween(extBtn, {
scaleX: 1.12,
scaleY: 1.12
}, {
duration: 600,
yoyo: true,
repeat: Infinity,
easing: tween.easeInOut
});
}
}
menuButtons = reorderedButtons;
// Chase mode setup
function setupChaseMode() {
chaseContainer = new Container();
game.addChild(chaseContainer);
// Create player (catcher) in chase mode
catcher = new Catcher();
catcher.x = chaseMapWidth / 2;
catcher.y = chaseMapHeight / 2;
chaseContainer.addChild(catcher);
// Create enemy (Tinky Winky)
enemy = new Enemy();
enemy.x = chaseMapWidth / 2 - 800;
enemy.y = chaseMapHeight / 2 - 600;
enemy.speed = 8;
chaseContainer.addChild(enemy);
// Initialize camera to follow player
chaseCameraX = catcher.x;
chaseCameraY = catcher.y;
// Score display
scoreTxt = new Text2('0', {
size: 120,
fill: 0xffffff
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
updateScoreDisplay();
}
// Hide game elements until difficulty is chosen
var ground, catcher, scoreTxt, missesTxt;
function setupGameElements() {
// Create ground at bottom
ground = new Ground();
ground.x = GAME_WIDTH / 2;
ground.y = GAME_HEIGHT - GROUND_HEIGHT / 2;
game.addChild(ground);
// Create catcher (player)
catcher = new Catcher();
catcher.x = GAME_WIDTH / 2;
catcher.y = GAME_HEIGHT - GROUND_HEIGHT - catcher.height / 2 - 10;
game.addChild(catcher);
// Score display
scoreTxt = new Text2('0', {
size: 120,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Misses display (hearts or Xs)
missesTxt = new Text2('', {
size: 90,
fill: 0xD83318
});
missesTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missesTxt);
missesTxt.y = 120; // Place below score
updateScoreDisplay();
}
function updateScoreDisplay() {
if (!scoreTxt) return;
scoreTxt.setText(score);
// Show misses as X X X (only in non-chase mode)
if (missesTxt) {
var missStr = '';
for (var i = 0; i < MAX_MISSES; i++) {
missStr += i < misses ? '✖ ' : '○ ';
}
missesTxt.setText(missStr);
}
}
// Called when a difficulty is selected
function selectDifficulty(idx) {
selectedDifficulty = idx;
// Remove menu
menuContainer.visible = false;
if (DIFFICULTY_SETTINGS[idx].type === "chase") {
isChaseMode = true;
setupChaseMode();
} else {
// Set initial values based on difficulty
spawnInterval = DIFFICULTY_SETTINGS[idx].spawnInterval;
papillaSpeed = DIFFICULTY_SETTINGS[idx].papillaSpeed;
// Setup game elements
setupGameElements();
}
}
// Touch/move controls
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Only allow horizontal movement
function handleMove(x, y, obj) {
if (selectedDifficulty === null) return;
if (isChaseMode) {
// Chase mode: don't move on hover
return;
}
if (isDragging) {
// Clamp catcher within screen
var halfWidth = catcher.width / 2;
catcher.x = clamp(x - dragOffsetX, halfWidth, GAME_WIDTH - halfWidth);
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (selectedDifficulty === null) return;
if (isChaseMode) {
// Convert screen coordinates to world coordinates
var worldX = chaseCameraX - GAME_WIDTH / 2 + x;
var worldY = chaseCameraY - GAME_HEIGHT / 2 + y;
// Move player to clicked location at high speed
tween(catcher, {
x: worldX,
y: worldY
}, {
duration: 400,
easing: tween.easeOut
});
return;
}
// Only start drag if touch is on or near the catcher
var local = catcher.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x >= -catcher.width / 2 && local.x <= catcher.width / 2 && local.y >= -catcher.height / 2 && local.y <= catcher.height / 2) {
isDragging = true;
dragOffsetX = x - catcher.x;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
if (selectedDifficulty === null) return;
isDragging = false;
};
// Papilla spawn logic
function spawnPapilla() {
var papilla = new Papilla();
// Random X, avoid spawning at extreme edges
var margin = 100 + papilla.width / 2;
papilla.x = margin + Math.random() * (GAME_WIDTH - 2 * margin);
papilla.y = 0 - papilla.height / 2;
papilla.speed = papillaSpeed;
papillas.push(papilla);
game.addChild(papilla);
}
// Main game update loop
game.update = function () {
// Block game logic until difficulty is selected
if (selectedDifficulty === null) {
return;
}
// Handle chase mode
if (isChaseMode) {
if (catcher && enemy) {
// Update enemy AI to chase player
enemy.targetX = catcher.x;
enemy.targetY = catcher.y;
enemy.update();
// Update camera to follow player
chaseCameraX = catcher.x;
chaseCameraY = catcher.y;
// Clamp camera to map bounds
chaseCameraX = clamp(chaseCameraX, GAME_WIDTH / 2, chaseMapWidth - GAME_WIDTH / 2);
chaseCameraY = clamp(chaseCameraY, GAME_HEIGHT / 2, chaseMapHeight - GAME_HEIGHT / 2);
// Position container to follow camera
chaseContainer.x = GAME_WIDTH / 2 - chaseCameraX;
chaseContainer.y = GAME_HEIGHT / 2 - chaseCameraY;
// Update score as time survived (in seconds)
score = Math.floor(LK.ticks / 60);
scoreTxt.setText("Tiempo: " + score + "s");
// Check if caught by enemy
if (catcher.intersects(enemy)) {
LK.effects.flashScreen(0xff0000, 400);
LK.setTimeout(function () {
LK.showGameOver();
}, 400);
}
}
return;
}
// Increase difficulty as score rises (relative to base difficulty)
if (selectedDifficulty === 3) {
// Extremo mode: always maxed out
spawnInterval = 8;
papillaSpeed = 38 + Math.floor(score / 10) * 2; // gets even faster as score increases
} else if (score < 10) {
spawnInterval = DIFFICULTY_SETTINGS[selectedDifficulty].spawnInterval;
papillaSpeed = DIFFICULTY_SETTINGS[selectedDifficulty].papillaSpeed;
} else if (score < 20) {
spawnInterval = Math.max(22, DIFFICULTY_SETTINGS[selectedDifficulty].spawnInterval - 12);
papillaSpeed = DIFFICULTY_SETTINGS[selectedDifficulty].papillaSpeed + 2;
} else if (score < 35) {
spawnInterval = Math.max(18, DIFFICULTY_SETTINGS[selectedDifficulty].spawnInterval - 22);
papillaSpeed = DIFFICULTY_SETTINGS[selectedDifficulty].papillaSpeed + 5;
} else if (score < 50) {
spawnInterval = Math.max(14, DIFFICULTY_SETTINGS[selectedDifficulty].spawnInterval - 30);
papillaSpeed = DIFFICULTY_SETTINGS[selectedDifficulty].papillaSpeed + 8;
} else {
spawnInterval = Math.max(10, DIFFICULTY_SETTINGS[selectedDifficulty].spawnInterval - 36);
papillaSpeed = DIFFICULTY_SETTINGS[selectedDifficulty].papillaSpeed + 12;
}
// Spawn new papilla
if (LK.ticks - lastSpawnTick >= spawnInterval) {
spawnPapilla();
lastSpawnTick = LK.ticks;
}
// Update papillas
for (var i = papillas.length - 1; i >= 0; i--) {
var p = papillas[i];
p.update();
// Check for catch (intersect with catcher)
if (!p.caught && p.intersects(catcher)) {
p.caught = true;
score += 1;
// Award papilla currency
storage.papillaCurrency = (storage.papillaCurrency || 0) + 1;
if (typeof papillaCurrencyTxt !== "undefined" && papillaCurrencyTxt.setText) {
papillaCurrencyTxt.setText("Papillas: " + storage.papillaCurrency);
}
if (typeof updateSkinShopUI === "function") updateSkinShopUI();
updateScoreDisplay();
LK.getSound('catch').play();
// Animate papilla (shrink and fade)
tween(p, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 250,
easing: tween.easeIn,
onFinish: function onFinish() {}
});
// Remove after animation
LK.setTimeout(function (papillaRef, idx) {
if (papillaRef && papillas.indexOf(papillaRef) !== -1) {
papillaRef.destroy();
papillas.splice(papillas.indexOf(papillaRef), 1);
}
}, 260, p, i);
continue;
}
// Check for miss (intersect with ground or off screen)
if (!p.caught && p.y + p.height / 2 >= ground.y - GROUND_HEIGHT / 2) {
p.caught = true;
misses += 1;
updateScoreDisplay();
LK.getSound('miss').play();
// Flash screen red
LK.effects.flashScreen(0xff0000, 400);
// Animate papilla (fall and fade)
tween(p, {
alpha: 0,
y: ground.y + 80
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {}
});
LK.setTimeout(function (papillaRef, idx) {
if (papillaRef && papillas.indexOf(papillaRef) !== -1) {
papillaRef.destroy();
papillas.splice(papillas.indexOf(papillaRef), 1);
}
}, 320, p, i);
// Game over if too many misses
if (misses >= MAX_MISSES) {
LK.setTimeout(function () {
LK.showGameOver();
}, 400);
}
continue;
}
// Remove papilla if far off screen (failsafe)
if (p.y > GAME_HEIGHT + 200) {
p.destroy();
papillas.splice(i, 1);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -264,14 +264,16 @@
})(i);
menuContainer.addChild(btn);
menuButtons.push(btn);
}
-for (var i = 0; i < menuButtons.length; i++) {
- menuButtons[i].x = 0;
- menuButtons[i].y = i * (buttonHeight + buttonSpacing) + 320;
+// Reorder buttons: move Persecución (last) to first position
+var reorderedButtons = [menuButtons[4], menuButtons[0], menuButtons[1], menuButtons[2], menuButtons[3]];
+for (var i = 0; i < reorderedButtons.length; i++) {
+ reorderedButtons[i].x = 0;
+ reorderedButtons[i].y = i * (buttonHeight + buttonSpacing) + 320;
// Highlight "Extremo" button for fun
- if (DIFFICULTY_SETTINGS[i].name === "Extremo") {
- var extBtn = menuButtons[i];
+ if (DIFFICULTY_SETTINGS[i].name === "Extremo" || i > 0 && DIFFICULTY_SETTINGS[i - 1].name === "Extremo") {
+ var extBtn = reorderedButtons[i];
// Animate color or scale for visibility
tween(extBtn, {
scaleX: 1.12,
scaleY: 1.12
@@ -282,8 +284,9 @@
easing: tween.easeInOut
});
}
}
+menuButtons = reorderedButtons;
// Chase mode setup
function setupChaseMode() {
chaseContainer = new Container();
game.addChild(chaseContainer);
@@ -293,10 +296,10 @@
catcher.y = chaseMapHeight / 2;
chaseContainer.addChild(catcher);
// Create enemy (Tinky Winky)
enemy = new Enemy();
- enemy.x = chaseMapWidth / 2 - 400;
- enemy.y = chaseMapHeight / 2;
+ enemy.x = chaseMapWidth / 2 - 800;
+ enemy.y = chaseMapHeight / 2 - 600;
enemy.speed = 8;
chaseContainer.addChild(enemy);
// Initialize camera to follow player
chaseCameraX = catcher.x;