/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Ghost class var Ghost = Container.expand(function () { var self = Container.call(this); self.colorId = 'ghost_red'; // default, will be set on init self.frightened = false; self.dir = { x: 0, y: 0 }; self.speed = 7; self.gridX = 0; self.gridY = 0; self.scatterTarget = { x: 0, y: 0 }; // for future AI self.mode = 'chase'; // 'chase', 'scatter', 'frightened' self.frightTimer = 0; self.attach = function (colorId) { self.colorId = colorId; self.removeChildren(); var ghostGfx = self.attachAsset(colorId, { anchorX: 0.5, anchorY: 0.5 }); }; self.setFrightened = function (on) { self.frightened = on; self.removeChildren(); if (on) { self.attachAsset('ghost_fright', { anchorX: 0.5, anchorY: 0.5 }); } else { self.attachAsset(self.colorId, { anchorX: 0.5, anchorY: 0.5 }); } }; self.update = function () { self.x += self.dir.x * self.speed; self.y += self.dir.y * self.speed; }; return self; }); // Pacman class var Pacman = Container.expand(function () { var self = Container.call(this); var pacmanGfx = self.attachAsset('pacman', { anchorX: 0.5, anchorY: 0.5 }); self.radius = pacmanGfx.width / 2; self.dir = { x: 1, y: 0 }; // Start moving right self.nextDir = { x: 1, y: 0 }; self.speed = 8; // pixels per tick self.gridX = 0; self.gridY = 0; self.moving = true; self.update = function () { if (!self.moving) return; // Move Pacman self.x += self.dir.x * self.speed; self.y += self.dir.y * self.speed; }; return self; }); // Pellet class var Pellet = Container.expand(function () { var self = Container.call(this); self.isPower = false; self.attach = function (isPower) { self.isPower = isPower; self.removeChildren(); if (isPower) { self.attachAsset('powerpellet', { anchorX: 0.5, anchorY: 0.5 }); } else { self.attachAsset('pellet', { anchorX: 0.5, anchorY: 0.5 }); } }; return self; }); // Wall class var Wall = Container.expand(function () { var self = Container.call(this); self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Frightened ghost (white) // Ghosts (four colors) // Wall (blue box) // Power Pellet (bigger blue dot) // Pellet (small white dot) // Pacman (yellow circle) // --- Maze Layout --- // 0: empty, 1: wall, 2: pellet, 3: power pellet // 19x23 grid (classic Pacman aspect, fits 2048x2732 well) var MAZE_ROWS = 23; var MAZE_COLS = 19; var CELL_SIZE = 112; // 19*112=2128, 23*112=2576, fits in 2048x2732 with margin var MAZE_OFFSET_X = (2048 - MAZE_COLS * CELL_SIZE) / 2; var MAZE_OFFSET_Y = (2732 - MAZE_ROWS * CELL_SIZE) / 2 + 40; // Simple Pacman-like maze (minimal, for MVP) var MAZE = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1], [1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1], [1, 3, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 3, 1, 1], [1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 1], [1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1], [1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1], [1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 1], [1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1], [1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1], [1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1], [1, 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1], [1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1], [1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1], [1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]; // --- Game State --- var pellets = []; var walls = []; var ghosts = []; var pacman = null; var score = 0; var pelletsLeft = 0; var frightTicks = 0; var frightActive = false; var frightDuration = 360; // 6 seconds at 60fps var swipeStart = null; var dragNode = null; var lastGameOver = false; // --- Score Display --- var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Maze Build --- function buildMaze() { // Clear previous for (var i = 0; i < pellets.length; ++i) pellets[i].destroy(); for (var i = 0; i < walls.length; ++i) walls[i].destroy(); pellets = []; walls = []; pelletsLeft = 0; for (var row = 0; row < MAZE_ROWS; ++row) { for (var col = 0; col < MAZE_COLS; ++col) { var cell = MAZE[row][col]; var x = MAZE_OFFSET_X + col * CELL_SIZE + CELL_SIZE / 2; var y = MAZE_OFFSET_Y + row * CELL_SIZE + CELL_SIZE / 2; if (cell === 1) { var wall = new Wall(); wall.x = x; wall.y = y; game.addChild(wall); walls.push(wall); } else if (cell === 2 || cell === 3) { var pellet = new Pellet(); pellet.x = x; pellet.y = y; pellet.attach(cell === 3); game.addChild(pellet); pellets.push(pellet); pelletsLeft++; } } } } // --- Pacman Init --- function spawnPacman() { if (pacman) pacman.destroy(); pacman = new Pacman(); // Start position: center of maze, row 15, col 9 pacman.gridX = 9; pacman.gridY = 15; pacman.x = MAZE_OFFSET_X + pacman.gridX * CELL_SIZE + CELL_SIZE / 2; pacman.y = MAZE_OFFSET_Y + pacman.gridY * CELL_SIZE + CELL_SIZE / 2; pacman.dir = { x: 1, y: 0 }; pacman.nextDir = { x: 1, y: 0 }; pacman.moving = true; game.addChild(pacman); } // --- Ghosts Init --- function spawnGhosts() { // Remove old ghosts for (var i = 0; i < ghosts.length; ++i) ghosts[i].destroy(); ghosts = []; // Four ghosts, different colors, start in center var ghostColors = ['ghost_red', 'ghost_pink', 'ghost_blue', 'ghost_orange']; var ghostStarts = [{ col: 9, row: 11 }, { col: 8, row: 11 }, { col: 10, row: 11 }, { col: 9, row: 12 }]; for (var i = 0; i < 4; ++i) { var ghost = new Ghost(); ghost.attach(ghostColors[i]); ghost.gridX = ghostStarts[i].col; ghost.gridY = ghostStarts[i].row; ghost.x = MAZE_OFFSET_X + ghost.gridX * CELL_SIZE + CELL_SIZE / 2; ghost.y = MAZE_OFFSET_Y + ghost.gridY * CELL_SIZE + CELL_SIZE / 2; // Initial direction: up or left/right if (i === 0) ghost.dir = { x: 0, y: -1 };else if (i === 1) ghost.dir = { x: -1, y: 0 };else if (i === 2) ghost.dir = { x: 1, y: 0 };else ghost.dir = { x: 0, y: 1 }; ghost.frightened = false; ghosts.push(ghost); game.addChild(ghost); } } // --- Utility: Grid <-> Pixel --- function posToGrid(x, y) { var col = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE); var row = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE); return { col: col, row: row }; } function gridToPos(col, row) { return { x: MAZE_OFFSET_X + col * CELL_SIZE + CELL_SIZE / 2, y: MAZE_OFFSET_Y + row * CELL_SIZE + CELL_SIZE / 2 }; } function isWall(col, row) { if (col < 0 || col >= MAZE_COLS || row < 0 || row >= MAZE_ROWS) return true; return MAZE[row][col] === 1; } // --- Pacman Movement & Input --- function canMove(col, row, dir) { var nextCol = col + dir.x; var nextRow = row + dir.y; return !isWall(nextCol, nextRow); } function updatePacmanDirection() { var grid = posToGrid(pacman.x, pacman.y); // Snap to center of cell var center = gridToPos(grid.col, grid.row); var dx = Math.abs(pacman.x - center.x); var dy = Math.abs(pacman.y - center.y); if (dx < 4 && dy < 4) { // At center, can change direction if (canMove(grid.col, grid.row, pacman.nextDir)) { pacman.dir = { x: pacman.nextDir.x, y: pacman.nextDir.y }; } // If can't move in current dir, stop if (!canMove(grid.col, grid.row, pacman.dir)) { pacman.moving = false; } else { pacman.moving = true; } // Snap to center pacman.x = center.x; pacman.y = center.y; } } // --- Ghost Movement (Random for MVP, smarter later) --- function getValidGhostDirs(ghost) { var grid = posToGrid(ghost.x, ghost.y); var dirs = [{ x: 1, y: 0 }, { x: -1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: -1 }]; var valid = []; for (var i = 0; i < dirs.length; ++i) { var d = dirs[i]; // Don't reverse direction if (ghost.dir.x === -d.x && ghost.dir.y === -d.y) continue; if (!isWall(grid.col + d.x, grid.row + d.y)) valid.push(d); } return valid; } function updateGhostDirection(ghost) { var grid = posToGrid(ghost.x, ghost.y); var center = gridToPos(grid.col, grid.row); var dx = Math.abs(ghost.x - center.x); var dy = Math.abs(ghost.y - center.y); if (dx < 4 && dy < 4) { // At center, pick new direction var valid = getValidGhostDirs(ghost); if (valid.length === 0) { ghost.dir = { x: -ghost.dir.x, y: -ghost.dir.y }; } else { // MVP: random direction var idx = Math.floor(Math.random() * valid.length); ghost.dir = { x: valid[idx].x, y: valid[idx].y }; } // Snap to center ghost.x = center.x; ghost.y = center.y; } } // --- Pellet Eating --- function checkPelletEat() { for (var i = pellets.length - 1; i >= 0; --i) { var pellet = pellets[i]; var dx = pacman.x - pellet.x; var dy = pacman.y - pellet.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 48) { // Eat pellet if (pellet.isPower) { frightTicks = frightDuration; frightActive = true; for (var g = 0; g < ghosts.length; ++g) { ghosts[g].setFrightened(true); } } pellet.destroy(); pellets.splice(i, 1); pelletsLeft--; score += pellet.isPower ? 50 : 10; scoreTxt.setText(score); LK.setScore(score); if (pelletsLeft === 0) { LK.showYouWin(); } } } } // --- Ghost Collisions --- function checkGhostCollisions() { for (var i = 0; i < ghosts.length; ++i) { var ghost = ghosts[i]; var dx = pacman.x - ghost.x; var dy = pacman.y - ghost.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 60) { if (ghost.frightened) { // Eat ghost ghost.setFrightened(false); // Send ghost to home var home = gridToPos(9, 11); ghost.x = home.x; ghost.y = home.y; ghost.dir = { x: 0, y: -1 }; score += 200; scoreTxt.setText(score); LK.setScore(score); } else { // Pacman dies if (!lastGameOver) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); lastGameOver = true; } } } } } // --- Frightened Mode Timer --- function updateFrightened() { if (frightActive) { frightTicks--; if (frightTicks <= 0) { frightActive = false; for (var g = 0; g < ghosts.length; ++g) { ghosts[g].setFrightened(false); } } } } // --- Input: Swipe to set direction --- function getSwipeDir(start, end) { var dx = end.x - start.x; var dy = end.y - start.y; if (Math.abs(dx) > Math.abs(dy)) { if (dx > 32) return { x: 1, y: 0 }; if (dx < -32) return { x: -1, y: 0 }; } else { if (dy > 32) return { x: 0, y: 1 }; if (dy < -32) return { x: 0, y: -1 }; } return null; } game.down = function (x, y, obj) { swipeStart = { x: x, y: y }; dragNode = pacman; }; game.move = function (x, y, obj) { if (!swipeStart) return; var swipeEnd = { x: x, y: y }; var dir = getSwipeDir(swipeStart, swipeEnd); if (dir) { pacman.nextDir = dir; swipeStart = null; } }; game.up = function (x, y, obj) { swipeStart = null; dragNode = null; }; // --- Game Update Loop --- game.update = function () { if (!pacman) return; lastGameOver = false; updatePacmanDirection(); pacman.update(); for (var i = 0; i < ghosts.length; ++i) { updateGhostDirection(ghosts[i]); ghosts[i].update(); } checkPelletEat(); checkGhostCollisions(); updateFrightened(); }; // --- Game Start --- function startGame() { score = 0; LK.setScore(0); scoreTxt.setText('0'); buildMaze(); spawnPacman(); spawnGhosts(); frightTicks = 0; frightActive = false; lastGameOver = false; } startGame();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,506 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Ghost class
+var Ghost = Container.expand(function () {
+ var self = Container.call(this);
+ self.colorId = 'ghost_red'; // default, will be set on init
+ self.frightened = false;
+ self.dir = {
+ x: 0,
+ y: 0
+ };
+ self.speed = 7;
+ self.gridX = 0;
+ self.gridY = 0;
+ self.scatterTarget = {
+ x: 0,
+ y: 0
+ }; // for future AI
+ self.mode = 'chase'; // 'chase', 'scatter', 'frightened'
+ self.frightTimer = 0;
+ self.attach = function (colorId) {
+ self.colorId = colorId;
+ self.removeChildren();
+ var ghostGfx = self.attachAsset(colorId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ };
+ self.setFrightened = function (on) {
+ self.frightened = on;
+ self.removeChildren();
+ if (on) {
+ self.attachAsset('ghost_fright', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else {
+ self.attachAsset(self.colorId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ };
+ self.update = function () {
+ self.x += self.dir.x * self.speed;
+ self.y += self.dir.y * self.speed;
+ };
+ return self;
+});
+// Pacman class
+var Pacman = Container.expand(function () {
+ var self = Container.call(this);
+ var pacmanGfx = self.attachAsset('pacman', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.radius = pacmanGfx.width / 2;
+ self.dir = {
+ x: 1,
+ y: 0
+ }; // Start moving right
+ self.nextDir = {
+ x: 1,
+ y: 0
+ };
+ self.speed = 8; // pixels per tick
+ self.gridX = 0;
+ self.gridY = 0;
+ self.moving = true;
+ self.update = function () {
+ if (!self.moving) return;
+ // Move Pacman
+ self.x += self.dir.x * self.speed;
+ self.y += self.dir.y * self.speed;
+ };
+ return self;
+});
+// Pellet class
+var Pellet = Container.expand(function () {
+ var self = Container.call(this);
+ self.isPower = false;
+ self.attach = function (isPower) {
+ self.isPower = isPower;
+ self.removeChildren();
+ if (isPower) {
+ self.attachAsset('powerpellet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ } else {
+ self.attachAsset('pellet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+ };
+ return self;
+});
+// Wall class
+var Wall = Container.expand(function () {
+ var self = Container.call(this);
+ self.attachAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
backgroundColor: 0x000000
-});
\ No newline at end of file
+});
+
+/****
+* Game Code
+****/
+// Frightened ghost (white)
+// Ghosts (four colors)
+// Wall (blue box)
+// Power Pellet (bigger blue dot)
+// Pellet (small white dot)
+// Pacman (yellow circle)
+// --- Maze Layout ---
+// 0: empty, 1: wall, 2: pellet, 3: power pellet
+// 19x23 grid (classic Pacman aspect, fits 2048x2732 well)
+var MAZE_ROWS = 23;
+var MAZE_COLS = 19;
+var CELL_SIZE = 112; // 19*112=2128, 23*112=2576, fits in 2048x2732 with margin
+var MAZE_OFFSET_X = (2048 - MAZE_COLS * CELL_SIZE) / 2;
+var MAZE_OFFSET_Y = (2732 - MAZE_ROWS * CELL_SIZE) / 2 + 40;
+// Simple Pacman-like maze (minimal, for MVP)
+var MAZE = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1], [1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1], [1, 3, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 3, 1, 1], [1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 1], [1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1], [1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1], [1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 1], [1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1], [1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1], [1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1], [1, 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1], [1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1], [1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1], [1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
+// --- Game State ---
+var pellets = [];
+var walls = [];
+var ghosts = [];
+var pacman = null;
+var score = 0;
+var pelletsLeft = 0;
+var frightTicks = 0;
+var frightActive = false;
+var frightDuration = 360; // 6 seconds at 60fps
+var swipeStart = null;
+var dragNode = null;
+var lastGameOver = false;
+// --- Score Display ---
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: "#fff"
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// --- Maze Build ---
+function buildMaze() {
+ // Clear previous
+ for (var i = 0; i < pellets.length; ++i) pellets[i].destroy();
+ for (var i = 0; i < walls.length; ++i) walls[i].destroy();
+ pellets = [];
+ walls = [];
+ pelletsLeft = 0;
+ for (var row = 0; row < MAZE_ROWS; ++row) {
+ for (var col = 0; col < MAZE_COLS; ++col) {
+ var cell = MAZE[row][col];
+ var x = MAZE_OFFSET_X + col * CELL_SIZE + CELL_SIZE / 2;
+ var y = MAZE_OFFSET_Y + row * CELL_SIZE + CELL_SIZE / 2;
+ if (cell === 1) {
+ var wall = new Wall();
+ wall.x = x;
+ wall.y = y;
+ game.addChild(wall);
+ walls.push(wall);
+ } else if (cell === 2 || cell === 3) {
+ var pellet = new Pellet();
+ pellet.x = x;
+ pellet.y = y;
+ pellet.attach(cell === 3);
+ game.addChild(pellet);
+ pellets.push(pellet);
+ pelletsLeft++;
+ }
+ }
+ }
+}
+// --- Pacman Init ---
+function spawnPacman() {
+ if (pacman) pacman.destroy();
+ pacman = new Pacman();
+ // Start position: center of maze, row 15, col 9
+ pacman.gridX = 9;
+ pacman.gridY = 15;
+ pacman.x = MAZE_OFFSET_X + pacman.gridX * CELL_SIZE + CELL_SIZE / 2;
+ pacman.y = MAZE_OFFSET_Y + pacman.gridY * CELL_SIZE + CELL_SIZE / 2;
+ pacman.dir = {
+ x: 1,
+ y: 0
+ };
+ pacman.nextDir = {
+ x: 1,
+ y: 0
+ };
+ pacman.moving = true;
+ game.addChild(pacman);
+}
+// --- Ghosts Init ---
+function spawnGhosts() {
+ // Remove old ghosts
+ for (var i = 0; i < ghosts.length; ++i) ghosts[i].destroy();
+ ghosts = [];
+ // Four ghosts, different colors, start in center
+ var ghostColors = ['ghost_red', 'ghost_pink', 'ghost_blue', 'ghost_orange'];
+ var ghostStarts = [{
+ col: 9,
+ row: 11
+ }, {
+ col: 8,
+ row: 11
+ }, {
+ col: 10,
+ row: 11
+ }, {
+ col: 9,
+ row: 12
+ }];
+ for (var i = 0; i < 4; ++i) {
+ var ghost = new Ghost();
+ ghost.attach(ghostColors[i]);
+ ghost.gridX = ghostStarts[i].col;
+ ghost.gridY = ghostStarts[i].row;
+ ghost.x = MAZE_OFFSET_X + ghost.gridX * CELL_SIZE + CELL_SIZE / 2;
+ ghost.y = MAZE_OFFSET_Y + ghost.gridY * CELL_SIZE + CELL_SIZE / 2;
+ // Initial direction: up or left/right
+ if (i === 0) ghost.dir = {
+ x: 0,
+ y: -1
+ };else if (i === 1) ghost.dir = {
+ x: -1,
+ y: 0
+ };else if (i === 2) ghost.dir = {
+ x: 1,
+ y: 0
+ };else ghost.dir = {
+ x: 0,
+ y: 1
+ };
+ ghost.frightened = false;
+ ghosts.push(ghost);
+ game.addChild(ghost);
+ }
+}
+// --- Utility: Grid <-> Pixel ---
+function posToGrid(x, y) {
+ var col = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE);
+ var row = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE);
+ return {
+ col: col,
+ row: row
+ };
+}
+function gridToPos(col, row) {
+ return {
+ x: MAZE_OFFSET_X + col * CELL_SIZE + CELL_SIZE / 2,
+ y: MAZE_OFFSET_Y + row * CELL_SIZE + CELL_SIZE / 2
+ };
+}
+function isWall(col, row) {
+ if (col < 0 || col >= MAZE_COLS || row < 0 || row >= MAZE_ROWS) return true;
+ return MAZE[row][col] === 1;
+}
+// --- Pacman Movement & Input ---
+function canMove(col, row, dir) {
+ var nextCol = col + dir.x;
+ var nextRow = row + dir.y;
+ return !isWall(nextCol, nextRow);
+}
+function updatePacmanDirection() {
+ var grid = posToGrid(pacman.x, pacman.y);
+ // Snap to center of cell
+ var center = gridToPos(grid.col, grid.row);
+ var dx = Math.abs(pacman.x - center.x);
+ var dy = Math.abs(pacman.y - center.y);
+ if (dx < 4 && dy < 4) {
+ // At center, can change direction
+ if (canMove(grid.col, grid.row, pacman.nextDir)) {
+ pacman.dir = {
+ x: pacman.nextDir.x,
+ y: pacman.nextDir.y
+ };
+ }
+ // If can't move in current dir, stop
+ if (!canMove(grid.col, grid.row, pacman.dir)) {
+ pacman.moving = false;
+ } else {
+ pacman.moving = true;
+ }
+ // Snap to center
+ pacman.x = center.x;
+ pacman.y = center.y;
+ }
+}
+// --- Ghost Movement (Random for MVP, smarter later) ---
+function getValidGhostDirs(ghost) {
+ var grid = posToGrid(ghost.x, ghost.y);
+ var dirs = [{
+ x: 1,
+ y: 0
+ }, {
+ x: -1,
+ y: 0
+ }, {
+ x: 0,
+ y: 1
+ }, {
+ x: 0,
+ y: -1
+ }];
+ var valid = [];
+ for (var i = 0; i < dirs.length; ++i) {
+ var d = dirs[i];
+ // Don't reverse direction
+ if (ghost.dir.x === -d.x && ghost.dir.y === -d.y) continue;
+ if (!isWall(grid.col + d.x, grid.row + d.y)) valid.push(d);
+ }
+ return valid;
+}
+function updateGhostDirection(ghost) {
+ var grid = posToGrid(ghost.x, ghost.y);
+ var center = gridToPos(grid.col, grid.row);
+ var dx = Math.abs(ghost.x - center.x);
+ var dy = Math.abs(ghost.y - center.y);
+ if (dx < 4 && dy < 4) {
+ // At center, pick new direction
+ var valid = getValidGhostDirs(ghost);
+ if (valid.length === 0) {
+ ghost.dir = {
+ x: -ghost.dir.x,
+ y: -ghost.dir.y
+ };
+ } else {
+ // MVP: random direction
+ var idx = Math.floor(Math.random() * valid.length);
+ ghost.dir = {
+ x: valid[idx].x,
+ y: valid[idx].y
+ };
+ }
+ // Snap to center
+ ghost.x = center.x;
+ ghost.y = center.y;
+ }
+}
+// --- Pellet Eating ---
+function checkPelletEat() {
+ for (var i = pellets.length - 1; i >= 0; --i) {
+ var pellet = pellets[i];
+ var dx = pacman.x - pellet.x;
+ var dy = pacman.y - pellet.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < 48) {
+ // Eat pellet
+ if (pellet.isPower) {
+ frightTicks = frightDuration;
+ frightActive = true;
+ for (var g = 0; g < ghosts.length; ++g) {
+ ghosts[g].setFrightened(true);
+ }
+ }
+ pellet.destroy();
+ pellets.splice(i, 1);
+ pelletsLeft--;
+ score += pellet.isPower ? 50 : 10;
+ scoreTxt.setText(score);
+ LK.setScore(score);
+ if (pelletsLeft === 0) {
+ LK.showYouWin();
+ }
+ }
+ }
+}
+// --- Ghost Collisions ---
+function checkGhostCollisions() {
+ for (var i = 0; i < ghosts.length; ++i) {
+ var ghost = ghosts[i];
+ var dx = pacman.x - ghost.x;
+ var dy = pacman.y - ghost.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < 60) {
+ if (ghost.frightened) {
+ // Eat ghost
+ ghost.setFrightened(false);
+ // Send ghost to home
+ var home = gridToPos(9, 11);
+ ghost.x = home.x;
+ ghost.y = home.y;
+ ghost.dir = {
+ x: 0,
+ y: -1
+ };
+ score += 200;
+ scoreTxt.setText(score);
+ LK.setScore(score);
+ } else {
+ // Pacman dies
+ if (!lastGameOver) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+ lastGameOver = true;
+ }
+ }
+ }
+ }
+}
+// --- Frightened Mode Timer ---
+function updateFrightened() {
+ if (frightActive) {
+ frightTicks--;
+ if (frightTicks <= 0) {
+ frightActive = false;
+ for (var g = 0; g < ghosts.length; ++g) {
+ ghosts[g].setFrightened(false);
+ }
+ }
+ }
+}
+// --- Input: Swipe to set direction ---
+function getSwipeDir(start, end) {
+ var dx = end.x - start.x;
+ var dy = end.y - start.y;
+ if (Math.abs(dx) > Math.abs(dy)) {
+ if (dx > 32) return {
+ x: 1,
+ y: 0
+ };
+ if (dx < -32) return {
+ x: -1,
+ y: 0
+ };
+ } else {
+ if (dy > 32) return {
+ x: 0,
+ y: 1
+ };
+ if (dy < -32) return {
+ x: 0,
+ y: -1
+ };
+ }
+ return null;
+}
+game.down = function (x, y, obj) {
+ swipeStart = {
+ x: x,
+ y: y
+ };
+ dragNode = pacman;
+};
+game.move = function (x, y, obj) {
+ if (!swipeStart) return;
+ var swipeEnd = {
+ x: x,
+ y: y
+ };
+ var dir = getSwipeDir(swipeStart, swipeEnd);
+ if (dir) {
+ pacman.nextDir = dir;
+ swipeStart = null;
+ }
+};
+game.up = function (x, y, obj) {
+ swipeStart = null;
+ dragNode = null;
+};
+// --- Game Update Loop ---
+game.update = function () {
+ if (!pacman) return;
+ lastGameOver = false;
+ updatePacmanDirection();
+ pacman.update();
+ for (var i = 0; i < ghosts.length; ++i) {
+ updateGhostDirection(ghosts[i]);
+ ghosts[i].update();
+ }
+ checkPelletEat();
+ checkGhostCollisions();
+ updateFrightened();
+};
+// --- Game Start ---
+function startGame() {
+ score = 0;
+ LK.setScore(0);
+ scoreTxt.setText('0');
+ buildMaze();
+ spawnPacman();
+ spawnGhosts();
+ frightTicks = 0;
+ frightActive = false;
+ lastGameOver = false;
+}
+startGame();
\ No newline at end of file
Pacman red ghost. In-Game asset. 2d. High contrast. No shadows
Pacman pink ghost. In-Game asset. 2d. High contrast. No shadows
Pacman blue ghost. In-Game asset. 2d. High contrast. No shadows
Pacman orange ghost. In-Game asset. 2d. High contrast. No shadows
Pacman dark blue ghost with plain white eyes. In-Game asset. 2d. High contrast. No shadows
Pacman with mouth closed pixilated . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Pacman. In-Game asset. 2d. High contrast. shadows. Outline. Pixilated
Pacman with mouth opened pixilated . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Pacman cherry. In-Game asset. 2d. High contrast. No shadows
Pixilated ice cream. In-Game asset. 2d. High contrast. No shadows
Pixilated pizza. In-Game asset. 2d. High contrast. No shadows