PACMAN BATTLE

Desktop screen of PacMan Battle
CONTACT

OVERVIEW

PacMan Battle Thumbnail

The Problem
Traditional Pac-Man is a single-player game, limiting opportunities for competitive and cooperative gameplay.

The Goal
Expand Pac-Man into a two-player experience while maintaining the classic feel and mechanics.

My Role
I was responsible for game design and development, from ideation to prototyping and final implementation, as part of a team of four

The Setup
This group projext was part of the "Frontend Development" Module at the University of Applied Sciences Grisons. Over one year we learned programming principles and applied them directly to this game.

UNDERSTANDING THE USER

Competitive Audit

To ensure PacMan Battle provided an engaging and competitive multiplayer experience, we conducted a competitive audit, analyzing existing projects to understand what works and what doesn’t. Our goal was to convert the iconic game into a multiplayer format while staying true to its retro aesthetic and mechanics.

Limitations

To ensure PacMan Battle provided an engaging and competitive multiplayer experience, we conducted a competitive audit, analyzing existing projects to understand what works and what doesn’t. Our goal was to convert the iconic game into a multiplayer format while staying true to its retro aesthetic and mechanics.

Persona

Since extensive research already existed on Pac-Man’s target audience, we conducted a secondary analysis to understand our potential users better. Based on the findings, we developed an ad-hoc persona to capture our target group's needs and frustrations.

Persona Lukas and his characteristics

Point-of-View (PoV) statement

Lukas is a retro game enthusiast, who needs an engaging multiplayer experience of PacMan, because it allows him to relive the nostalgia of the game while playing socially with friends.

PROTOTYPING

Sketching

To explore different design concepts, we visualized the game layout through digital sketches. Early iterations helped us quickly refine design choices before programming, ensuring that we can set the focus on JavaScript which was the main part of this module.

Usability Test

Once our initial game layout was in place, we conducted usability testing to validate our design decisions and test the functionality of our code.

A prototype of PacMan Battle

The usability test involved a live demonstration of the prototype to a group of 11 participants. They could play freely and explore the mechanics naturally. We observed this real-world user interactions and conducted interviews to identify areas for improvement:

Improvements

Tunnel Mechanic:
Removed due to a bug where characters could escape the game area

Scoring System:
Adjusted points to create a fairer competitive game

Local Score Storage:
Added a local storage to see how the user compared to previous scores

Interactive Quiz:
Introduced a Pac-Man-themed quiz to maintain engagement

Tunnel Mechanic:
Removed due to a bug where characters could escape the game area

Scoring System:
Adjusted points to create a fairer competitive game

Local Score Storage:
Added a local storage to see how the user compared to previous scores

Interactive Quiz:
Introduced a Pac-Man-themed quiz to maintain engagement

IMPLEMENTATION

PacMan Battle Home Screen

Gameplay

Quiz

Code

The game board is built using a grid-based system, where each tile represents different objects in an array.


// Map Example
const map = [
    ['1','a','a','2'],  // Walls = a / Corners = Numbers
    ['b','.','.','b'],  // Pellets = . / Vertical Walls = b
    ['b','p','p','b'],  // Power‑ups = p
    ['4','a','a','3']   // Walls = a / Corners = Numbers
];

// Dynamic Generation
function generateMap () {
    map.forEach((row, i) => { 
        row.forEach((symbol, j) => { 
            if (symbol === '.') {
                pellets.push(new Pellet({ position: { x: j * 32, y: i * 32 }}));
            } else if (symbol === 'p') {
                powerUps.push(new PowerUp({ position: { x: j * 32, y: i * 32 }}));
            } else {
                boundaries.push(new Boundary({ position: { x: j * 32, y: i * 32 }}));
            }
        });
    });
}

Pac-Man's movement follows a collision-based system. To avoid conflicts with webpage functions, only W, A, S, D keys were assigned for player controls.


// Player Movement
document.addEventListener("keydown", (event) => {
    switch (event.key) {
        case 'ArrowUp': player.velocity.y = -3; break;
        case 'ArrowDown': player.velocity.y = 3; break;
        case 'ArrowLeft': player.velocity.x = -3; break;
        case 'ArrowRight': player.velocity.x = 3; break;
    }
});

// Collision Detection
boundaries.forEach((boundary) => {
    if (circleCollidesWithRectangle({ circle: player, rectangle: boundary })) {
        player.velocity.x = 0;
        player.velocity.y = 0;
    }
});

The ghosts navigate randomly while avoiding walls. At the same time, the AI adjusts movement based on available paths.


// Ghosts Movement
const possibleDirections = ['up', 'down', 'left', 'right'];
const randomDirection = possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
switch (randomDirection) {
    case 'up': ghost.velocity.y = -3; break;
    case 'down': ghost.velocity.y = 3; break;
    case 'left': ghost.velocity.x = -3; break;
    case 'right': ghost.velocity.x = 3; break;
}

// Ghosts Change Behavior
ghosts.forEach(ghost => {
    ghost.scared = true;
    setTimeout(() => ghost.scared = false, 5000);
});

Multiplayer turn system


// Round Timer
var timeLeft = 20;
var timerId = setInterval(() => {
    timeLeft--;
    if (timeLeft === 0) {
        clearTimeout(timerId);
        switchTurn();
    }
}, 1000);

// Switch Turn
function switchTurn() {
    currentPlayer = currentPlayer === 1 ? 2 : 1;
    resetPlayerPosition();
}

Scoring System and Power-Ups


// Power-Up Collision Effect
if (circleCollidesWithRectangle({ circle: player, rectangle: pellet })) {
    pellets.splice(i, 1); // Remove pellet
    score += 10; // Increase score
}

// Power to Eat Ghosts
if (circleCollidesWithRectangle({ circle: player, rectangle: powerUp })) {
    powerUps.splice(i, 1);
    ghosts.forEach(ghost => ghost.scared = true);
}

Let's work together!

For any inquiries, collaborations, or just to say hello. I would love to hear from you!

© 2025 Anthony Zoss. All rights reserved.