The way this game is set up, the three basic tasks
- carrying out "chosen" direction changes (random or user-commanded)
- changing location (stepping forward, possibly with a
change in direction dictated by bouncing off a wall, and
- determining whether the player dies
can be done as three separate tasks. Do it that way! Have a
chunk of code that goes through all the objects and checks for
& carries out chosen changes of direction. Then have a
chunk of code that goes through all the objects and steps them
forward (which may involve bouncing). Then have a chunk of code
that goes through all the object and determines whether there
has been a collision that kills the player.
Keep these tasks separate!
Debugging a program that uses ncurses can be a bit bothersome.
For example, one of the most basic debugging techniques is
to temporarily add cout (or better, cerr) lines to output
messages as the program runs. With ncurses, however, that
output interferes with the ncurses output, making this technique
pretty much unusable. Using "valgrind" to help diagnose
segfaults has the same problem. However, in Lab 11 we showed
you an easy fix for these problems, which we'll recapitulate
here. We strongly recommend that you try this before you move on
from Part 1, even if your Part 1 works perfectly and there's
nothing to debug.
Note: the ncurses wgetch(W)
function (in "no-delay mode", as you'll be using it) is
"non-blocking". That means that it doesn't wait for the user
to to press a key. Instead, it returns the appropriate key if
a key has just been pressed, and returns the
constant ERR otherwise.
So, for example, adding the line shown in red below to your
Part 1 code would print a message whenever the user pressed a key.
...
char c = wgetch(W);
if (c != ERR) { cerr << "Read a '" << c << "'!" << endl;
if (c == 'y') break; // game exits with a 'y'
...
If you want to take advantage of this, however, you need
messages written to
cerr to print somewhere else
other than the terminal window that's showing the ncurses output.
-
Create a fifo in the same directory as your project 3
work using the command
If you are
- on a lab machine,
- ssh'd into a lab machine, or
- on your VM but not in csunix
or any of its subdirectories
do the following:
|
If you are on your VM and working in csunix or one of
its subdirectories, do the following:
Note: this will require typing your password as it is
ssh'ing into an academy machine
Note: please copy and paste this! It's too
easy to mess up typing by hand.
|
mkfifo err |
perl -e '`pwd`=~/csunix(.*)$/; `ssh mope mkfifo ./$1/err`;' |
Do an ls and you should see "err" show up in the directory
listing. The fifo "err" is like a wormhole in the Unix
filesystem.
Note: you only need to do this once!
-
Open a separate terminal window, cd to the project 3
directory containing "err", and give the command
tail -f err
Go back to your original terminal and type something like
this:
echo "whoooooooo" > err
You should see the whoooooo pop up in the other terminal.
Spooky, eh?
-
Now run project3's part 1 in the original terminal like this:
./a.out 2> err
... and watch as your ncurses window is pure and unblighted
by debugging messages, but the message does pop up at the
appropriate time in the second window. What's going on here
is this: the 2> err is telling the shell to
redirect standard error (cerr in our program) output to the
fifo err, from whence it travels by wormhole to
the less -f running in the other window.
Note: you can also use "valgrind" this way, which is
useful if you have a segfault, though it requires compiling
with the -g option to insert debugging
information. You would run your program like this:
valgrind ./a.out 2> err
... and watch as the valgrind messages display in the second
terminal window.
Important: You'll want to use this technique
throughout this project!
All moving objects in this project bounce off walls in the same
way. Part 2 of the project explains this precisely and
completely, but I thought maybe some pictures would be in order.
Normally, if moving one step in the current direction would put
you inside a wall, you turn 180 degrees and step in the new
direction (away from the wall), all in one turn. Like this:

The only "tricky" situation is when there is a wall both in your
current direction and in the opposite direction. In that case,
the object stays in the same place and in the same direction,
like this:

There are two (and only two!) ways that objects in this game can
collide. Either after one "step" they end up occupying the same
square, like this:

... which is of, of course, the obvious case. Less obviously,
two objects can also collide by swapping positions, like this:

Identifying this is a bit tricky, because you have to know not
only what square the object is in at time
t, but also
what square the object was in prior to that move, i.e. at time
t-1.