The way this game is set up, there are 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.
These 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" (for those who've seen
it) 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 file
err in the same directory as your project 3
work using the command: echo > err
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.
Note: For those of you who've seen it, 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.