CS 18 (Spring 2026) Project 01: Pacman (Demo)

In this project, you will implement a simple pacman game.

Code Correctness

If you haven’t already, please do the Setup for the course!

Goals and Deliverables

This week, you will build a basic pacman game that uses a basic library that one of your teammates implemented.

We think it is important to “see” your work as you go. So, every week, your team will write a small simulation that uses the engine work you’ve completed that week. These will get ever closer to “correct” physics as we go!

Ticks and the Main Run Loop

We’re going to be working through a lot of graphics-related code in this class, so it’s important to understand the basic concepts behind drawing graphical content to the screen.

When we talk about graphics in the context of writing software, we are dealing with computing the contents of individual frames in real-time, clearing the canvas of the previous frame, and drawing the new computed frame, all at regular intervals. If you want your graphics to look realistic, you need to have a reasonable measurement of the time between frames, since our goal is to generate a graphical representation that is independent of the speed at which frames are processed by the computer. This is why low frame rates in graphics-intensive games result in a scene that is choppy – each frame encompasses a large amount of real-world time, causing objects to move large distances in each frame. The most basic implementation of a graphical application, then, looks as follows:

while app_is_running:
    dt = time_since_last_frame()
    object_pos = compute_new_positions(object_pos, dt)
    
    clear_screen()
    draw_frame_offscreen()
    display_frame()

We’ve provided a few helper functions to help facilitate writing these functions. You can see how they interface with the lower-level SDL2 library in sdl_wrapper.c.

Files of Importance

The above basic loop is implemented in emscripten.c, which relies on a number of functions you will write in your demos - namely, emscripten_init, emscripten_main, and emscripten_free. emscripten.c serves as the basic functionality of all our demos - you do not need to modify this file. Notably, because emscripten.c implements the main while loop described above, your pacman.c file should not have a main loop.

The header file for the functions you write in your demo is state.h, which tells emscripten.c that these three functions are properly defined elsewhere. You do not need to write a state.c file - you should write the three functions in the header in your pacman.c demo as mentioned above. Notably, state.h also includes an opaque type definition for a “state”. This is a struct that you will define in each of your demos (here, in pacman.c). This state struct is how you will pass information between your three functions - anything you initialize in emscripten_init that you need in your emscripten_main loop should be put in this state accordingly and returned. You are responsible for defining the state’s parameters, malloc’ing it in emscripten_init and freeing it in emscripten_free.

Using the basic breakdown of the files above, and the documentation in sdl_wrapper.h and state.h, you should be able to get a good idea of how to implement a graphical application in C, using our wrapper library.

Although it does not use the same abstractions, the circle.c demo works with emscripten.c and state.h in the same way you will.

Deliverable

This week’s demo is a pacman-like game in which pacman runs around the screen eating pellets. A major part of the demo is keyboard events–the user should be able to control pacman using the arrow keys. To implement this, we recommend thoroughly reading through sdl_wrapper.c/h.

We expect your demo to contain the following:

In pacman.c, we have given you some starter code to create the pacman shape and pellet bodies. However, the rest of the demo is left to you.

You should write your emscripten_init to initialize everything you need for the demo, including the SDL window itself (you will find functions in sdl_wrapper.c to be useful here). Then, in emscripten_main, you should update the position and velocity of your pacman based on the arrow key that is pressed, how long the key has been held for, and the time elapsed since the last frame. When the demo exits, emscripten_free is called, so you should write this function to clean up all the memory you allocated in the demo.

One of your group members should’ve implemented body_t, scene_t, and vector_t. Talk to them to get a sense of how to use these structures and how they are implemented.

We’ll also point out a few things about list_t that should help with interacting with them:

Running and Testing your Code: make and the Makefile

All the projects in our class will have the following directory structure:

We have provided you with a Makefile which is set up to build the project. It allows you to run the following commands:

This year, we will be testing demos via a web interface hosted on labradoodle, using a library called emscripten.
Every student has been assigned a port, which you can see after running make demo or make server, or by running cs3-port in a shell on labradoodle. To run your demo, you should run make demo or make server and then navigate to the link printed to the shell (the last line before “Serving HTTP on …”) and click the compiled demo .demo.html file. If you see an error that says Address already in use, please run cs3-kill-web in the terminal and rerun make demo. If you’ve made changes to your code but make demo generates the link instantly, you might have to run make clean before make demo again to recompile the demo.

One additional part of testing any game/demo code will be ensuring that there are no memory leaks. For the physics engine, we can run the leak sanitizier after the test finishes, but for demos/games, there is no obvious “end of execution” unless the player loses/wins, which isn’t always defined. Thus, we’ve set up the “esc” key on the keyboard to run emscripten_free and kill the demo/game when pressed. Once you press “esc,” you should be able to see any memory leaks if you Inspect Element and go to “Console.” If you see any memory leaks, make sure to fix them!

If there are no memory leaks, the console should look like this (you can ignore the RuntimeError which will always get thrown when we kill the demo):

If there are memory leaks, the console should report the lines that are causing them like this (the relevant lines are boxed in blue):

In this example, the memory leak was caused by our malloc call on line 177 of pacman.c.

Note that there is nothing special about the “esc” key in this case; we’ve just chosen to bind it to emscripten_free. Once you start working on your final game, feel free to change this keybinding, but please don’t do so until we are done with all the projects this term.

We will take off points if your code has memory leaks, so be sure to check for them before you submit your code!

Once all your group members have finished, work with them to complete the extension (more information in the main project page).