Movement
First, remove all the test actors from the previous part, but keep the actor that uses the Stars.png
background texture as that’ll be the background for the game.
The MoveComponent
class will implement actor movement. We’ve given you a declaration of the class, but you’ll have to implement the Update
function.
Remember that in Actor::Update
, you call Update
on each component associated with that actor. So by giving an actor a MoveComponent
, the movement code contained in it will run every frame.
Before you can implement Update
, create a function in Actor
called GetForward
that returns the forward direction vector of the actor. Since the game is 2D, you can compute this using the unit circle equation covered in class. Remember that since +y is down in SDL, negate the y component of the equation.
MoveComponent
has the following member variables:
- An angular speed (in radians/second)
- A forward speed (in pixels/second)
Inside MoveComponent::Update
, first add code to update the owning actor’s rotation over time. This is very similar to the position update equation covered in lecture, except instead of position and velocity vectors, you have scalars for the current angle and angular velocity/speed.
Next, add code to updates the owning actor’s position based on the owning actor’s forward vector, the forward speed, and delta time (this is exactly like the slides at the end of the lecture).
To make sure that MoveComponent
updates before other components update, we’ve set it’s “update order” variable to a lower number than the default of 100
.
Ship
Now it’s time to create new files. We’re first going to create a subclass of Actor
called Ship
in two new files (Ship.h/cpp). The best way to create the files depends on whether you’re in Visual Studio or Visual Studio Code.
In Visual Studio:
- Right click on the folder for the Lab in the solution explorer (so in this case,
Lab02
) - Select Add>New File
- Rename “New File” to whatever you want, so in this case
Ship.cpp
. Then repeat steps 2/3 forShip.h
, as well.
In Visual Studio Code:
- Right click on the folder for the Lab in the file list (in this case,
Lab02
- Select Add>New File
- Rename the file to whatever you want, so in this case
Ship.cpp
. Then repeat steps 2/3 forShip.h
, as well.
Now in your Ship.h file, declare a subclass of Actor
called Ship
. Since you’re subclassing Actor
, you can’t just use a forward declaration and you DO have to #include "Actor.h"
. The constructor of Ship
takes in a class Game*
parameter (as all Actor
subclasses must).
Then, add two member variables (for these, you can use forward declarations):
- A
MoveComponent*
- A
SpriteComponent*
Since the Actor
constructor takes in a game pointer, the implementation of the Ship
constructor (in Ship.cpp) needs to pass the game pointer along in its initializer list, like this:
Ship::Ship(Game* game)
:Actor(game)
{
// TODO: Add code here
}
Inside the Ship
constructor, dynamically allocate a SpriteComponent
and a MoveComponent
, and assign them to the member variables for these components. Use "Assets/Ship.png"
for the texture.
Create an instance of the Ship
in Game
and set its initial position to the center of the screen. Try various hardcoded angular/forward speeds just to make sure your movement works.
Hooking Up Input
Now, in the declaration for Ship
, add an override of OnProcessInput
. In this function, use the key state array to query the different keys (like SDL_SCANCODE_A
). Based on the keys, you want to change the forward and angular speed of the MoveComponent
the ship is using. Make it so the controls work as follows:
- Pressing
W
moves forward while pressingS
moves backwards. If bothW
andS
are pressed, the ship shouldn’t move forward or backwards. - Pressing
A
rotates the ship counter-clockwise while pressingD
rotates the ship clockwise. If bothA
andD
are pressed, the ship shouldn’t rotate. - It is possible for the ship to move and rotate at the same time.
You should now be able to move and rotate the ship.
As an alternative to creating member variables to store the different components, you could instead use the templated GetComponent
function that’s provided in Actor
. For example, the following would get the pointer to the actor’s MoveComponent
MoveComponent* mc = GetComponent<MoveComponent>();
However, calling GetComponent
every frame is not efficient when you know the component pointer isn’t going to change. That’s why we tell you to make a pointer to the components as member variables.
That being said, in cases where you don’t actually know the type of Actor
subclass you’ve got a pointer to, it’s very helpful to use GetComponent
to get a component if a specific type (if there is one).
Changing the Ship Texture when Moving
For some polish, add code in Ship
that changes the sprite component texture to "Assets/ShipThrust.png"
when the ship moves forward or backwards. When the ship’s not moving, set the texture back to the default "Assets/Ship.png"
.
When the ship flies around it should now look like this:
Once you’e pushed this code, you’re ready to move on to part 3.