Code Correctness
Like last week, in addition to the functionality of your code, we also want you to focus on your code quality. For the complete list of code quality items we’ll look at throughout the quarter, please consult the code quality document.
Setup
Before we start, register for the project using the registration tool.
Engine Changes
Like last week, our engine library has been updated with even more functionality this week. Unlike last week, you will actually be using the library to implement a demo this week. Let’s go over the changes that were made to the engine; we encourage you to follow along by reading the relevant files as you read the guide. We also highly recommend you to read the engine changes in its entirety before writing any code for the demo.
body_t
body_t
still retains most of the functions that it had last week, although some have been repurposed
(for example, body_translate
has been replaced by body_set_centroid
). body_init
also doesn’t
take in an initial velocity nor rotation speed, but it does take in a mass. The mass
won’t be useful for this project, but it will be once forces and collisions are
implemented in the engine. We also wanted to highlight that body_rotate
has been repurposed to
body_set_rotation
and is used slightly differently. Read its documentation carefully to
understand how to use it.
We’ve also renamed the body_move
function to body_tick
. We’ve done so to
introduce the idea of a game “tick” during which state gets updated.
This is basically a wrapper around the dt
idea we’ve been using.
list_t
list_init
now contains a free_func_t
parameter. The free_func_t
type
is defined at the top of list.h
. Essentially, it’s defining the free_func_t
type as any function that returns void
and takes in a void *
(generic pointer).
You can’t see the implementation of list_free
, but suppose we didn’t take in a
free_func_t
parameter. Then a reasonable (and probably the only valid) implementation of
list_free
is to free()
every element that it contains, and then to
free the list_t
itself. However, what if the objects inside the list_t
allocate memory for their fields? In the case for an object like body_t
, free()
would only free the space allocated for the body_t
struct, but not any of the fields
that might’ve been allocated in body_init()
, leading to memory leaks. Thus, we
pass in a free_func_t
so that the list_t
knows which function to run on each element
when list_free
is called. In the case of our body_t
example, we would initialize
a list_t
of bodies with list_init(capacity, body_free)
.
Importantly, list_t
takes ownership of its elements depending on if freer
is NULL
or not. If freer
is NULL
, then the list_t
doesn’t free its elements
whatsoever when list_free
is called. This might not be relevant to this project, but it will be if you ever
want to keep ownership of an item while adding it to a list_t
.
scene_t
This week, we’ve added a new scene_t
abstraction to represent a collection of bodies.
While its functionality seems pretty basic for now, it will be much more helpful
in later weeks and prove to be much easier to manage than a list_t
of bodies.
We highly recommend you to start using it this week, for another reason that will
be mentioned below.
sdl_wrapper
We’ve added an sdl_render_scene
function that takes in a scene_t
and renders
all of its bodies onto the screen. This is yet another example of abstraction and
helps us by calling many of the sdl
functions for us.
Most importantly, we’ve also implemented key handling in our sdl_wrapper
this week.
We’ve updated sdl_wrapper.h
with the new arrow_key_t
and key_event_type_t
enums,
an sdl_on_key
function, and
and a new key_handler_t
type (similarly to how we defined a free_func_t
type
in list.h
). Futhermore, sdl_is_done
has been
updated to handle keypresses.
Rather than elaborating further on the changes, we want you to figure out
how they all work together. Carefully read the contents of each new/modified function
in sdl_wrapper.h/c
along with their documentation. If you need more help, we
encourage you to come talk to a TA at office hours.
Note on sdl_wrapper
changes:
Since you might’ve made changes to sdl_wrapper.c/h
last week to implement text,
it would be good practice to copy any changes you made over to the new sdl_wrapper.c/h
files this week, being
careful not to overwrite any of the new functions we’ve provided. However, since you don’t
need to add text to this week’s game, it’s not strictly necessary, but you might need
to copy it over at some point for a later project.
This week’s library changes place a big emphasis on abstraction and ownership. While you might be tempted to call a function directly on an object, it might already be called by another object that owns it.
This is why you should at least skim through all of the .h
files before writing any code. This will give you a good idea for what is being
done for you when you use each struct
and will almost definitely save you time/confusion later down the road.
Deliverable
Task 0. This week, you will be implementing a “pacman” demo which should look something like the following (the arrow keys on the bottom are an overlay to show you what is being pressed–not part of the scene):
This week’s demo is a pacman-like game in which pacman runs around the screen eating pellets. The novel SDL feature this week is keyboard events, so 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 (at least) the following:
- pacman should move around and change direction based on the arrow keys
- pacman should accelerate proportionally to how long the key has been held down
- pellets spawn in random locations at some interval (a function in
math.h
will be helpful for this) - when pacman runs into a pellet, it should disappear
- pacman should “wrap around” the screen in both directions
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.
emscripten_free
must be written correctly for full credit on the project. Note that emscripten_free
is never actually run, so you will not be able to tell if it’s correct or not just by running the demo.
We will manually check if emscripten_free
correctly frees all the memory that is
initialized in your project.
To compile pacman.c
you will want to use the make demo
command. Once you navigate to the link printed
to the shell (the last line before “Serving HTTP on …”), click the compiled pacman.demo.html
file.
Once you are done, push your code to GitLab to finish the project.