CS 70

Setting the Scene

  • Cat speaking

    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.

  • Pig speaking

    And I wish I had MORE control over how the sprites move in the scene, like BOUNCING off the walls and such!

  • LHS Cow speaking

    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 call scene.getSprite(i) to get each sprite to render. We also don't move the sprites here anymore.
    • Scene::getSprite returns a const Sprite&, which means we can't modify the sprite through this reference. This restriction is intentional, as the Scene class will be responsible for updating the sprites' positions. Using a reference also saves needless copying of the Sprite objects, which is especially important because copying Sprite 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);
}
  • Dog speaking

    Whoa! That code for makeOurMovie is way simpler now! It's like a thing of beauty.

  • Goat speaking

    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.

  • Duck speaking

    Couldn't I just initialize the array in the body of the constructor?

  • LHS Cow speaking

    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.

  • Cat speaking

    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.

  • LHS Cow speaking

    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!

  • RHS Cow speaking

    We often give “Helpful Hints” at this point, but a goal for this part is to have you be a little more self sufficient.

  • LHS Cow speaking

    Remember, though: You can always talk to your professor or grutors if you get stuck!

To Complete This Part of the Assignment

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)