Setting the Scene
I know that the code's just using concepts we've seen, but I don't much like the “reference to an array” syntax argument to
Asciimation::play
. It seems a bit clunky.And I wish I had MORE control over how the sprites move in the scene, like BOUNCING off the walls and such!
Let's make things better!
In this part, you're going to create a new class called Scene
that will manage multiple sprites and their movements. This addition will allow you to have more complex interactions in your animation, such as bouncing off walls or even responding to user input.
The Vision
We're going to change the Asciimation::play
function to take a Scene
object instead of an array of Sprite
objects. The Scene
class will hold an array of sprites and manage their movements and interactions. The play
function will now look like
void Asciimation::play(Scene& scene) {
// Time to sleep between screen refreshes
const int PAUSE_TIME_IN_MICROSECONDS = 40000;
Display display{MOVIE_WIDTH, MOVIE_HEIGHT};
// Play the movie by refreshing the screen with new data, every so often
int key = 0;
bool finished = false;
int numSprites = scene.getNumSprites();
while (!finished) {
clearFrame();
// Render all sprites
for (int i = 0; i < numSprites; ++i) {
renderSprite(scene.getSprite(i));
}
// Show the frame on the screen
copyToScreen(display);
display.refresh();
// Sleep between updates
usleep(PAUSE_TIME_IN_MICROSECONDS);
// Check to see if the user has entered 'q' to quit
key = display.checkForKeypress();
if (key == 'q') {
finished = true;
}
// Update the scene for the next frame
scene.advance(key, screenBounds_);
}
}
Here's what's changed:
- In the
for
loop, we now callscene.getSprite(i)
to get each sprite to render. We also don't move the sprites here anymore.Scene::getSprite
returns aconst Sprite&
, which means we can't modify the sprite through this reference. This restriction is intentional, as theScene
class will be responsible for updating the sprites' positions. Using a reference also saves needless copying of theSprite
objects, which is especially important because copyingSprite
objects is disallowed (the copy constructor is disabled).
- At the end of the loop, we call
scene.advance(key, screenBounds_)
to update the scene for the next frame. This function is where the sprites will be moved and any interactions will be handled. We pass in any key that was pressed, in case we want the scene to be affected by user input.
Likewise, the our-movie.cpp
file will change to create a Scene
object and pass it to play
:
void makeOurMovie() {
Scene theScene;
Asciimation ourMovie;
ourMovie.play(theScene);
}
Whoa! That code for
makeOurMovie
is way simpler now! It's like a thing of beauty.I love the way it doesn't need any comments because it's so obvious what it's doing. Less code FTW!
Your Task
Your task is bring this vision into reality by implementing the Scene
class and modifying the Asciimation
class and our-movie.cpp
file as described above.
Unlike previous parts where we've often spelled out exactly what to do, this time you'll need to plan it out with your partner. To make our autograder happy, you are required to implement the Scene
class in scene.hpp
and scene.cpp
files, and modify asciimation.hpp
, asciimation.cpp
, and our-movie.cpp
as described above.
There's one exception: We know from experience that students struggle with member-initialization lists, and initializing an array in one is a bit outside what you've seen so far, so here's the code for a constructor that mirrors the existing behavior of the program:
Scene::Scene()
: sprites_{
{"mystery1.tsprite", 30, 5} // mystery image at column 30, row 5
} {
// It's moving to the right...
sprites_[0].setVelocity(1, 0);
}
This constructor initializes the sprites_
array with one sprite, just like the code we began with, and sets the sprite's velocity to move to the right. You can modify this constructor to add more sprites or change their initial positions and velocities as you see fit.
Couldn't I just initialize the array in the body of the constructor?
No. Once we're in the body of the constructor, the compiler will have already default initialized the array. Except that it will have failed because
Sprite
objects are not default constructible. So you must use the member-initialization list to initialize the array.Actually, we could specify the initialization in the declaration of the array in the class definition (in the header). Then it would work exactly the same is it does in
our-movie.cpp
now.Yes, that would work, too.
Your goal at this stage is to add the Scene
class, but otherwise have your code behave exactly as it did before. Once you've done that, you can move on to the next part where you can get creative with your scene!
We often give “Helpful Hints” at this point, but a goal for this part is to have you be a little more self sufficient.
Remember, though: You can always talk to your professor or grutors if you get stuck!
(When logged in, completion status appears here.)