User prompt
Que el profesor sea lento
User prompt
Elimina los muebles
User prompt
Que el jugador se mueva
User prompt
que los muebles tengan colision
User prompt
Que en la puerta haiga una pregunta con varias obsiones la pregunta es 7×2 cuanto es obciones 13 obcion 2 14 obsion correcta 2
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var dx = student.x - self.x;' Line Number: 32
User prompt
Que el profesor bregue matar al alumno
User prompt
Please fix the bug: 'Student is not defined' in or related to this line: 'var student = new Student();' Line Number: 154
User prompt
Que el profesor brege matar a el alumno
User prompt
Please fix the bug: 'Student is not defined' in or related to this line: 'var student = new Student();' Line Number: 154
User prompt
Please fix the bug: 'Student is not defined' in or related to this line: 'var student = new Student();' Line Number: 154
User prompt
que el profesor brege matar a el jugador
User prompt
Que por cuarto haiga una puerta
User prompt
Que haiga un colegio como el de baldi
User prompt
Que la camara este atras del personaje
User prompt
Que el mapa sea de un colegio que sea muy grande cancha y de todo
User prompt
Pero has un juego en 3 persona
User prompt
Please fix the bug: 'Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 76
User prompt
Please fix the bug: 'Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 75
User prompt
Please fix the bug: 'RangeError: Maximum call stack size exceeded' in or related to this line: 'return {' Line Number: 155
Code edit (1 edits merged)
Please save this source code
User prompt
San Luis: El Monstruo del Colegio
User prompt
Juego de un colegio escondite de un profesor monstruoso y que este basado en el sanluis yarumal
User prompt
Basado en el colegio sanluis de yarumal
User prompt
Un juego de supervivencia esconderse de un monstruo en un colegio
/**** * 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 collision removed for level 4 // 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 = 8; // Now 8 levels (added sala de computo) // --- START SCREEN LOGIC --- var startScreenOverlay = null; var gameStarted = false; function showStartScreen() { if (startScreenOverlay) return; startScreenOverlay = new Container(); // Only a single prominent JUGAR button, centered var playBtn = LK.getAsset('furniture', { width: 600, height: 220, color: 0x83de44, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1200 }); playBtn.interactive = true; playBtn.buttonMode = true; startScreenOverlay.addChild(playBtn); var playText = new Text2("JUGAR", { size: 150, fill: 0x000000 }); playText.anchor.set(0.5, 0.5); playText.x = playBtn.x; playText.y = playBtn.y; startScreenOverlay.addChild(playText); playBtn.down = function () { if (startScreenOverlay && startScreenOverlay.parent) { startScreenOverlay.parent.removeChild(startScreenOverlay); } startScreenOverlay = null; gameStarted = true; setupLevel(currentLevel); }; // Add overlay to game (not GUI, so it blocks input) game.addChild(startScreenOverlay); } // Show start screen on load LK.setTimeout(function () { showStartScreen(); }, 10); // 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_rocky'; // Piso de concreto para el nivel 4 } // Only add a floor if floorAssetId is defined (skip for level 5) if (typeof floorAssetId !== "undefined") { 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} // Easy maze: outer boundaries plus a few simple interior walls var mazeWalls = [ // Outer boundaries { x: 0, y: 0, width: 2048, height: 40 }, // top { x: 0, y: 2732 - 40, width: 2048, height: 40 }, // bottom { x: 0, y: 0, width: 40, height: 2732 }, // left { x: 2048 - 40, y: 0, width: 40, height: 2732 }, // right // A few easy interior walls (horizontal and vertical, leaving wide passages) { x: 400, y: 600, width: 1200, height: 40 }, // horizontal, upper { x: 400, y: 1500, width: 1200, height: 40 }, // horizontal, lower { x: 800, y: 900, width: 40, height: 600 }, // vertical, left { x: 1200, y: 1200, width: 40, height: 600 } // vertical, right ]; 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 removed for level 4 if (!game.level4SoccerBalls) game.level4SoccerBalls = []; game.level4SoccerBalls.length = 0; } else if (level === 5) { // Level 5: Adivina la puerta correcta (guess the correct door) // Add floor for level 5 var floor = LK.getAsset('floor', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(floor); // Three doors, only one is correct if (!game.level5Doors) game.level5Doors = []; game.level5Doors.length = 0; // Place three doors spaced horizontally at the top of the map var doorY = 300; var doorSpacing = 500; var firstDoorX = 524; // Centered: (2048 - (3*240 + 2*500))/2 = 524 var correctDoorIndex = Math.floor(Math.random() * 3); // Random correct door for (var i = 0; i < 3; i++) { var d = LK.getAsset('door', { x: firstDoorX + i * (240 + doorSpacing), y: doorY, anchorX: 0, anchorY: 0 }); d.isCorrectDoor = i === correctDoorIndex; game.addChild(d); game.level5Doors.push(d); } // Add centered text above the doors in level 5 var chooseText = new Text2("Escoje la puerta correcta", { size: 120, fill: 0xFFF700 }); chooseText.anchor.set(0.5, 0.5); chooseText.x = 2048 / 2; chooseText.y = doorY - 80; game.addChild(chooseText); // No maze walls, just outer boundaries var wallTop = LK.getAsset('wall', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); var wallBottom = LK.getAsset('wall', { x: 0, y: 2732 - 40, anchorX: 0, anchorY: 0 }); var wallLeft = LK.getAsset('wall', { width: 40, height: 2732, x: 0, y: 0, anchorX: 0, anchorY: 0 }); var 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 profesor for level 5 (will chase the student) } else if (level === 6) { // Nivel 6: Patio con UN obstáculo móvil y solo una puerta de salida var floor = LK.getAsset('floor_placa', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(floor); // Solo una puerta en la parte superior, es la salida if (!game.level6Doors) game.level6Doors = []; game.level6Doors.length = 0; var doorY = 200; var doorX = 1024 - 120; // Centrada horizontalmente (2048/2 - door width/2) var d = LK.getAsset('door', { x: doorX, y: doorY, anchorX: 0, anchorY: 0 }); d.isCorrectDoor = true; game.addChild(d); game.level6Doors.push(d); // Texto de pista var chooseText6 = new Text2("¡Encuentra la puerta de salida!", { size: 120, fill: 0xFFF700 }); chooseText6.anchor.set(0.5, 0.5); chooseText6.x = 2048 / 2; chooseText6.y = doorY - 80; game.addChild(chooseText6); // Paredes exteriores var wallTop = LK.getAsset('wall', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); var wallBottom = LK.getAsset('wall', { x: 0, y: 2732 - 40, anchorX: 0, anchorY: 0 }); var wallLeft = LK.getAsset('wall', { width: 40, height: 2732, x: 0, y: 0, anchorX: 0, anchorY: 0 }); var 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); // Obstáculo móvil (solo 1 bloque que se mueve horizontalmente) if (!game.level6MovingObstacles) game.level6MovingObstacles = []; game.level6MovingObstacles.length = 0; var obsY = [1400]; // Solo un obstáculo, centrado verticalmente for (var i = 0; i < 1; i++) { var obs = LK.getAsset('furniture', { width: 320, height: 80, anchorX: 0.5, anchorY: 0.5, x: 1024, y: obsY[i] }); obs._moveDir = 1; obs._moveMin = 300; obs._moveMax = 2048 - 300; obs._moveSpeed = 10; game.addChild(obs); game.level6MovingObstacles.push(obs); } } else if (level === 7) { // Nivel 7: Laser room - dodge moving laser beams and reach the exit door var floor = LK.getAsset('floor', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(floor); // Outer walls var wallTop = LK.getAsset('wall', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); var wallBottom = LK.getAsset('wall', { x: 0, y: 2732 - 40, anchorX: 0, anchorY: 0 }); var wallLeft = LK.getAsset('wall', { width: 40, height: 2732, x: 0, y: 0, anchorX: 0, anchorY: 0 }); var 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); // Exit door at the top center if (!game.level7Door) game.level7Door = null; var doorY = 120; var doorX = 2048 / 2 - 120; var d7 = LK.getAsset('door', { x: doorX, y: doorY, anchorX: 0, anchorY: 0 }); d7.isCorrectDoor = true; game.addChild(d7); game.level7Door = d7; // Laser beams (moving obstacles) if (!game.level7Lasers) game.level7Lasers = []; game.level7Lasers.length = 0; // Each laser: {x, y, w, h, vertical, min, max, speed, dir} var lasers = [ // Horizontal lasers { x: 300, y: 700, w: 1448, h: 30, vertical: false, min: 700, max: 1200, speed: 8, dir: 1 }, { x: 300, y: 1800, w: 1448, h: 30, vertical: false, min: 1400, max: 2100, speed: 10, dir: -1 }, // Vertical lasers { x: 600, y: 400, w: 30, h: 1000, vertical: true, min: 600, max: 1400, speed: 7, dir: 1 }, { x: 1400, y: 1600, w: 30, h: 900, vertical: true, min: 900, max: 2100, speed: 9, dir: -1 }]; for (var i = 0; i < lasers.length; i++) { var l = lasers[i]; var laser = LK.getAsset('wall', { width: l.w, height: l.h, x: l.x, y: l.y, anchorX: 0, anchorY: 0 }); laser._isLaser = true; laser._vertical = l.vertical; laser._moveMin = l.min; laser._moveMax = l.max; laser._moveSpeed = l.speed; laser._moveDir = l.dir; game.addChild(laser); game.level7Lasers.push(laser); } // Instruction text var instrText = new Text2("¡Esquiva los rayos láser y escapa por la puerta!", { size: 110, fill: 0xFF2222 }); instrText.anchor.set(0.5, 0.5); instrText.x = 2048 / 2; instrText.y = 320; game.addChild(instrText); } else if (level === 8) { // Nivel 8: Sala de cómputo con escritorios como obstáculos y una sola puerta de salida var floor = LK.getAsset('floor', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(floor); // Paredes exteriores var wallTop = LK.getAsset('wall', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); var wallBottom = LK.getAsset('wall', { x: 0, y: 2732 - 40, anchorX: 0, anchorY: 0 }); var wallLeft = LK.getAsset('wall', { width: 40, height: 2732, x: 0, y: 0, anchorX: 0, anchorY: 0 }); var 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); // Puerta de salida en la parte superior derecha if (!game.level8Door) game.level8Door = null; var doorY = 120; var doorX = 2048 - 320; var d8 = LK.getAsset('door', { x: doorX, y: doorY, anchorX: 0, anchorY: 0 }); d8.isCorrectDoor = true; game.addChild(d8); game.level8Door = d8; // Escritorios como obstáculos (usando 'furniture') if (!game.level8Desks) game.level8Desks = []; game.level8Desks.length = 0; // Distribuir escritorios en filas y columnas, dejando pasillos var deskRows = 3; var deskCols = 4; var deskW = 180; var deskH = 120; var startX = 400; var startY = 700; var gapX = 320; var gapY = 400; for (var row = 0; row < deskRows; row++) { for (var col = 0; col < deskCols; col++) { // Dejar pasillo central if (col === 1 && row === 1) continue; var desk = LK.getAsset('furniture', { width: deskW, height: deskH, anchorX: 0.5, anchorY: 0.5, x: startX + col * gapX, y: startY + row * gapY }); game.addChild(desk); game.level8Desks.push(desk); } } // Texto de instrucción var instrText8 = new Text2("¡Esquiva los escritorios y escapa por la puerta!", { size: 110, fill: 0x1E90FF }); instrText8.anchor.set(0.5, 0.5); instrText8.x = 2048 / 2; instrText8.y = 320; game.addChild(instrText8); } if (level !== 5 && level !== 6 && level !== 7) { 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; } else if (level === 5) { // Start at bottom center student.x = 2048 / 2; student.y = 2500; } else if (level === 6) { // Start at bottom center student.x = 2048 / 2; student.y = 2500; } else if (level === 7) { // Start at bottom center for level 7 student.x = 2048 / 2; student.y = 2500; } else if (level === 8) { // Start at bottom left for level 8 student.x = 200; student.y = 2500; } 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; } else if (level === 5) { // Profesor starts at the bottom left in level 5 and will chase the student profesor.x = 300; profesor.y = 2500; } else if (level === 6) { // Profesor starts at the bottom right in level 6 and will chase the student profesor.x = 1800; profesor.y = 2500; } else if (level === 7) { // No profesor in level 7 profesor = null; } else if (level === 8) { // Profesor en la esquina superior izquierda, velocidad lenta profesor.x = 200; profesor.y = 200; profesor.level8Slow = true; } if (level !== 7) { 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 () { // If start screen is active, pause game logic if (!gameStarted) return; // 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 removed for level 4 // 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 && profesor.update) { // Slow profesor in level 2 if (currentLevel === 2 && profesor.level2Slow) { // Temporarily override update to move slower 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; } }; } // Slow profesor in level 8 if (currentLevel === 8 && profesor.level8Slow) { profesor.update = function () { this.lastX = this.x; this.lastY = this.y; if (typeof showMathQuestion !== "undefined" && showMathQuestion) { 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 = 2.5; // even slower for level 8 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; // Level 6: Obstáculos móviles y dos puertas if (currentLevel === 6 && game.level6MovingObstacles && student) { // Obstáculos móviles: mover y checar colisión for (var i = 0; i < game.level6MovingObstacles.length; i++) { var obs = game.level6MovingObstacles[i]; // Guardar última posición if (typeof obs.lastX === "undefined") obs.lastX = obs.x; // Movimiento horizontal obs.x += obs._moveDir * obs._moveSpeed; if (obs.x < obs._moveMin) { obs.x = obs._moveMin; obs._moveDir = 1; } if (obs.x > obs._moveMax) { obs.x = obs._moveMax; obs._moveDir = -1; } // Colisión con el estudiante if (student.intersects(obs)) { // Game over LK.effects.flashScreen(0xff0000, 1000); currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1200); LK.showGameOver(); return; } obs.lastX = obs.x; } // Checar si toca una puerta if (game.level6Doors) { for (var i = 0; i < game.level6Doors.length; i++) { var d = game.level6Doors[i]; if (!d._alreadyTriggered && student.intersects(d)) { d._alreadyTriggered = true; // Mostrar popup de resultado var popup = new Container(); var bg = LK.getAsset('furniture', { width: 2048, height: 2732, color: 0x000000, anchorX: 0, anchorY: 0 }); bg.alpha = 0.01; popup.addChild(bg); var msg = d.isCorrectDoor ? "¡Escapaste del patio!" : "¡Esa no es la puerta de salida!"; var color = d.isCorrectDoor ? 0x00FF00 : 0xFF4444; var text = new Text2(msg, { size: 180, fill: color }); text.anchor.set(0.5, 0.5); text.x = 2048 / 2; text.y = 900; popup.addChild(text); game.addChild(popup); if (d.isCorrectDoor) { LK.effects.flashScreen(0x00ff00, 800); LK.setTimeout(function () { if (popup && popup.parent) popup.parent.removeChild(popup); LK.showYouWin(); }, 1200); } else { LK.effects.flashScreen(0xff0000, 800); LK.setTimeout(function () { if (popup && popup.parent) popup.parent.removeChild(popup); currentLevel = 1; setupLevel(currentLevel); LK.showGameOver(); }, 1200); } break; } } } // No más lógica de puertas para este frame return; } // Level 7: Laser room logic if (currentLevel === 7 && game.level7Lasers && student) { // Move lasers and check collision for (var i = 0; i < game.level7Lasers.length; i++) { var laser = game.level7Lasers[i]; if (laser._vertical) { laser.y += laser._moveDir * laser._moveSpeed; if (laser.y < laser._moveMin) { laser.y = laser._moveMin; laser._moveDir = 1; } if (laser.y > laser._moveMax) { laser.y = laser._moveMax; laser._moveDir = -1; } } else { laser.x += laser._moveDir * laser._moveSpeed; if (laser.x < laser._moveMin) { laser.x = laser._moveMin; laser._moveDir = 1; } if (laser.x > laser._moveMax) { laser.x = laser._moveMax; laser._moveDir = -1; } } // Check collision with student if (student.intersects(laser)) { LK.effects.flashScreen(0xff0000, 1000); currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1200); LK.showGameOver(); return; } } // Check if student touches the exit door if (game.level7Door && !game.level7Door._alreadyTriggered && student.intersects(game.level7Door)) { game.level7Door._alreadyTriggered = true; var popup = new Container(); var bg = LK.getAsset('furniture', { width: 2048, height: 2732, color: 0x000000, anchorX: 0, anchorY: 0 }); bg.alpha = 0.01; popup.addChild(bg); var text = new Text2("¡Escapaste del nivel láser!", { size: 180, fill: 0x00FF00 }); text.anchor.set(0.5, 0.5); text.x = 2048 / 2; text.y = 900; popup.addChild(text); game.addChild(popup); LK.effects.flashScreen(0x00ff00, 800); LK.setTimeout(function () { if (popup && popup.parent) popup.parent.removeChild(popup); LK.showYouWin(); }, 1200); return; } // No more logic for this frame return; } // Level 8: Sala de cómputo lógica if (currentLevel === 8 && game.level8Desks && student) { // Colisión con escritorios for (var i = 0; i < game.level8Desks.length; i++) { var desk = game.level8Desks[i]; if (student.intersects(desk)) { student.x = student.lastX; student.y = student.lastY; student.targetX = student.lastX; student.targetY = student.lastY; break; } } // Colisión con paredes (igual que otros niveles) 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; // Colisión con profesor if (profesor && student.intersects(profesor)) { LK.effects.flashScreen(0xff0000, 1000); currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1200); LK.showGameOver(); return; } // Checar si toca la puerta de salida if (game.level8Door && !game.level8Door._alreadyTriggered && student.intersects(game.level8Door)) { game.level8Door._alreadyTriggered = true; var popup = new Container(); var bg = LK.getAsset('furniture', { width: 2048, height: 2732, color: 0x000000, anchorX: 0, anchorY: 0 }); bg.alpha = 0.01; popup.addChild(bg); var text = new Text2("¡Escapaste de la sala de cómputo!", { size: 180, fill: 0x00FF00 }); text.anchor.set(0.5, 0.5); text.x = 2048 / 2; text.y = 900; popup.addChild(text); game.addChild(popup); LK.effects.flashScreen(0x00ff00, 800); LK.setTimeout(function () { if (popup && popup.parent) popup.parent.removeChild(popup); LK.showYouWin(); }, 1200); return; } // No más lógica para este frame return; } // Check if student touches the door (minimum contact triggers question) if (currentLevel === 5 && game.level5Doors && student) { // Only trigger if not already showing a popup if (typeof showMathQuestion === "undefined" || !showMathQuestion) { for (var i = 0; i < game.level5Doors.length; i++) { var d = game.level5Doors[i]; if (!d._alreadyTriggered && student.intersects(d)) { d._alreadyTriggered = true; showMathQuestion = true; // Show popup: ¿Es esta la puerta correcta? var popup = new Container(); var bg = LK.getAsset('furniture', { width: 2048, height: 2732, color: 0x000000, anchorX: 0, anchorY: 0 }); bg.alpha = 0.01; popup.addChild(bg); var msg = d.isCorrectDoor ? "¡Felicidades! Escapaste del colegio." : "¡Esa no es la puerta correcta!"; var color = d.isCorrectDoor ? 0x00FF00 : 0xFF4444; var text = new Text2(msg, { size: 180, fill: color }); text.anchor.set(0.5, 0.5); text.x = 2048 / 2; text.y = 900; popup.addChild(text); game.addChild(popup); if (d.isCorrectDoor) { LK.effects.flashScreen(0x00ff00, 800); LK.setTimeout(function () { if (popup && popup.parent) popup.parent.removeChild(popup); showMathQuestion = false; // Advance to level 6 instead of showing win screen currentLevel = 6; setupLevel(currentLevel); }, 1200); } else { LK.effects.flashScreen(0xff0000, 800); LK.setTimeout(function () { if (popup && popup.parent) popup.parent.removeChild(popup); showMathQuestion = false; currentLevel = 1; setupLevel(currentLevel); LK.showGameOver(); }, 1200); } break; } } } } else // 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 () { if (typeof mathQuestionTimeout !== "undefined") { LK.clearTimeout(mathQuestionTimeout); mathQuestionTimeout = undefined; } 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 === 5) { // If on level 5, advance to level 6 instead of showing win currentLevel = 6; setupLevel(currentLevel); } else if (currentLevel < maxLevel) { currentLevel += 1; setupLevel(currentLevel); } else { LK.showYouWin(); } } }; } else { optObj.down = function () { if (typeof mathQuestionTimeout !== "undefined") { LK.clearTimeout(mathQuestionTimeout); mathQuestionTimeout = undefined; } 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; }; } } // Add timer text var timeLimit = 10; // seconds var timeLeft = timeLimit; var timerText = new Text2("Tiempo: " + timeLeft, { size: 120, fill: 0xFF4444 }); timerText.anchor.set(0.5, 0); timerText.x = 2048 / 2; timerText.y = 650; mathQuestionPopup.addChild(timerText); // Timer logic if (typeof mathQuestionTimeout !== "undefined") { LK.clearTimeout(mathQuestionTimeout); mathQuestionTimeout = undefined; } if (typeof mathQuestionInterval !== "undefined") { LK.clearInterval(mathQuestionInterval); mathQuestionInterval = undefined; } mathQuestionInterval = LK.setInterval(function () { if (typeof timeLeft !== "undefined") { timeLeft -= 1; if (timerText && timerText.setText) timerText.setText("Tiempo: " + timeLeft); if (timeLeft <= 0) { // Time's up! Fail the question if (typeof mathQuestionTimeout !== "undefined") { LK.clearTimeout(mathQuestionTimeout); mathQuestionTimeout = undefined; } if (typeof mathQuestionInterval !== "undefined") { LK.clearInterval(mathQuestionInterval); mathQuestionInterval = undefined; } LK.effects.flashScreen(0xff0000, 800); currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1000); LK.showGameOver(); if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup); mathQuestionPopup = null; showMathQuestion = false; } } }, 1000); // Also set a hard timeout in case interval fails mathQuestionTimeout = LK.setTimeout(function () { if (typeof mathQuestionInterval !== "undefined") { LK.clearInterval(mathQuestionInterval); mathQuestionInterval = undefined; } LK.effects.flashScreen(0xff0000, 800); currentLevel = 1; LK.setTimeout(function () { setupLevel(currentLevel); }, 1000); LK.showGameOver(); if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup); mathQuestionPopup = null; showMathQuestion = false; }, timeLimit * 1000); // 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 (!gameStarted) return; if (!joystickActive) { student.targetX = x; student.targetY = y; } }; game.move = function (x, y, obj) { if (!gameStarted) return; 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 collision removed for level 4
// 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 = 8; // Now 8 levels (added sala de computo)
// --- START SCREEN LOGIC ---
var startScreenOverlay = null;
var gameStarted = false;
function showStartScreen() {
if (startScreenOverlay) return;
startScreenOverlay = new Container();
// Only a single prominent JUGAR button, centered
var playBtn = LK.getAsset('furniture', {
width: 600,
height: 220,
color: 0x83de44,
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200
});
playBtn.interactive = true;
playBtn.buttonMode = true;
startScreenOverlay.addChild(playBtn);
var playText = new Text2("JUGAR", {
size: 150,
fill: 0x000000
});
playText.anchor.set(0.5, 0.5);
playText.x = playBtn.x;
playText.y = playBtn.y;
startScreenOverlay.addChild(playText);
playBtn.down = function () {
if (startScreenOverlay && startScreenOverlay.parent) {
startScreenOverlay.parent.removeChild(startScreenOverlay);
}
startScreenOverlay = null;
gameStarted = true;
setupLevel(currentLevel);
};
// Add overlay to game (not GUI, so it blocks input)
game.addChild(startScreenOverlay);
}
// Show start screen on load
LK.setTimeout(function () {
showStartScreen();
}, 10);
// 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_rocky'; // Piso de concreto para el nivel 4
}
// Only add a floor if floorAssetId is defined (skip for level 5)
if (typeof floorAssetId !== "undefined") {
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}
// Easy maze: outer boundaries plus a few simple interior walls
var mazeWalls = [
// Outer boundaries
{
x: 0,
y: 0,
width: 2048,
height: 40
},
// top
{
x: 0,
y: 2732 - 40,
width: 2048,
height: 40
},
// bottom
{
x: 0,
y: 0,
width: 40,
height: 2732
},
// left
{
x: 2048 - 40,
y: 0,
width: 40,
height: 2732
},
// right
// A few easy interior walls (horizontal and vertical, leaving wide passages)
{
x: 400,
y: 600,
width: 1200,
height: 40
},
// horizontal, upper
{
x: 400,
y: 1500,
width: 1200,
height: 40
},
// horizontal, lower
{
x: 800,
y: 900,
width: 40,
height: 600
},
// vertical, left
{
x: 1200,
y: 1200,
width: 40,
height: 600
} // vertical, right
];
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 removed for level 4
if (!game.level4SoccerBalls) game.level4SoccerBalls = [];
game.level4SoccerBalls.length = 0;
} else if (level === 5) {
// Level 5: Adivina la puerta correcta (guess the correct door)
// Add floor for level 5
var floor = LK.getAsset('floor', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(floor);
// Three doors, only one is correct
if (!game.level5Doors) game.level5Doors = [];
game.level5Doors.length = 0;
// Place three doors spaced horizontally at the top of the map
var doorY = 300;
var doorSpacing = 500;
var firstDoorX = 524; // Centered: (2048 - (3*240 + 2*500))/2 = 524
var correctDoorIndex = Math.floor(Math.random() * 3); // Random correct door
for (var i = 0; i < 3; i++) {
var d = LK.getAsset('door', {
x: firstDoorX + i * (240 + doorSpacing),
y: doorY,
anchorX: 0,
anchorY: 0
});
d.isCorrectDoor = i === correctDoorIndex;
game.addChild(d);
game.level5Doors.push(d);
}
// Add centered text above the doors in level 5
var chooseText = new Text2("Escoje la puerta correcta", {
size: 120,
fill: 0xFFF700
});
chooseText.anchor.set(0.5, 0.5);
chooseText.x = 2048 / 2;
chooseText.y = doorY - 80;
game.addChild(chooseText);
// No maze walls, just outer boundaries
var wallTop = LK.getAsset('wall', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var wallBottom = LK.getAsset('wall', {
x: 0,
y: 2732 - 40,
anchorX: 0,
anchorY: 0
});
var wallLeft = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var 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 profesor for level 5 (will chase the student)
} else if (level === 6) {
// Nivel 6: Patio con UN obstáculo móvil y solo una puerta de salida
var floor = LK.getAsset('floor_placa', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(floor);
// Solo una puerta en la parte superior, es la salida
if (!game.level6Doors) game.level6Doors = [];
game.level6Doors.length = 0;
var doorY = 200;
var doorX = 1024 - 120; // Centrada horizontalmente (2048/2 - door width/2)
var d = LK.getAsset('door', {
x: doorX,
y: doorY,
anchorX: 0,
anchorY: 0
});
d.isCorrectDoor = true;
game.addChild(d);
game.level6Doors.push(d);
// Texto de pista
var chooseText6 = new Text2("¡Encuentra la puerta de salida!", {
size: 120,
fill: 0xFFF700
});
chooseText6.anchor.set(0.5, 0.5);
chooseText6.x = 2048 / 2;
chooseText6.y = doorY - 80;
game.addChild(chooseText6);
// Paredes exteriores
var wallTop = LK.getAsset('wall', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var wallBottom = LK.getAsset('wall', {
x: 0,
y: 2732 - 40,
anchorX: 0,
anchorY: 0
});
var wallLeft = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var 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);
// Obstáculo móvil (solo 1 bloque que se mueve horizontalmente)
if (!game.level6MovingObstacles) game.level6MovingObstacles = [];
game.level6MovingObstacles.length = 0;
var obsY = [1400]; // Solo un obstáculo, centrado verticalmente
for (var i = 0; i < 1; i++) {
var obs = LK.getAsset('furniture', {
width: 320,
height: 80,
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: obsY[i]
});
obs._moveDir = 1;
obs._moveMin = 300;
obs._moveMax = 2048 - 300;
obs._moveSpeed = 10;
game.addChild(obs);
game.level6MovingObstacles.push(obs);
}
} else if (level === 7) {
// Nivel 7: Laser room - dodge moving laser beams and reach the exit door
var floor = LK.getAsset('floor', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(floor);
// Outer walls
var wallTop = LK.getAsset('wall', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var wallBottom = LK.getAsset('wall', {
x: 0,
y: 2732 - 40,
anchorX: 0,
anchorY: 0
});
var wallLeft = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var 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);
// Exit door at the top center
if (!game.level7Door) game.level7Door = null;
var doorY = 120;
var doorX = 2048 / 2 - 120;
var d7 = LK.getAsset('door', {
x: doorX,
y: doorY,
anchorX: 0,
anchorY: 0
});
d7.isCorrectDoor = true;
game.addChild(d7);
game.level7Door = d7;
// Laser beams (moving obstacles)
if (!game.level7Lasers) game.level7Lasers = [];
game.level7Lasers.length = 0;
// Each laser: {x, y, w, h, vertical, min, max, speed, dir}
var lasers = [
// Horizontal lasers
{
x: 300,
y: 700,
w: 1448,
h: 30,
vertical: false,
min: 700,
max: 1200,
speed: 8,
dir: 1
}, {
x: 300,
y: 1800,
w: 1448,
h: 30,
vertical: false,
min: 1400,
max: 2100,
speed: 10,
dir: -1
},
// Vertical lasers
{
x: 600,
y: 400,
w: 30,
h: 1000,
vertical: true,
min: 600,
max: 1400,
speed: 7,
dir: 1
}, {
x: 1400,
y: 1600,
w: 30,
h: 900,
vertical: true,
min: 900,
max: 2100,
speed: 9,
dir: -1
}];
for (var i = 0; i < lasers.length; i++) {
var l = lasers[i];
var laser = LK.getAsset('wall', {
width: l.w,
height: l.h,
x: l.x,
y: l.y,
anchorX: 0,
anchorY: 0
});
laser._isLaser = true;
laser._vertical = l.vertical;
laser._moveMin = l.min;
laser._moveMax = l.max;
laser._moveSpeed = l.speed;
laser._moveDir = l.dir;
game.addChild(laser);
game.level7Lasers.push(laser);
}
// Instruction text
var instrText = new Text2("¡Esquiva los rayos láser y escapa por la puerta!", {
size: 110,
fill: 0xFF2222
});
instrText.anchor.set(0.5, 0.5);
instrText.x = 2048 / 2;
instrText.y = 320;
game.addChild(instrText);
} else if (level === 8) {
// Nivel 8: Sala de cómputo con escritorios como obstáculos y una sola puerta de salida
var floor = LK.getAsset('floor', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(floor);
// Paredes exteriores
var wallTop = LK.getAsset('wall', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var wallBottom = LK.getAsset('wall', {
x: 0,
y: 2732 - 40,
anchorX: 0,
anchorY: 0
});
var wallLeft = LK.getAsset('wall', {
width: 40,
height: 2732,
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
var 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);
// Puerta de salida en la parte superior derecha
if (!game.level8Door) game.level8Door = null;
var doorY = 120;
var doorX = 2048 - 320;
var d8 = LK.getAsset('door', {
x: doorX,
y: doorY,
anchorX: 0,
anchorY: 0
});
d8.isCorrectDoor = true;
game.addChild(d8);
game.level8Door = d8;
// Escritorios como obstáculos (usando 'furniture')
if (!game.level8Desks) game.level8Desks = [];
game.level8Desks.length = 0;
// Distribuir escritorios en filas y columnas, dejando pasillos
var deskRows = 3;
var deskCols = 4;
var deskW = 180;
var deskH = 120;
var startX = 400;
var startY = 700;
var gapX = 320;
var gapY = 400;
for (var row = 0; row < deskRows; row++) {
for (var col = 0; col < deskCols; col++) {
// Dejar pasillo central
if (col === 1 && row === 1) continue;
var desk = LK.getAsset('furniture', {
width: deskW,
height: deskH,
anchorX: 0.5,
anchorY: 0.5,
x: startX + col * gapX,
y: startY + row * gapY
});
game.addChild(desk);
game.level8Desks.push(desk);
}
}
// Texto de instrucción
var instrText8 = new Text2("¡Esquiva los escritorios y escapa por la puerta!", {
size: 110,
fill: 0x1E90FF
});
instrText8.anchor.set(0.5, 0.5);
instrText8.x = 2048 / 2;
instrText8.y = 320;
game.addChild(instrText8);
}
if (level !== 5 && level !== 6 && level !== 7) {
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;
} else if (level === 5) {
// Start at bottom center
student.x = 2048 / 2;
student.y = 2500;
} else if (level === 6) {
// Start at bottom center
student.x = 2048 / 2;
student.y = 2500;
} else if (level === 7) {
// Start at bottom center for level 7
student.x = 2048 / 2;
student.y = 2500;
} else if (level === 8) {
// Start at bottom left for level 8
student.x = 200;
student.y = 2500;
}
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;
} else if (level === 5) {
// Profesor starts at the bottom left in level 5 and will chase the student
profesor.x = 300;
profesor.y = 2500;
} else if (level === 6) {
// Profesor starts at the bottom right in level 6 and will chase the student
profesor.x = 1800;
profesor.y = 2500;
} else if (level === 7) {
// No profesor in level 7
profesor = null;
} else if (level === 8) {
// Profesor en la esquina superior izquierda, velocidad lenta
profesor.x = 200;
profesor.y = 200;
profesor.level8Slow = true;
}
if (level !== 7) {
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 () {
// If start screen is active, pause game logic
if (!gameStarted) return;
// 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 removed for level 4
// 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 && profesor.update) {
// Slow profesor in level 2
if (currentLevel === 2 && profesor.level2Slow) {
// Temporarily override update to move slower
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;
}
};
}
// Slow profesor in level 8
if (currentLevel === 8 && profesor.level8Slow) {
profesor.update = function () {
this.lastX = this.x;
this.lastY = this.y;
if (typeof showMathQuestion !== "undefined" && showMathQuestion) {
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 = 2.5; // even slower for level 8
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;
// Level 6: Obstáculos móviles y dos puertas
if (currentLevel === 6 && game.level6MovingObstacles && student) {
// Obstáculos móviles: mover y checar colisión
for (var i = 0; i < game.level6MovingObstacles.length; i++) {
var obs = game.level6MovingObstacles[i];
// Guardar última posición
if (typeof obs.lastX === "undefined") obs.lastX = obs.x;
// Movimiento horizontal
obs.x += obs._moveDir * obs._moveSpeed;
if (obs.x < obs._moveMin) {
obs.x = obs._moveMin;
obs._moveDir = 1;
}
if (obs.x > obs._moveMax) {
obs.x = obs._moveMax;
obs._moveDir = -1;
}
// Colisión con el estudiante
if (student.intersects(obs)) {
// Game over
LK.effects.flashScreen(0xff0000, 1000);
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1200);
LK.showGameOver();
return;
}
obs.lastX = obs.x;
}
// Checar si toca una puerta
if (game.level6Doors) {
for (var i = 0; i < game.level6Doors.length; i++) {
var d = game.level6Doors[i];
if (!d._alreadyTriggered && student.intersects(d)) {
d._alreadyTriggered = true;
// Mostrar popup de resultado
var popup = new Container();
var bg = LK.getAsset('furniture', {
width: 2048,
height: 2732,
color: 0x000000,
anchorX: 0,
anchorY: 0
});
bg.alpha = 0.01;
popup.addChild(bg);
var msg = d.isCorrectDoor ? "¡Escapaste del patio!" : "¡Esa no es la puerta de salida!";
var color = d.isCorrectDoor ? 0x00FF00 : 0xFF4444;
var text = new Text2(msg, {
size: 180,
fill: color
});
text.anchor.set(0.5, 0.5);
text.x = 2048 / 2;
text.y = 900;
popup.addChild(text);
game.addChild(popup);
if (d.isCorrectDoor) {
LK.effects.flashScreen(0x00ff00, 800);
LK.setTimeout(function () {
if (popup && popup.parent) popup.parent.removeChild(popup);
LK.showYouWin();
}, 1200);
} else {
LK.effects.flashScreen(0xff0000, 800);
LK.setTimeout(function () {
if (popup && popup.parent) popup.parent.removeChild(popup);
currentLevel = 1;
setupLevel(currentLevel);
LK.showGameOver();
}, 1200);
}
break;
}
}
}
// No más lógica de puertas para este frame
return;
}
// Level 7: Laser room logic
if (currentLevel === 7 && game.level7Lasers && student) {
// Move lasers and check collision
for (var i = 0; i < game.level7Lasers.length; i++) {
var laser = game.level7Lasers[i];
if (laser._vertical) {
laser.y += laser._moveDir * laser._moveSpeed;
if (laser.y < laser._moveMin) {
laser.y = laser._moveMin;
laser._moveDir = 1;
}
if (laser.y > laser._moveMax) {
laser.y = laser._moveMax;
laser._moveDir = -1;
}
} else {
laser.x += laser._moveDir * laser._moveSpeed;
if (laser.x < laser._moveMin) {
laser.x = laser._moveMin;
laser._moveDir = 1;
}
if (laser.x > laser._moveMax) {
laser.x = laser._moveMax;
laser._moveDir = -1;
}
}
// Check collision with student
if (student.intersects(laser)) {
LK.effects.flashScreen(0xff0000, 1000);
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1200);
LK.showGameOver();
return;
}
}
// Check if student touches the exit door
if (game.level7Door && !game.level7Door._alreadyTriggered && student.intersects(game.level7Door)) {
game.level7Door._alreadyTriggered = true;
var popup = new Container();
var bg = LK.getAsset('furniture', {
width: 2048,
height: 2732,
color: 0x000000,
anchorX: 0,
anchorY: 0
});
bg.alpha = 0.01;
popup.addChild(bg);
var text = new Text2("¡Escapaste del nivel láser!", {
size: 180,
fill: 0x00FF00
});
text.anchor.set(0.5, 0.5);
text.x = 2048 / 2;
text.y = 900;
popup.addChild(text);
game.addChild(popup);
LK.effects.flashScreen(0x00ff00, 800);
LK.setTimeout(function () {
if (popup && popup.parent) popup.parent.removeChild(popup);
LK.showYouWin();
}, 1200);
return;
}
// No more logic for this frame
return;
}
// Level 8: Sala de cómputo lógica
if (currentLevel === 8 && game.level8Desks && student) {
// Colisión con escritorios
for (var i = 0; i < game.level8Desks.length; i++) {
var desk = game.level8Desks[i];
if (student.intersects(desk)) {
student.x = student.lastX;
student.y = student.lastY;
student.targetX = student.lastX;
student.targetY = student.lastY;
break;
}
}
// Colisión con paredes (igual que otros niveles)
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;
// Colisión con profesor
if (profesor && student.intersects(profesor)) {
LK.effects.flashScreen(0xff0000, 1000);
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1200);
LK.showGameOver();
return;
}
// Checar si toca la puerta de salida
if (game.level8Door && !game.level8Door._alreadyTriggered && student.intersects(game.level8Door)) {
game.level8Door._alreadyTriggered = true;
var popup = new Container();
var bg = LK.getAsset('furniture', {
width: 2048,
height: 2732,
color: 0x000000,
anchorX: 0,
anchorY: 0
});
bg.alpha = 0.01;
popup.addChild(bg);
var text = new Text2("¡Escapaste de la sala de cómputo!", {
size: 180,
fill: 0x00FF00
});
text.anchor.set(0.5, 0.5);
text.x = 2048 / 2;
text.y = 900;
popup.addChild(text);
game.addChild(popup);
LK.effects.flashScreen(0x00ff00, 800);
LK.setTimeout(function () {
if (popup && popup.parent) popup.parent.removeChild(popup);
LK.showYouWin();
}, 1200);
return;
}
// No más lógica para este frame
return;
}
// Check if student touches the door (minimum contact triggers question)
if (currentLevel === 5 && game.level5Doors && student) {
// Only trigger if not already showing a popup
if (typeof showMathQuestion === "undefined" || !showMathQuestion) {
for (var i = 0; i < game.level5Doors.length; i++) {
var d = game.level5Doors[i];
if (!d._alreadyTriggered && student.intersects(d)) {
d._alreadyTriggered = true;
showMathQuestion = true;
// Show popup: ¿Es esta la puerta correcta?
var popup = new Container();
var bg = LK.getAsset('furniture', {
width: 2048,
height: 2732,
color: 0x000000,
anchorX: 0,
anchorY: 0
});
bg.alpha = 0.01;
popup.addChild(bg);
var msg = d.isCorrectDoor ? "¡Felicidades! Escapaste del colegio." : "¡Esa no es la puerta correcta!";
var color = d.isCorrectDoor ? 0x00FF00 : 0xFF4444;
var text = new Text2(msg, {
size: 180,
fill: color
});
text.anchor.set(0.5, 0.5);
text.x = 2048 / 2;
text.y = 900;
popup.addChild(text);
game.addChild(popup);
if (d.isCorrectDoor) {
LK.effects.flashScreen(0x00ff00, 800);
LK.setTimeout(function () {
if (popup && popup.parent) popup.parent.removeChild(popup);
showMathQuestion = false;
// Advance to level 6 instead of showing win screen
currentLevel = 6;
setupLevel(currentLevel);
}, 1200);
} else {
LK.effects.flashScreen(0xff0000, 800);
LK.setTimeout(function () {
if (popup && popup.parent) popup.parent.removeChild(popup);
showMathQuestion = false;
currentLevel = 1;
setupLevel(currentLevel);
LK.showGameOver();
}, 1200);
}
break;
}
}
}
} else
// 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 () {
if (typeof mathQuestionTimeout !== "undefined") {
LK.clearTimeout(mathQuestionTimeout);
mathQuestionTimeout = undefined;
}
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 === 5) {
// If on level 5, advance to level 6 instead of showing win
currentLevel = 6;
setupLevel(currentLevel);
} else if (currentLevel < maxLevel) {
currentLevel += 1;
setupLevel(currentLevel);
} else {
LK.showYouWin();
}
}
};
} else {
optObj.down = function () {
if (typeof mathQuestionTimeout !== "undefined") {
LK.clearTimeout(mathQuestionTimeout);
mathQuestionTimeout = undefined;
}
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;
};
}
}
// Add timer text
var timeLimit = 10; // seconds
var timeLeft = timeLimit;
var timerText = new Text2("Tiempo: " + timeLeft, {
size: 120,
fill: 0xFF4444
});
timerText.anchor.set(0.5, 0);
timerText.x = 2048 / 2;
timerText.y = 650;
mathQuestionPopup.addChild(timerText);
// Timer logic
if (typeof mathQuestionTimeout !== "undefined") {
LK.clearTimeout(mathQuestionTimeout);
mathQuestionTimeout = undefined;
}
if (typeof mathQuestionInterval !== "undefined") {
LK.clearInterval(mathQuestionInterval);
mathQuestionInterval = undefined;
}
mathQuestionInterval = LK.setInterval(function () {
if (typeof timeLeft !== "undefined") {
timeLeft -= 1;
if (timerText && timerText.setText) timerText.setText("Tiempo: " + timeLeft);
if (timeLeft <= 0) {
// Time's up! Fail the question
if (typeof mathQuestionTimeout !== "undefined") {
LK.clearTimeout(mathQuestionTimeout);
mathQuestionTimeout = undefined;
}
if (typeof mathQuestionInterval !== "undefined") {
LK.clearInterval(mathQuestionInterval);
mathQuestionInterval = undefined;
}
LK.effects.flashScreen(0xff0000, 800);
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1000);
LK.showGameOver();
if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup);
mathQuestionPopup = null;
showMathQuestion = false;
}
}
}, 1000);
// Also set a hard timeout in case interval fails
mathQuestionTimeout = LK.setTimeout(function () {
if (typeof mathQuestionInterval !== "undefined") {
LK.clearInterval(mathQuestionInterval);
mathQuestionInterval = undefined;
}
LK.effects.flashScreen(0xff0000, 800);
currentLevel = 1;
LK.setTimeout(function () {
setupLevel(currentLevel);
}, 1000);
LK.showGameOver();
if (mathQuestionPopup && mathQuestionPopup.parent) mathQuestionPopup.parent.removeChild(mathQuestionPopup);
mathQuestionPopup = null;
showMathQuestion = false;
}, timeLimit * 1000);
// 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 (!gameStarted) return;
if (!joystickActive) {
student.targetX = x;
student.targetY = y;
}
};
game.move = function (x, y, obj) {
if (!gameStarted) return;
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