Skip to main content Link Search Menu Expand Document (external link)

Theme: auto

Basic Actors and Drawing

In this first assignment, we are going to setup a few classes to support or “game object model” which we will talk more about in Week 2. We’ll use the term actor to reference any object in the game world. For example, in Pong, the ball, paddle, and walls will all be “actors.”

Transform

The Transform class is a container for information about where actors are in the world, their size, and so on.

In Transform.h, declare a class called Transform. In the private data, it will need two member variables that are both type Vector2:

  • The position, which represents the center position of the actor
  • The size, which represents the width (the x component) and the height (the y component) of the actor

Getters/Setters

You should declare public getter and setter functions for the position and size, respectively, and they must have the following signatures:

const Vector2& GetPosition() const;
const Vector2& GetSize() const;

void SetPosition(const Vector2& position);
void SetSize(const Vector2& size);

Notice how we are using const references for Vector2s to avoid making copies.

Implement these getter and setter functions (you can implement them inline in the declarations if you want to).

GetRect

Next, add the following function declaration:

SDL_FRect GetRect() const;

The implementation of this function needs to create an SDL_FRect on the stack (i.e. do not allocate it with new), assign the x, y, w, and h values based on the position/size members, and return the SDL_FRect.

Keep in mind that our actor position is the center but SDL_FRect uses the top left corner for the x/y values, so you’ll have to calculate it.

Make sure your code still builds.

Actor

For now, the Actor will just have a Transform in its protected member data.

Then, you need two versions of a GetTransform function in the public section:

// This version allows us to modify the transform
Transform& GetTransform();
// This version is for cases where we don't need to modify
const Transform& GetTransform() const;

The implementations of both functions are the same; they just need to return the transform member variable. But we made one version that allows for modification of the transform, so you can later write code like:

myActor->GetTransform().SetPosition({50.0f, 30.0f});

Make sure your code still builds.

Tracking Actors in Game

The game needs to keep track of all the actors in the game. So, add a std::vector<Actor*> to the private data in Game. You’ll need to add the appropriate includes for this.

CreateActor

Whenever we dynamically allocate a new actor, we also need to add it to the Game’s std::vector. But it would be annoying to have to manually add it to the vector every time you create one, so we will make a public member function in Game called CreateActor:

Actor* CreateActor();

This function needs to:

  1. Dynamically allocate an Actor, saving it in a pointer
  2. Add the actor created in (1) to the Game’s std::vector of actors
  3. Return the actor pointer

LoadData and UnloadData

Add two private member functions to game: LoadData and UnloadData. Both functions take no parameters and return void.

When you add a declaration of a function in the header file, the quickest way to add a stub implementation of the function is to let CLion create the implementation for you. If you mouse over the declaration, you’ll see that CLion knows you are missing an implementation:Missing implementationThen, right-click (or two finger tap or Ctrl+tap on a Mac), select “Show Context Actions”:Show Context ActionsFinally, select the “Generate Definition” option, which will create the definition in the .cpp file:Generate DefinitionUsing this feature will save you a lot of time!

For now, the implementation of LoadData can be empty. Call this function in Game::Initialize, right before you return true.

In UnloadData, you need to loop over the Game’s std::vector of actors, calling delete on each pointer. Then, after the loop, clear() the vector. This makes sure we aren’t leaking memory! Call this function at the start of Game::Shutdown.

Creating Your First Actor

Now in LoadData, call CreateActor to make an actor for the ball. You want this actor’s position to be in the center of the window and a size that’s 15x15. Keep in mind to change the position or size, you’ll have to chain your call to SetPosition or SetSize off of GetTransform, like GetTransform().SetPosition

To make it easy to later modify the ball, save the Actor* you get from CreateActor into a private member variable for the ball.

You won’t see the ball yet, but make sure your code still builds!

Drawing

SDL rendering uses a back buffer (which we’ll cover later in the semester). For now, just know that every frame, the game code must clear the back buffer, draw the scene, and “present” the back buffer.

In GenerateOutput, do the following:

  1. Set the render draw color to black (0, 0, 0, 255) using SDL_SetRenderDrawColor: https://wiki.libsdl.org/SDL3/SDL_SetRenderDrawColor
  2. Clear the rendering target using SDL_RenderClear: https://wiki.libsdl.org/SDL3/SDL_RenderClear
  3. Set the render draw color to whatever color you want your Pong actors to be. I chose cyan, which is (0, 255, 255, 255), but feel free to use whichever color you like!
  4. Loop over all the actors in the Game’s std::vector. For each actor, call GetTransform().GetRect(), saving it in a local variable, then call SDL_RenderFillRect: https://wiki.libsdl.org/SDL3/SDL_RenderFillRect
  5. Present using SDL_RenderPresent: https://wiki.libsdl.org/SDL3/SDL_RenderPresent

You should now see a ball in the center of the window, like this:BallIf you don’t see the ball in the center, put a breakpoint on the SDL_RenderFillRect line. If it doesn’t get hit at all, try to put some more breakpoints to figure out why not? If it does get hit, check the what values your SDL_FRect has. It should have x=392.5, y=292.5, w=15, h=15. If it doesn’t, put a breakpoint in your GetRect function to figure out why it’s not giving the expected value. Are your position and size variables correct? Is there something wrong with your calculations in GetRect?

Adding the Walls

Now create three more actors for the left wall, right wall, and top wall. Their sizes will be different based on the sides, but you want it to be 15 pixels thick (which you should make a constexpr. You should take advantage of the window width/height constants, as well! You also should save these pointers in member variables in Game.

You should now have a left, top, and right wall:Walls

Adding a Paddle

Finally, create an actor for the paddle. It should have a width of 100 and a height of 15, and be near the bottom of the screen, horizontally centered. You’ll also want a member variable pointer for this.

You should now have a paddle:Paddle

Make sure you push your code. You’re now ready to make things move in Part 3.