User prompt
Crea nuevo nivel
User prompt
Que haiga nivel 7 que sea original
User prompt
Que la pantalla de inicio solo sea un boton que resalte de jugar y ya
User prompt
Quita 2 obstaculos en el nivel 6 y que solo haiga una puerta
User prompt
Quita el fondo en el inicio de pantalla
User prompt
Que el fondo del inicio de pantalla sea bonito
User prompt
Crea una pantalla de inicio
User prompt
Que el juego siga al nivel 6 despues del 5
User prompt
Que el juego no termine en el 5 nivel
User prompt
Haa el nivel 6
User prompt
Crea el nivel 6
User prompt
Crea el nivel 6 un nivel original
User prompt
en el nivel 5 que el profesor lo siga
User prompt
Que en el nivel 5 pon suelo
User prompt
Que en el nivel 5 en mitad delas 2 puerta haiga unas letras que digan escoje la puerta correcta
User prompt
Que el piso del cuarto nivel sea el de concreto
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'var floor = LK.getAsset(floorAssetId, {' Line Number: 239
User prompt
nivel 5 adivina la puerta correcta
User prompt
Que haiga un tiempo limite para responder la pregunta
User prompt
Que en el nivel 4 haiga un laberinto facil
User prompt
Que el laberinto del nivel 4 sea muy facil
User prompt
Que el laberinto de el nivel 4 sea abierto
User prompt
No pongas obstaculos en el nivel 4
User prompt
Que en el nivel 4 no haigan tantos obstaculos solo uno que otro
User prompt
Que el profesor no atraviese los obstaculos
/**** * Classes ****/ // ProfesorMonster class: AI-driven monster that chases the student var ProfesorMonster = Container.expand(function () { var self = Container.call(this); // Attach profesor asset var profesorSprite = self.attachAsset('profesor', { anchorX: 0.5, anchorY: 0.5 }); // Track last position for event logic self.lastX = self.x; self.lastY = self.y; self.lastWasIntersecting = false; // Update method: chase the student self.update = function () { // Store last position self.lastX = self.x; self.lastY = self.y; // Immobilize profesor if student is touching the door (popup active) if (typeof showMathQuestion !== "undefined" && showMathQuestion || typeof student !== "undefined" && typeof student.lastWasIntersectingDoor !== "undefined" && student.lastWasIntersectingDoor) { // Profesor stays still, do not move return; } // Use global student variable if (typeof student === "undefined" || !student) return; // Simple AI: move towards the student var dx = student.x - self.x; var dy = student.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 6; // profesor speed, now much slower than student if (dist > speed) { // Calculate intended new position var nextX = self.x + dx / dist * speed; var nextY = self.y + dy / dist * speed; var blocked = false; // Level 2: block profesor on obstacles if (typeof currentLevel !== "undefined" && currentLevel === 2 && typeof game !== "undefined" && game.level2Obstacles) { for (var i = 0; i < game.level2Obstacles.length; i++) { var obs = game.level2Obstacles[i]; // Simulate move: temporarily set position, check collision, revert var oldX = self.x, oldY = self.y; self.x = nextX; self.y = nextY; if (self.intersects(obs)) { blocked = true; } self.x = oldX; self.y = oldY; if (blocked) break; } } // Level 2: also block corridor walls if (!blocked && typeof currentLevel !== "undefined" && currentLevel === 2) { var corridorHeight = 520; var corridorY = (2732 - corridorHeight) / 2; var corridorTop = corridorY; var corridorBottom = corridorY + corridorHeight; var leftWall = 40; var rightWall = 2048 - 40; var profesorTop = nextY - 80; var profesorBottom = nextY + 80; var profesorLeft = nextX - 80; var profesorRight = nextX + 80; if (profesorTop < corridorTop || profesorBottom > corridorBottom || profesorLeft < leftWall || profesorRight > rightWall) { blocked = true; } } // Level 3: block profesor on rocks and map boundaries if (!blocked && typeof currentLevel !== "undefined" && currentLevel === 3 && typeof game !== "undefined" && game.level3Obstacles) { for (var i = 0; i < game.level3Obstacles.length; i++) { var rock = game.level3Obstacles[i]; var oldX = self.x, oldY = self.y; self.x = nextX; self.y = nextY; if (self.intersects(rock)) { blocked = true; } self.x = oldX; self.y = oldY; if (blocked) break; } // Map boundaries for profesor in level 3 var leftWall = 40; var rightWall = 2048 - 40; var topWall = 40; var bottomWall = 2732 - 40; var profesorLeft = nextX - 80; var profesorRight = nextX + 80; var profesorTop = nextY - 80; var profesorBottom = nextY + 80; if (profesorLeft < leftWall || profesorRight > rightWall || profesorTop < topWall || profesorBottom > bottomWall) { blocked = true; } } // Level 4: block profesor on maze walls and soccer balls and map boundaries if (!blocked && typeof currentLevel !== "undefined" && currentLevel === 4 && typeof game !== "undefined") { // Maze walls if (game.level4MazeWalls) { for (var i = 0; i < game.level4MazeWalls.length; i++) { var wall = game.level4MazeWalls[i]; var oldX = self.x, oldY = self.y; self.x = nextX; self.y = nextY; if (self.intersects(wall)) { blocked = true; } self.x = oldX; self.y = oldY; if (blocked) break; } } // Soccer balls if (!blocked && game.level4SoccerBalls) { for (var i = 0; i < game.level4SoccerBalls.length; i++) { var ball = game.level4SoccerBalls[i]; var oldX = self.x, oldY = self.y; self.x = nextX; self.y = nextY; if (self.intersects(ball)) { blocked = true; } self.x = oldX; self.y = oldY; if (blocked) break; } } // Map boundaries for profesor in level 4 var leftWall = 40; var rightWall = 2048 - 40; var topWall = 40; var bottomWall = 2732 - 40; var profesorLeft = nextX - 80; var profesorRight = nextX + 80; var profesorTop = nextY - 80; var profesorBottom = nextY + 80; if (profesorLeft < leftWall || profesorRight > rightWall || profesorTop < topWall || profesorBottom > bottomWall) { blocked = true; } } // If not blocked, move if (!blocked) { self.x = nextX; self.y = nextY; } } else { self.x = student.x; self.y = student.y; } }; return self; }); // Student class: controllable player character var Student = Container.expand(function () { var self = Container.call(this); // Attach student asset var studentSprite = self.attachAsset('student', { anchorX: 0.5, anchorY: 0.5 }); // Initial target position is current position self.targetX = 300; self.targetY = 2732 / 2; // Track last position for event logic self.lastX = self.x; self.lastY = self.y; // Update method: move towards target position self.update = function () { // Store last position self.lastX = self.x; self.lastY = self.y; // Move towards targetX, targetY var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 18; // pixels per frame if (dist > speed) { self.x += dx / dist * speed; self.y += dy / dist * speed; } else { self.x = self.targetX; self.y = self.targetY; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Level system // Rocky park floor for level 3 (must be present in asset library) var currentLevel = 1; var maxLevel = 4; // Now 4 levels // Helper to clear all children except joystick and overlays function clearGameObjects() { // Remove all children except overlays and joystick for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; // Don't remove overlays or joystick (which are in LK.gui) game.removeChild(child); } // Clear level 2 obstacles array if present if (game.level2Obstacles) { game.level2Obstacles.length = 0; } } // Helper to setup a level function setupLevel(level) { clearGameObjects(); // Main floor (covers the whole map) - different for each level var floorAssetId; if (level === 1) { floorAssetId = 'floor'; // Default school floor } else if (level === 2) { floorAssetId = 'floor'; // Piso normal para el nivel 2 } else if (level === 3) { floorAssetId = 'floor_rocky'; // Use a rocky park floor for level 3 } else if (level === 4) { floorAssetId = 'floor_placa'; // Piso de placa para el nivel 4 } var floor = LK.getAsset(floorAssetId, { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(floor); // Top and bottom walls (main corridor) var wallTop, wallBottom, wallLeft, wallRight; if (level === 3) { // Level 3: Rocky park, open area with rocks as obstacles and a new door position // Remove corridor walls, use only map boundaries wallTop = LK.getAsset('wall', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); wallBottom = LK.getAsset('wall', { x: 0, y: 2732 - 40, anchorX: 0, anchorY: 0 }); wallLeft = LK.getAsset('wall', { width: 40, height: 2732, x: 0, y: 0, anchorX: 0, anchorY: 0 }); wallRight = LK.getAsset('wall', { width: 40, height: 2732, x: 2048 - 40, y: 0, anchorX: 0, anchorY: 0 }); } else if (level === 2) { // Narrow hallway: corridor is 520px tall, centered vertically var corridorHeight = 520; var corridorY = (2732 - corridorHeight) / 2; wallTop = LK.getAsset('wall', { x: 0, y: corridorY - 40, anchorX: 0, anchorY: 0 }); wallBottom = LK.getAsset('wall', { x: 0, y: corridorY + corridorHeight, anchorX: 0, anchorY: 0 }); // Left and right walls (vertical boundaries) wallLeft = LK.getAsset('wall', { width: 40, height: corridorHeight, x: 0, y: corridorY, anchorX: 0, anchorY: 0 }); wallRight = LK.getAsset('wall', { width: 40, height: corridorHeight, x: 2048 - 40, y: corridorY, anchorX: 0, anchorY: 0 }); } else { wallTop = LK.getAsset('wall', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); wallBottom = LK.getAsset('wall', { x: 0, y: 2732 - 40, anchorX: 0, anchorY: 0 }); wallLeft = LK.getAsset('wall', { width: 40, height: 2732, x: 0, y: 0, anchorX: 0, anchorY: 0 }); wallRight = LK.getAsset('wall', { width: 40, height: 2732, x: 2048 - 40, y: 0, anchorX: 0, anchorY: 0 }); } game.addChild(wallTop); game.addChild(wallBottom); game.addChild(wallLeft); game.addChild(wallRight); // Add door (exit) for each level if (level === 1) { door = LK.getAsset('door', { x: 2048 - 200, y: 2200, anchorX: 0, anchorY: 0 }); } else if (level === 2) { // Level 2: Hallway with open doors as obstacles, exit at the end, profesor behind // Place the exit door at the far right end of the hallway, centered in corridor var corridorHeight = 520; var corridorY = (2732 - corridorHeight) / 2; door = LK.getAsset('door', { x: 2048 - 200, y: corridorY + corridorHeight / 2 - 200, anchorX: 0, anchorY: 0 }); // Add open doors as obstacles along the hallway // We'll use furniture assets as open doors (obstacles) var numObstacles = 3; var spacing = (2048 - 400) / (numObstacles + 1); for (var i = 1; i <= numObstacles; i++) { var obsX = i * spacing + 100; // Obstacles alternate above and below the center line, but always inside the corridor var obsY; if (i % 2 === 0) { obsY = corridorY + 120; } else { obsY = corridorY + corridorHeight - 120; } var obstacle = LK.getAsset('furniture', { width: 180, height: 60, anchorX: 0.5, anchorY: 0.5, x: obsX, y: obsY }); game.addChild(obstacle); // Store obstacles for collision in global array if (!game.level2Obstacles) game.level2Obstacles = []; game.level2Obstacles.push(obstacle); } } // Level 3: Add rocky obstacles and new door position if (level === 3) { // Place the exit door at the top right corner of the park door = LK.getAsset('door', { x: 2048 - 320, y: 180, anchorX: 0, anchorY: 0 }); // Add rocky obstacles (use 'furniture' asset as rocks, but with different positions and sizes) var rocks = [{ x: 600, y: 700, w: 180, h: 120 }, { x: 1200, y: 500, w: 220, h: 100 }, { x: 900, y: 1400, w: 160, h: 160 }, { x: 1500, y: 900, w: 200, h: 120 }, { x: 400, y: 2000, w: 180, h: 120 }]; if (!game.level3Obstacles) game.level3Obstacles = []; game.level3Obstacles.length = 0; for (var i = 0; i < rocks.length; i++) { var r = rocks[i]; var rock = LK.getAsset('furniture', { width: r.w, height: r.h, anchorX: 0.5, anchorY: 0.5, x: r.x, y: r.y }); game.addChild(rock); game.level3Obstacles.push(rock); } } // Level 4: Add maze, soccer balls, and door if (level === 4) { // Place the exit door at the top right of the maze door = LK.getAsset('door', { x: 2048 - 320, y: 180, anchorX: 0, anchorY: 0 }); // Maze walls (using 'wall' asset, horizontal and vertical) // Each wall: {x, y, width, height} var mazeWalls = [ // Outer boundaries (already added above, but can reinforce) { x: 0, y: 0, width: 2048, height: 40 }, { x: 0, y: 2732 - 40, width: 2048, height: 40 }, { x: 0, y: 0, width: 40, height: 2732 }, { x: 2048 - 40, y: 0, width: 40, height: 2732 }, // Maze interior (example layout, can be adjusted) { x: 200, y: 400, width: 1648, height: 40 }, { x: 200, y: 800, width: 1200, height: 40 }, { x: 600, y: 1200, width: 1200, height: 40 }, { x: 200, y: 1600, width: 1000, height: 40 }, { x: 800, y: 2000, width: 1000, height: 40 }, { x: 400, y: 2200, width: 1200, height: 40 }, // Vertical walls { x: 400, y: 400, width: 40, height: 800 }, { x: 800, y: 800, width: 40, height: 800 }, { x: 1200, y: 1200, width: 40, height: 800 }, { x: 1600, y: 400, width: 40, height: 1200 }, { x: 1800, y: 1600, width: 40, height: 800 }]; if (!game.level4MazeWalls) game.level4MazeWalls = []; game.level4MazeWalls.length = 0; for (var i = 0; i < mazeWalls.length; i++) { var mw = mazeWalls[i]; var wall = LK.getAsset('wall', { width: mw.width, height: mw.height, x: mw.x, y: mw.y, anchorX: 0, anchorY: 0 }); game.addChild(wall); game.level4MazeWalls.push(wall); } // Soccer balls as obstacles (use 'furniture' asset, but could be replaced with a soccer ball asset) // Place many balls scattered in the maze var soccerBalls = [{ x: 300, y: 600 }, { x: 500, y: 900 }, { x: 700, y: 500 }, { x: 900, y: 1300 }, { x: 1100, y: 700 }, { x: 1300, y: 1100 }, { x: 1500, y: 1500 }, { x: 1700, y: 1900 }, { x: 600, y: 1700 }, { x: 800, y: 2100 }, { x: 1000, y: 2300 }, { x: 1200, y: 1900 }, { x: 1400, y: 2100 }, { x: 1600, y: 2300 }, { x: 1800, y: 2100 }, { x: 1800, y: 400 }, { x: 400, y: 2000 }, { x: 600, y: 2200 }, { x: 900, y: 1800 }, { x: 1100, y: 1500 }]; if (!game.level4SoccerBalls) game.level4SoccerBalls = []; game.level4SoccerBalls.length = 0; for (var i = 0; i < soccerBalls.length; i++) { var sb = soccerBalls[i]; var ball = LK.getAsset('furniture', { width: 100, height: 100, anchorX: 0.5, anchorY: 0.5, x: sb.x, y: sb.y }); game.addChild(ball); game.level4SoccerBalls.push(ball); } } game.addChild(door); // Add student (player) and center camera on them student = new Student(); if (level === 1) { student.x = 300; student.y = 2732 / 2; } else if (level === 2) { // Start at the far left of the hallway student.x = 200; student.y = 2732 / 2; } else if (level === 3) { // Start at bottom left of the park student.x = 200; student.y = 2400; } else if (level === 4) { // Start at bottom left of the maze student.x = 120; student.y = 2600; } game.addChild(student); // Add profesor (monster) as an AI-driven monster profesor = new ProfesorMonster(); if (level === 1) { profesor.x = 1600; profesor.y = 2732 / 2; } else if (level === 2) { // Profesor starts behind the student, at the left edge profesor.x = 60; profesor.y = 2732 / 2; // Make profesor slower for this level profesor.level2Slow = true; } else if (level === 3) { // Profesor starts at the center of the park profesor.x = 1024; profesor.y = 900; } else if (level === 4) { // Profesor starts at the bottom of the maze, far from the student profesor.x = 1800; profesor.y = 2600; } game.addChild(profesor); // Camera offset for 3rd person (centered on student) cameraOffsetX = 1024; // half width cameraOffsetY = 1366; // half height // Reset popup/question state showMathQuestion = false; mathQuestionPopup = null; } var door, student, profesor, cameraOffsetX, cameraOffsetY; setupLevel(currentLevel); // Camera follow logic game.update = function () { // Update student if (student.update) student.update(); // Level 2: Check collision with obstacles (open doors) if (currentLevel === 2 && game.level2Obstacles && student) { for (var i = 0; i < game.level2Obstacles.length; i++) { var obs = game.level2Obstacles[i]; if (student.intersects(obs)) { // Block movement: revert to last position and prevent further movement in this update student.x = student.lastX; student.y = student.lastY; // Also update targetX/targetY so the student doesn't keep trying to move into the obstacle student.targetX = student.lastX; student.targetY = student.lastY; break; // Stop checking further obstacles this frame } } // Corridor wall collision (block student from passing through corridor) // Get corridor bounds from setupLevel var corridorHeight = 520; var corridorY = (2732 - corridorHeight) / 2; var corridorTop = corridorY; var corridorBottom = corridorY + corridorHeight; // Student's bounding box var studentTop = student.y - 60; var studentBottom = student.y + 60; // If student tries to go above the corridor if (studentTop < corridorTop) { student.y = corridorTop + 60; } // If student tries to go below the corridor if (studentBottom > corridorBottom) { student.y = corridorBottom - 60; } // Block left and right walls var leftWall = 40; var rightWall = 2048 - 40; var studentLeft = student.x - 60; var studentRight = student.x + 60; if (studentLeft < leftWall) { student.x = leftWall + 60; } if (studentRight > rightWall) { student.x = rightWall - 60; } } // Level 3: Check collision with rocky obstacles if (currentLevel === 3 && game.level3Obstacles && student) { for (var i = 0; i < game.level3Obstacles.length; i++) { var rock = game.level3Obstacles[i]; if (student.intersects(rock)) { // Block movement: revert to last position and prevent further movement in this update student.x = student.lastX; student.y = student.lastY; student.targetX = student.lastX; student.targetY = student.lastY; break; } } // Block map boundaries var leftWall = 40; var rightWall = 2048 - 40; var topWall = 40; var bottomWall = 2732 - 40; var studentLeft = student.x - 60; var studentRight = student.x + 60; var studentTop = student.y - 60; var studentBottom = student.y + 60; if (studentLeft < leftWall) { student.x = leftWall + 60; } if (studentRight > rightWall) { student.x = rightWall - 60; } if (studentTop < topWall) { student.y = topWall + 60; } if (studentBottom > bottomWall) { student.y = bottomWall - 60; } } // Level 4: Check collision with maze walls and soccer balls if (currentLevel === 4 && student) { // Maze wall collision if (game.level4MazeWalls) { for (var i = 0; i < game.level4MazeWalls.length; i++) { var wall = game.level4MazeWalls[i]; if (student.intersects(wall)) { student.x = student.lastX; student.y = student.lastY; student.targetX = student.lastX; student.targetY = student.lastY; break; } } } // Soccer ball collision if (game.level4SoccerBalls) { for (var i = 0; i < game.level4SoccerBalls.length; i++) { var ball = game.level4SoccerBalls[i]; if (student.intersects(ball)) { student.x = student.lastX; student.y = student.lastY; student.targetX = student.lastX; student.targetY = student.lastY; break; } } } // Block map boundaries var leftWall = 40; var rightWall = 2048 - 40; var topWall = 40; var bottomWall = 2732 - 40; var studentLeft = student.x - 60; var studentRight = student.x + 60; var studentTop = student.y - 60; var studentBottom = student.y + 60; if (studentLeft < leftWall) { student.x = leftWall + 60; } if (studentRight > rightWall) { student.x = rightWall - 60; } if (studentTop < topWall) { student.y = topWall + 60; } if (studentBottom > bottomWall) { student.y = bottomWall - 60; } } // Update profesor monster AI if (profesor.update) { // Slow profesor in level 2 if (currentLevel === 2 && profesor.level2Slow) { // Temporarily override update to move slower var oldSpeed = 6; profesor.update = function () { this.lastX = this.x; this.lastY = this.y; if (typeof showMathQuestion !== "undefined" && showMathQuestion || typeof student !== "undefined" && typeof student.lastWasIntersectingDoor !== "undefined" && student.lastWasIntersectingDoor) { return; } if (typeof student === "undefined" || !student) return; var dx = student.x - this.x; var dy = student.y - this.y; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 3; // slower speed for level 2 if (dist > speed) { this.x += dx / dist * speed; this.y += dy / dist * speed; } else { this.x = student.x; this.y = student.y; } }; } profesor.update(); } // Check for kill: profesor touches student (collision) var isIntersecting = profesor.intersects(student); if (!profesor.lastWasIntersecting && isIntersecting) { // Profesor kills student: show game over LK.effects.flashScreen(0xff0000, 1000); // Reset to level 1 after game over currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1200); LK.showGameOver(); } profesor.lastWasIntersecting = isIntersecting; // Check if student touches the door (minimum contact triggers question) if ((typeof showMathQuestion === "undefined" || !showMathQuestion) && door && student && !student.lastWasIntersectingDoor && student.intersects(door)) { showMathQuestion = true; student.lastWasIntersectingDoor = true; // Show the math question in-game as a fullscreen overlay with large, high-contrast text and options if (typeof mathQuestionPopup === "undefined" || !mathQuestionPopup) { mathQuestionPopup = new Container(); // Fullscreen transparent background (no purple, just to block input) var bg = LK.getAsset('furniture', { width: 2048, height: 2732, color: 0x000000, anchorX: 0, anchorY: 0 }); bg.alpha = 0.01; // almost invisible, just to block input mathQuestionPopup.addChild(bg); // Define questions and answers for each level/door // You can expand this array for more levels/doors var questions = [{ question: "¿Cuánto es 8 × 6?", options: [{ text: "1) 42", correct: false }, { text: "2) 48", correct: true }, { text: "3) 54", correct: false }] }, { question: "¿Cuánto es 7 × 22?", options: [{ text: "1) 144", correct: false }, { text: "2) 154", correct: true }, { text: "3) 127", correct: false }] }, { question: "¿Cuánto es 13 × 5?", options: [{ text: "1) 65", correct: true }, { text: "2) 45", correct: false }, { text: "3) 75", correct: false }] }]; // Pick question by level (default to first if out of range) var qIndex = typeof currentLevel !== "undefined" && currentLevel - 1 < questions.length ? currentLevel - 1 : 0; var qData = questions[qIndex]; // Question text - very large, high-contrast, centered var questionText = new Text2(qData.question, { size: 180, fill: 0xFFF700 // bright yellow for contrast }); questionText.anchor.set(0.5, 0); questionText.x = 2048 / 2; questionText.y = 320; mathQuestionPopup.addChild(questionText); // Render options var optionYStart = 800; var optionYStep = 300; var optionObjs = []; for (var i = 0; i < qData.options.length; i++) { var opt = qData.options[i]; var optObj = new Text2(opt.text, { size: 140, fill: 0xFFFFFF }); optObj.anchor.set(0.5, 0); optObj.x = 2048 / 2; optObj.y = optionYStart + i * optionYStep; mathQuestionPopup.addChild(optObj); optionObjs.push(optObj); // Add interaction for options optObj.interactive = true; optObj.buttonMode = true; if (opt.correct) { optObj.down = function () { LK.effects.flashScreen(0x00ff00, 800); // Open the door: remove it from the game scene if (door && door.parent) { door.parent.removeChild(door); door = null; } if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup); mathQuestionPopup = null; showMathQuestion = false; // Advance to next level or win if (typeof currentLevel !== "undefined" && typeof maxLevel !== "undefined") { if (currentLevel < maxLevel) { currentLevel += 1; setupLevel(currentLevel); } else { LK.showYouWin(); } } }; } else { optObj.down = function () { LK.effects.flashScreen(0xff0000, 800); // Reset to level 1 after game over currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1000); LK.showGameOver(); if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup); mathQuestionPopup = null; showMathQuestion = false; }; } } // Fullscreen, no pivot, top-left at (0,0) mathQuestionPopup.x = 0; mathQuestionPopup.y = 0; game.addChild(mathQuestionPopup); } } // Track lastX for student for event logic student.lastX = student.x; student.lastY = student.y; // Track last intersection with door for event logic if (door && student) { if (typeof student.lastWasIntersectingDoor === "undefined") student.lastWasIntersectingDoor = false; var nowIntersectingDoor = student.intersects(door); student.lastWasIntersectingDoor = nowIntersectingDoor; } // Camera follows student from behind (3rd person, offset behind student direction) var dx = student.targetX - student.x; var dy = student.targetY - student.y; var dist = Math.sqrt(dx * dx + dy * dy); var camBehindDist = 350; // Distance behind the student var camX, camY; if (dist > 10) { // Camera is offset behind the student, in the opposite direction of movement camX = student.x - dx / dist * camBehindDist; camY = student.y - dy / dist * camBehindDist; } else { // If not moving, camera stays slightly above/behind camX = student.x - camBehindDist; camY = student.y; } // Clamp camera to map bounds camX = Math.max(0, Math.min(camX, 2048 - 2048)); camY = Math.max(0, Math.min(camY, 2732 - 2732)); game.x = -camX; game.y = -camY; }; // On-screen joystick controls for student movement // Joystick visual base var joystickBase = LK.getAsset('furniture', { width: 260, height: 260, color: 0x222222, anchorX: 0.5, anchorY: 0.5, x: 260, y: 2732 - 260 }); joystickBase.alpha = 0.25; LK.gui.left.addChild(joystickBase); // Joystick thumb var joystickThumb = LK.getAsset('furniture', { width: 120, height: 120, color: 0xffffff, anchorX: 0.5, anchorY: 0.5, x: 260, y: 2732 - 260 }); joystickThumb.alpha = 0.7; LK.gui.left.addChild(joystickThumb); var joystickActive = false; var joystickStartX = 0; var joystickStartY = 0; var joystickRadius = 110; // Helper to convert GUI to game coordinates function guiToGameCoords(guiX, guiY) { // For this game, joystick is always at bottom left, so just return as is return { x: guiX, y: guiY }; } // Joystick down joystickBase.interactive = true; joystickBase.buttonMode = true; joystickBase.down = function (x, y, obj) { joystickActive = true; joystickStartX = joystickBase.x; joystickStartY = joystickBase.y; joystickThumb.x = x; joystickThumb.y = y; }; // Joystick move joystickBase.move = function (x, y, obj) { if (!joystickActive) return; var dx = x - joystickStartX; var dy = y - joystickStartY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > joystickRadius) { dx = dx / dist * joystickRadius; dy = dy / dist * joystickRadius; } joystickThumb.x = joystickStartX + dx; joystickThumb.y = joystickStartY + dy; // Move student target relative to joystick direction var moveStrength = dist > 20 ? 1 : 0; // Deadzone if (moveStrength) { // Map joystick to game area var moveX = student.x + dx * 3; var moveY = student.y + dy * 3; student.targetX = Math.max(60, Math.min(2048 - 60, moveX)); student.targetY = Math.max(60, Math.min(2732 - 60, moveY)); } }; // Joystick up joystickBase.up = function (x, y, obj) { joystickActive = false; joystickThumb.x = joystickBase.x; joystickThumb.y = joystickBase.y; }; // Also allow drag-to-move for desktop or direct touch game.down = function (x, y, obj) { if (!joystickActive) { student.targetX = x; student.targetY = y; } }; game.move = function (x, y, obj) { if (!joystickActive) { student.targetX = x; student.targetY = y; } }; game.up = function (x, y, obj) { // No-op for now };
/****
* Classes
****/
// ProfesorMonster class: AI-driven monster that chases the student
var ProfesorMonster = Container.expand(function () {
var self = Container.call(this);
// Attach profesor asset
var profesorSprite = self.attachAsset('profesor', {
anchorX: 0.5,
anchorY: 0.5
});
// Track last position for event logic
self.lastX = self.x;
self.lastY = self.y;
self.lastWasIntersecting = false;
// Update method: chase the student
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Immobilize profesor if student is touching the door (popup active)
if (typeof showMathQuestion !== "undefined" && showMathQuestion || typeof student !== "undefined" && typeof student.lastWasIntersectingDoor !== "undefined" && student.lastWasIntersectingDoor) {
// Profesor stays still, do not move
return;
}
// Use global student variable
if (typeof student === "undefined" || !student) return;
// Simple AI: move towards the student
var dx = student.x - self.x;
var dy = student.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 6; // profesor speed, now much slower than student
if (dist > speed) {
// Calculate intended new position
var nextX = self.x + dx / dist * speed;
var nextY = self.y + dy / dist * speed;
var blocked = false;
// Level 2: block profesor on obstacles
if (typeof currentLevel !== "undefined" && currentLevel === 2 && typeof game !== "undefined" && game.level2Obstacles) {
for (var i = 0; i < game.level2Obstacles.length; i++) {
var obs = game.level2Obstacles[i];
// Simulate move: temporarily set position, check collision, revert
var oldX = self.x,
oldY = self.y;
self.x = nextX;
self.y = nextY;
if (self.intersects(obs)) {
blocked = true;
}
self.x = oldX;
self.y = oldY;
if (blocked) break;
}
}
// Level 2: also block corridor walls
if (!blocked && typeof currentLevel !== "undefined" && currentLevel === 2) {
var corridorHeight = 520;
var corridorY = (2732 - corridorHeight) / 2;
var corridorTop = corridorY;
var corridorBottom = corridorY + corridorHeight;
var leftWall = 40;
var rightWall = 2048 - 40;
var profesorTop = nextY - 80;
var profesorBottom = nextY + 80;
var profesorLeft = nextX - 80;
var profesorRight = nextX + 80;
if (profesorTop < corridorTop || profesorBottom > corridorBottom || profesorLeft < leftWall || profesorRight > rightWall) {
blocked = true;
}
}
// Level 3: block profesor on rocks and map boundaries
if (!blocked && typeof currentLevel !== "undefined" && currentLevel === 3 && typeof game !== "undefined" && game.level3Obstacles) {
for (var i = 0; i < game.level3Obstacles.length; i++) {
var rock = game.level3Obstacles[i];
var oldX = self.x,
oldY = self.y;
self.x = nextX;
self.y = nextY;
if (self.intersects(rock)) {
blocked = true;
}
self.x = oldX;
self.y = oldY;
if (blocked) break;
}
// Map boundaries for profesor in level 3
var leftWall = 40;
var rightWall = 2048 - 40;
var topWall = 40;
var bottomWall = 2732 - 40;
var profesorLeft = nextX - 80;
var profesorRight = nextX + 80;
var profesorTop = nextY - 80;
var profesorBottom = nextY + 80;
if (profesorLeft < leftWall || profesorRight > rightWall || profesorTop < topWall || profesorBottom > bottomWall) {
blocked = true;
}
}
// Level 4: block profesor on maze walls and soccer balls and map boundaries
if (!blocked && typeof currentLevel !== "undefined" && currentLevel === 4 && typeof game !== "undefined") {
// Maze walls
if (game.level4MazeWalls) {
for (var i = 0; i < game.level4MazeWalls.length; i++) {
var wall = game.level4MazeWalls[i];
var oldX = self.x,
oldY = self.y;
self.x = nextX;
self.y = nextY;
if (self.intersects(wall)) {
blocked = true;
}
self.x = oldX;
self.y = oldY;
if (blocked) break;
}
}
// Soccer balls
if (!blocked && game.level4SoccerBalls) {
for (var i = 0; i < game.level4SoccerBalls.length; i++) {
var ball = game.level4SoccerBalls[i];
var oldX = self.x,
oldY = self.y;
self.x = nextX;
self.y = nextY;
if (self.intersects(ball)) {
blocked = true;
}
self.x = oldX;
self.y = oldY;
if (blocked) break;
}
}
// Map boundaries for profesor in level 4
var leftWall = 40;
var rightWall = 2048 - 40;
var topWall = 40;
var bottomWall = 2732 - 40;
var profesorLeft = nextX - 80;
var profesorRight = nextX + 80;
var profesorTop = nextY - 80;
var profesorBottom = nextY + 80;
if (profesorLeft < leftWall || profesorRight > rightWall || profesorTop < topWall || profesorBottom > bottomWall) {
blocked = true;
}
}
// If not blocked, move
if (!blocked) {
self.x = nextX;
self.y = nextY;
}
} else {
self.x = student.x;
self.y = student.y;
}
};
return self;
});
// Student class: controllable player character
var Student = Container.expand(function () {
var self = Container.call(this);
// Attach student asset
var studentSprite = self.attachAsset('student', {
anchorX: 0.5,
anchorY: 0.5
});
// Initial target position is current position
self.targetX = 300;
self.targetY = 2732 / 2;
// Track last position for event logic
self.lastX = self.x;
self.lastY = self.y;
// Update method: move towards target position
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move towards targetX, targetY
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 18; // pixels per frame
if (dist > speed) {
self.x += dx / dist * speed;
self.y += dy / dist * speed;
} else {
self.x = self.targetX;
self.y = self.targetY;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Level system
// Rocky park floor for level 3 (must be present in asset library)
var currentLevel = 1;
var maxLevel = 4; // Now 4 levels
// Helper to clear all children except joystick and overlays
function clearGameObjects() {
// Remove all children except overlays and joystick
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
// Don't remove overlays or joystick (which are in LK.gui)
game.removeChild(child);
}
// Clear level 2 obstacles array if present
if (game.level2Obstacles) {
game.level2Obstacles.length = 0;
}
}
// Helper to setup a level
function setupLevel(level) {
clearGameObjects();
// Main floor (covers the whole map) - different for each level
var floorAssetId;
if (level === 1) {
floorAssetId = 'floor'; // Default school floor
} else if (level === 2) {
floorAssetId = 'floor'; // Piso normal para el nivel 2
} else if (level === 3) {
floorAssetId = 'floor_rocky'; // Use a rocky park floor for level 3
} else if (level === 4) {
floorAssetId = 'floor_placa'; // Piso de placa para el nivel 4
}
var floor = LK.getAsset(floorAssetId, {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(floor);
// Top and bottom walls (main corridor)
var wallTop, wallBottom, wallLeft, wallRight;
if (level === 3) {
// Level 3: Rocky park, open area with rocks as obstacles and a new door position
// Remove corridor walls, use only map boundaries
wallTop = LK.getAsset('wall', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
wallBottom = LK.getAsset('wall', {
x: 0,
y: 2732 - 40,
anchorX: 0,
anchorY: 0
});
wallLeft = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
wallRight = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 2048 - 40,
y: 0,
anchorX: 0,
anchorY: 0
});
} else if (level === 2) {
// Narrow hallway: corridor is 520px tall, centered vertically
var corridorHeight = 520;
var corridorY = (2732 - corridorHeight) / 2;
wallTop = LK.getAsset('wall', {
x: 0,
y: corridorY - 40,
anchorX: 0,
anchorY: 0
});
wallBottom = LK.getAsset('wall', {
x: 0,
y: corridorY + corridorHeight,
anchorX: 0,
anchorY: 0
});
// Left and right walls (vertical boundaries)
wallLeft = LK.getAsset('wall', {
width: 40,
height: corridorHeight,
x: 0,
y: corridorY,
anchorX: 0,
anchorY: 0
});
wallRight = LK.getAsset('wall', {
width: 40,
height: corridorHeight,
x: 2048 - 40,
y: corridorY,
anchorX: 0,
anchorY: 0
});
} else {
wallTop = LK.getAsset('wall', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
wallBottom = LK.getAsset('wall', {
x: 0,
y: 2732 - 40,
anchorX: 0,
anchorY: 0
});
wallLeft = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
wallRight = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 2048 - 40,
y: 0,
anchorX: 0,
anchorY: 0
});
}
game.addChild(wallTop);
game.addChild(wallBottom);
game.addChild(wallLeft);
game.addChild(wallRight);
// Add door (exit) for each level
if (level === 1) {
door = LK.getAsset('door', {
x: 2048 - 200,
y: 2200,
anchorX: 0,
anchorY: 0
});
} else if (level === 2) {
// Level 2: Hallway with open doors as obstacles, exit at the end, profesor behind
// Place the exit door at the far right end of the hallway, centered in corridor
var corridorHeight = 520;
var corridorY = (2732 - corridorHeight) / 2;
door = LK.getAsset('door', {
x: 2048 - 200,
y: corridorY + corridorHeight / 2 - 200,
anchorX: 0,
anchorY: 0
});
// Add open doors as obstacles along the hallway
// We'll use furniture assets as open doors (obstacles)
var numObstacles = 3;
var spacing = (2048 - 400) / (numObstacles + 1);
for (var i = 1; i <= numObstacles; i++) {
var obsX = i * spacing + 100;
// Obstacles alternate above and below the center line, but always inside the corridor
var obsY;
if (i % 2 === 0) {
obsY = corridorY + 120;
} else {
obsY = corridorY + corridorHeight - 120;
}
var obstacle = LK.getAsset('furniture', {
width: 180,
height: 60,
anchorX: 0.5,
anchorY: 0.5,
x: obsX,
y: obsY
});
game.addChild(obstacle);
// Store obstacles for collision in global array
if (!game.level2Obstacles) game.level2Obstacles = [];
game.level2Obstacles.push(obstacle);
}
}
// Level 3: Add rocky obstacles and new door position
if (level === 3) {
// Place the exit door at the top right corner of the park
door = LK.getAsset('door', {
x: 2048 - 320,
y: 180,
anchorX: 0,
anchorY: 0
});
// Add rocky obstacles (use 'furniture' asset as rocks, but with different positions and sizes)
var rocks = [{
x: 600,
y: 700,
w: 180,
h: 120
}, {
x: 1200,
y: 500,
w: 220,
h: 100
}, {
x: 900,
y: 1400,
w: 160,
h: 160
}, {
x: 1500,
y: 900,
w: 200,
h: 120
}, {
x: 400,
y: 2000,
w: 180,
h: 120
}];
if (!game.level3Obstacles) game.level3Obstacles = [];
game.level3Obstacles.length = 0;
for (var i = 0; i < rocks.length; i++) {
var r = rocks[i];
var rock = LK.getAsset('furniture', {
width: r.w,
height: r.h,
anchorX: 0.5,
anchorY: 0.5,
x: r.x,
y: r.y
});
game.addChild(rock);
game.level3Obstacles.push(rock);
}
}
// Level 4: Add maze, soccer balls, and door
if (level === 4) {
// Place the exit door at the top right of the maze
door = LK.getAsset('door', {
x: 2048 - 320,
y: 180,
anchorX: 0,
anchorY: 0
});
// Maze walls (using 'wall' asset, horizontal and vertical)
// Each wall: {x, y, width, height}
var mazeWalls = [
// Outer boundaries (already added above, but can reinforce)
{
x: 0,
y: 0,
width: 2048,
height: 40
}, {
x: 0,
y: 2732 - 40,
width: 2048,
height: 40
}, {
x: 0,
y: 0,
width: 40,
height: 2732
}, {
x: 2048 - 40,
y: 0,
width: 40,
height: 2732
},
// Maze interior (example layout, can be adjusted)
{
x: 200,
y: 400,
width: 1648,
height: 40
}, {
x: 200,
y: 800,
width: 1200,
height: 40
}, {
x: 600,
y: 1200,
width: 1200,
height: 40
}, {
x: 200,
y: 1600,
width: 1000,
height: 40
}, {
x: 800,
y: 2000,
width: 1000,
height: 40
}, {
x: 400,
y: 2200,
width: 1200,
height: 40
},
// Vertical walls
{
x: 400,
y: 400,
width: 40,
height: 800
}, {
x: 800,
y: 800,
width: 40,
height: 800
}, {
x: 1200,
y: 1200,
width: 40,
height: 800
}, {
x: 1600,
y: 400,
width: 40,
height: 1200
}, {
x: 1800,
y: 1600,
width: 40,
height: 800
}];
if (!game.level4MazeWalls) game.level4MazeWalls = [];
game.level4MazeWalls.length = 0;
for (var i = 0; i < mazeWalls.length; i++) {
var mw = mazeWalls[i];
var wall = LK.getAsset('wall', {
width: mw.width,
height: mw.height,
x: mw.x,
y: mw.y,
anchorX: 0,
anchorY: 0
});
game.addChild(wall);
game.level4MazeWalls.push(wall);
}
// Soccer balls as obstacles (use 'furniture' asset, but could be replaced with a soccer ball asset)
// Place many balls scattered in the maze
var soccerBalls = [{
x: 300,
y: 600
}, {
x: 500,
y: 900
}, {
x: 700,
y: 500
}, {
x: 900,
y: 1300
}, {
x: 1100,
y: 700
}, {
x: 1300,
y: 1100
}, {
x: 1500,
y: 1500
}, {
x: 1700,
y: 1900
}, {
x: 600,
y: 1700
}, {
x: 800,
y: 2100
}, {
x: 1000,
y: 2300
}, {
x: 1200,
y: 1900
}, {
x: 1400,
y: 2100
}, {
x: 1600,
y: 2300
}, {
x: 1800,
y: 2100
}, {
x: 1800,
y: 400
}, {
x: 400,
y: 2000
}, {
x: 600,
y: 2200
}, {
x: 900,
y: 1800
}, {
x: 1100,
y: 1500
}];
if (!game.level4SoccerBalls) game.level4SoccerBalls = [];
game.level4SoccerBalls.length = 0;
for (var i = 0; i < soccerBalls.length; i++) {
var sb = soccerBalls[i];
var ball = LK.getAsset('furniture', {
width: 100,
height: 100,
anchorX: 0.5,
anchorY: 0.5,
x: sb.x,
y: sb.y
});
game.addChild(ball);
game.level4SoccerBalls.push(ball);
}
}
game.addChild(door);
// Add student (player) and center camera on them
student = new Student();
if (level === 1) {
student.x = 300;
student.y = 2732 / 2;
} else if (level === 2) {
// Start at the far left of the hallway
student.x = 200;
student.y = 2732 / 2;
} else if (level === 3) {
// Start at bottom left of the park
student.x = 200;
student.y = 2400;
} else if (level === 4) {
// Start at bottom left of the maze
student.x = 120;
student.y = 2600;
}
game.addChild(student);
// Add profesor (monster) as an AI-driven monster
profesor = new ProfesorMonster();
if (level === 1) {
profesor.x = 1600;
profesor.y = 2732 / 2;
} else if (level === 2) {
// Profesor starts behind the student, at the left edge
profesor.x = 60;
profesor.y = 2732 / 2;
// Make profesor slower for this level
profesor.level2Slow = true;
} else if (level === 3) {
// Profesor starts at the center of the park
profesor.x = 1024;
profesor.y = 900;
} else if (level === 4) {
// Profesor starts at the bottom of the maze, far from the student
profesor.x = 1800;
profesor.y = 2600;
}
game.addChild(profesor);
// Camera offset for 3rd person (centered on student)
cameraOffsetX = 1024; // half width
cameraOffsetY = 1366; // half height
// Reset popup/question state
showMathQuestion = false;
mathQuestionPopup = null;
}
var door, student, profesor, cameraOffsetX, cameraOffsetY;
setupLevel(currentLevel);
// Camera follow logic
game.update = function () {
// Update student
if (student.update) student.update();
// Level 2: Check collision with obstacles (open doors)
if (currentLevel === 2 && game.level2Obstacles && student) {
for (var i = 0; i < game.level2Obstacles.length; i++) {
var obs = game.level2Obstacles[i];
if (student.intersects(obs)) {
// Block movement: revert to last position and prevent further movement in this update
student.x = student.lastX;
student.y = student.lastY;
// Also update targetX/targetY so the student doesn't keep trying to move into the obstacle
student.targetX = student.lastX;
student.targetY = student.lastY;
break; // Stop checking further obstacles this frame
}
}
// Corridor wall collision (block student from passing through corridor)
// Get corridor bounds from setupLevel
var corridorHeight = 520;
var corridorY = (2732 - corridorHeight) / 2;
var corridorTop = corridorY;
var corridorBottom = corridorY + corridorHeight;
// Student's bounding box
var studentTop = student.y - 60;
var studentBottom = student.y + 60;
// If student tries to go above the corridor
if (studentTop < corridorTop) {
student.y = corridorTop + 60;
}
// If student tries to go below the corridor
if (studentBottom > corridorBottom) {
student.y = corridorBottom - 60;
}
// Block left and right walls
var leftWall = 40;
var rightWall = 2048 - 40;
var studentLeft = student.x - 60;
var studentRight = student.x + 60;
if (studentLeft < leftWall) {
student.x = leftWall + 60;
}
if (studentRight > rightWall) {
student.x = rightWall - 60;
}
}
// Level 3: Check collision with rocky obstacles
if (currentLevel === 3 && game.level3Obstacles && student) {
for (var i = 0; i < game.level3Obstacles.length; i++) {
var rock = game.level3Obstacles[i];
if (student.intersects(rock)) {
// Block movement: revert to last position and prevent further movement in this update
student.x = student.lastX;
student.y = student.lastY;
student.targetX = student.lastX;
student.targetY = student.lastY;
break;
}
}
// Block map boundaries
var leftWall = 40;
var rightWall = 2048 - 40;
var topWall = 40;
var bottomWall = 2732 - 40;
var studentLeft = student.x - 60;
var studentRight = student.x + 60;
var studentTop = student.y - 60;
var studentBottom = student.y + 60;
if (studentLeft < leftWall) {
student.x = leftWall + 60;
}
if (studentRight > rightWall) {
student.x = rightWall - 60;
}
if (studentTop < topWall) {
student.y = topWall + 60;
}
if (studentBottom > bottomWall) {
student.y = bottomWall - 60;
}
}
// Level 4: Check collision with maze walls and soccer balls
if (currentLevel === 4 && student) {
// Maze wall collision
if (game.level4MazeWalls) {
for (var i = 0; i < game.level4MazeWalls.length; i++) {
var wall = game.level4MazeWalls[i];
if (student.intersects(wall)) {
student.x = student.lastX;
student.y = student.lastY;
student.targetX = student.lastX;
student.targetY = student.lastY;
break;
}
}
}
// Soccer ball collision
if (game.level4SoccerBalls) {
for (var i = 0; i < game.level4SoccerBalls.length; i++) {
var ball = game.level4SoccerBalls[i];
if (student.intersects(ball)) {
student.x = student.lastX;
student.y = student.lastY;
student.targetX = student.lastX;
student.targetY = student.lastY;
break;
}
}
}
// Block map boundaries
var leftWall = 40;
var rightWall = 2048 - 40;
var topWall = 40;
var bottomWall = 2732 - 40;
var studentLeft = student.x - 60;
var studentRight = student.x + 60;
var studentTop = student.y - 60;
var studentBottom = student.y + 60;
if (studentLeft < leftWall) {
student.x = leftWall + 60;
}
if (studentRight > rightWall) {
student.x = rightWall - 60;
}
if (studentTop < topWall) {
student.y = topWall + 60;
}
if (studentBottom > bottomWall) {
student.y = bottomWall - 60;
}
}
// Update profesor monster AI
if (profesor.update) {
// Slow profesor in level 2
if (currentLevel === 2 && profesor.level2Slow) {
// Temporarily override update to move slower
var oldSpeed = 6;
profesor.update = function () {
this.lastX = this.x;
this.lastY = this.y;
if (typeof showMathQuestion !== "undefined" && showMathQuestion || typeof student !== "undefined" && typeof student.lastWasIntersectingDoor !== "undefined" && student.lastWasIntersectingDoor) {
return;
}
if (typeof student === "undefined" || !student) return;
var dx = student.x - this.x;
var dy = student.y - this.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 3; // slower speed for level 2
if (dist > speed) {
this.x += dx / dist * speed;
this.y += dy / dist * speed;
} else {
this.x = student.x;
this.y = student.y;
}
};
}
profesor.update();
}
// Check for kill: profesor touches student (collision)
var isIntersecting = profesor.intersects(student);
if (!profesor.lastWasIntersecting && isIntersecting) {
// Profesor kills student: show game over
LK.effects.flashScreen(0xff0000, 1000);
// Reset to level 1 after game over
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1200);
LK.showGameOver();
}
profesor.lastWasIntersecting = isIntersecting;
// Check if student touches the door (minimum contact triggers question)
if ((typeof showMathQuestion === "undefined" || !showMathQuestion) && door && student && !student.lastWasIntersectingDoor && student.intersects(door)) {
showMathQuestion = true;
student.lastWasIntersectingDoor = true;
// Show the math question in-game as a fullscreen overlay with large, high-contrast text and options
if (typeof mathQuestionPopup === "undefined" || !mathQuestionPopup) {
mathQuestionPopup = new Container();
// Fullscreen transparent background (no purple, just to block input)
var bg = LK.getAsset('furniture', {
width: 2048,
height: 2732,
color: 0x000000,
anchorX: 0,
anchorY: 0
});
bg.alpha = 0.01; // almost invisible, just to block input
mathQuestionPopup.addChild(bg);
// Define questions and answers for each level/door
// You can expand this array for more levels/doors
var questions = [{
question: "¿Cuánto es 8 × 6?",
options: [{
text: "1) 42",
correct: false
}, {
text: "2) 48",
correct: true
}, {
text: "3) 54",
correct: false
}]
}, {
question: "¿Cuánto es 7 × 22?",
options: [{
text: "1) 144",
correct: false
}, {
text: "2) 154",
correct: true
}, {
text: "3) 127",
correct: false
}]
}, {
question: "¿Cuánto es 13 × 5?",
options: [{
text: "1) 65",
correct: true
}, {
text: "2) 45",
correct: false
}, {
text: "3) 75",
correct: false
}]
}];
// Pick question by level (default to first if out of range)
var qIndex = typeof currentLevel !== "undefined" && currentLevel - 1 < questions.length ? currentLevel - 1 : 0;
var qData = questions[qIndex];
// Question text - very large, high-contrast, centered
var questionText = new Text2(qData.question, {
size: 180,
fill: 0xFFF700 // bright yellow for contrast
});
questionText.anchor.set(0.5, 0);
questionText.x = 2048 / 2;
questionText.y = 320;
mathQuestionPopup.addChild(questionText);
// Render options
var optionYStart = 800;
var optionYStep = 300;
var optionObjs = [];
for (var i = 0; i < qData.options.length; i++) {
var opt = qData.options[i];
var optObj = new Text2(opt.text, {
size: 140,
fill: 0xFFFFFF
});
optObj.anchor.set(0.5, 0);
optObj.x = 2048 / 2;
optObj.y = optionYStart + i * optionYStep;
mathQuestionPopup.addChild(optObj);
optionObjs.push(optObj);
// Add interaction for options
optObj.interactive = true;
optObj.buttonMode = true;
if (opt.correct) {
optObj.down = function () {
LK.effects.flashScreen(0x00ff00, 800);
// Open the door: remove it from the game scene
if (door && door.parent) {
door.parent.removeChild(door);
door = null;
}
if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup);
mathQuestionPopup = null;
showMathQuestion = false;
// Advance to next level or win
if (typeof currentLevel !== "undefined" && typeof maxLevel !== "undefined") {
if (currentLevel < maxLevel) {
currentLevel += 1;
setupLevel(currentLevel);
} else {
LK.showYouWin();
}
}
};
} else {
optObj.down = function () {
LK.effects.flashScreen(0xff0000, 800);
// Reset to level 1 after game over
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1000);
LK.showGameOver();
if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup);
mathQuestionPopup = null;
showMathQuestion = false;
};
}
}
// Fullscreen, no pivot, top-left at (0,0)
mathQuestionPopup.x = 0;
mathQuestionPopup.y = 0;
game.addChild(mathQuestionPopup);
}
}
// Track lastX for student for event logic
student.lastX = student.x;
student.lastY = student.y;
// Track last intersection with door for event logic
if (door && student) {
if (typeof student.lastWasIntersectingDoor === "undefined") student.lastWasIntersectingDoor = false;
var nowIntersectingDoor = student.intersects(door);
student.lastWasIntersectingDoor = nowIntersectingDoor;
}
// Camera follows student from behind (3rd person, offset behind student direction)
var dx = student.targetX - student.x;
var dy = student.targetY - student.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var camBehindDist = 350; // Distance behind the student
var camX, camY;
if (dist > 10) {
// Camera is offset behind the student, in the opposite direction of movement
camX = student.x - dx / dist * camBehindDist;
camY = student.y - dy / dist * camBehindDist;
} else {
// If not moving, camera stays slightly above/behind
camX = student.x - camBehindDist;
camY = student.y;
}
// Clamp camera to map bounds
camX = Math.max(0, Math.min(camX, 2048 - 2048));
camY = Math.max(0, Math.min(camY, 2732 - 2732));
game.x = -camX;
game.y = -camY;
};
// On-screen joystick controls for student movement
// Joystick visual base
var joystickBase = LK.getAsset('furniture', {
width: 260,
height: 260,
color: 0x222222,
anchorX: 0.5,
anchorY: 0.5,
x: 260,
y: 2732 - 260
});
joystickBase.alpha = 0.25;
LK.gui.left.addChild(joystickBase);
// Joystick thumb
var joystickThumb = LK.getAsset('furniture', {
width: 120,
height: 120,
color: 0xffffff,
anchorX: 0.5,
anchorY: 0.5,
x: 260,
y: 2732 - 260
});
joystickThumb.alpha = 0.7;
LK.gui.left.addChild(joystickThumb);
var joystickActive = false;
var joystickStartX = 0;
var joystickStartY = 0;
var joystickRadius = 110;
// Helper to convert GUI to game coordinates
function guiToGameCoords(guiX, guiY) {
// For this game, joystick is always at bottom left, so just return as is
return {
x: guiX,
y: guiY
};
}
// Joystick down
joystickBase.interactive = true;
joystickBase.buttonMode = true;
joystickBase.down = function (x, y, obj) {
joystickActive = true;
joystickStartX = joystickBase.x;
joystickStartY = joystickBase.y;
joystickThumb.x = x;
joystickThumb.y = y;
};
// Joystick move
joystickBase.move = function (x, y, obj) {
if (!joystickActive) return;
var dx = x - joystickStartX;
var dy = y - joystickStartY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > joystickRadius) {
dx = dx / dist * joystickRadius;
dy = dy / dist * joystickRadius;
}
joystickThumb.x = joystickStartX + dx;
joystickThumb.y = joystickStartY + dy;
// Move student target relative to joystick direction
var moveStrength = dist > 20 ? 1 : 0; // Deadzone
if (moveStrength) {
// Map joystick to game area
var moveX = student.x + dx * 3;
var moveY = student.y + dy * 3;
student.targetX = Math.max(60, Math.min(2048 - 60, moveX));
student.targetY = Math.max(60, Math.min(2732 - 60, moveY));
}
};
// Joystick up
joystickBase.up = function (x, y, obj) {
joystickActive = false;
joystickThumb.x = joystickBase.x;
joystickThumb.y = joystickBase.y;
};
// Also allow drag-to-move for desktop or direct touch
game.down = function (x, y, obj) {
if (!joystickActive) {
student.targetX = x;
student.targetY = y;
}
};
game.move = function (x, y, obj) {
if (!joystickActive) {
student.targetX = x;
student.targetY = y;
}
};
game.up = function (x, y, obj) {
// No-op for now
};
Modern App Store icon, high definition, square with rounded corners, for a game titled "San Luis: El Monstruo del Colegio" and with the description "Juego de escondite en el colegio San Luis de Yarumal, donde debes evitar a un profesor monstruoso y escapar del colegio.". No text on icon!
Puerta. In-Game asset. 2d. High contrast. No shadows
Piso liso. In-Game asset. 2d. High contrast. No shadows
Un solo pupitre. In-Game asset. 2d. High contrast. No shadows
Niño pequeño con uniforme blanco y sudadera azul. In-Game asset. 2d. High contrast. No shadows
Suelo de concreto. In-Game asset. 2d. High contrast. No shadows