Energy Launcher Puzzles
For this part of the lab, we aren’t going to give you as detailed instructions and instead are going to ask you to implement the gameplay features as specified. You will need to use what you know to implement the features!
That being said, the instructions will still specify some constants in order to make sure your game behaves appropriately. And there will be a few hints sprinkled throughout, as well.
Basic Energy Launchers
There are doors, and these doors initially start as “closed.” For this lab, the door will not visually look closed, but it will start out as a collider so you won’t be able to go through it. Once the door “opens,” it should be removed from the colliders vector so you will be able to go through it. Doors have a unique key in their JSON data:
"name"
(required; string) - specifies a unique name for that door
The energy launchers shoot pellets periodically, and have these unique keys in their data:
"cooldown"
(optional; float) - specifies how frequently the energy launcher shoots a pellet. If this is not specified, the cooldown for theEnergyLauncher
should default to 1.5f."door"
(optional; string) - which door name this energy launcher is associated with. If the door is open, the energy launcher will not fire any more pellets
If a pellet intersects with an energy catcher, then the pellet will stop moving and the energy catcher will open a corresponding door. Energy catcher has this unique key:
"door"
(optional; string) - which door name this energy catcher is associated with. If the energy catcher catches a pellet, it will “open” the corresponding door
Creating Actors
First, create these classes and add code to load them in LoadActor
. The "type"
in the JSON file corresponds to the name of the class. Make sure you also add any properties as needed to track the keys specified above:
Door
:- Uses the
"Assets/Meshes/DoorFrame.gpmesh"
mesh - Has collision component with a size from the mesh
GetWidth(), GetHeight(), GetDepth()
- Is a “collider”
- Uses the
EnergyLauncher
:- Uses the
"Assets/Meshes/EnergyLauncher.gpmesh"
mesh - Has a collision component with size
(50.0f, 50.0f, 50.0f)
- Is a “collider”
- Uses the
EnergyCatcher
:- Uses the
"Assets/Meshes/EnergyCatcher.gpmesh"
mesh - Has a collision component with size
(50.0f, 50.0f, 50.0f)
- Is a “collider”
- Uses the
Remember that actors which are colliders need a destructor that calls RemoveCollider
or when the actor is deleted, a pointer would still be in the collider vector which will cause a crash.
When playing the game, you should now see a door, energy launchers, and energy catcher. It will look like this:
The entry way has something that looks like a door, but it’s just a prop with no collision. The door you created should have collision, though.
Firing Pellets
The Pellet
class does not exist in the level file, but you also need to make an Actor
subclass for it:
- It needs a
MeshComponent
that uses the"Assets/Meshes/Sphere.gpmesh"
mesh with texture index 1 - Has a collision component with size
(25.0f, 25.0f, 25.0f)
- Is NOT a “collider” (so don’t add it to the collider vector)
- Will need an
OnUpdate
function as it will need to move around
The EnergyLauncher
should fire pellets periodically based on its cooldown. To fire a pellet, the EnergyLauncher
should create a new pellet actor 20 units in front of itself. The pellet should start out moving in the forward direction of EnergyLauncher
. For simplicity, you may assume that EnergyLauncher
s will only ever use GetForward()
for their forward direction.
After setting the position of the new pellet actor, make sure you call CalcWorldTransform()
on it. Otherwise, the pellet will render at the origin on the first frame.
Pellet
s should travel 500 units/s in their movement direction (although it starts out as the direction of the EnergyLauncher
that spawned it, the direction will change when teleporting through a portal).
If the Pellet
intersects with the player, it should be destroyed.
For its first 0.25 seconds of existence, Pellet
should not collide with colliders, but otherwise intersecting with a collider should also destroy the pellet. (You need this window or otherwise the pellet will instantly die due to the initial intersection with the EnergyLauncher
).
You should now see the energy launchers periodically firing pellets. The energy launcher closer to the entrance fires more quickly (a cooldown of 2s) while the ones further away fire at a cooldown of 2.5s. It will look like this:
Pellets Teleporting Through Portals
Pellets should also teleport through portals. To make sure this works properly, you should check for collision against portals before checking for collision against colliders.
As with player teleporting, the pellet can only teleport if there’s both a blue and orange portal. When the pellet teleports, you need to use GetPortalOutVector
to transform both the position of the pellet and the velocity vector of the pellet (remember when you should use a w of 0 vs. when you should use a w of 1).
Finally, for 0.25 seconds after teleporting, the pellet should ignore any collisions with portals or colliders. This includes ignoring any other collisions on the frame the teleport occurs. This is so the pellet doesn’t get stuck infinitely teleporting or die immediately after teleporting. It should still be able to collide with the player, however.
Confirm that pellets can teleport to the portals. Test putting an exit portal with different facings to ensure it’s working correctly. It will look like this:
Catching Pellets
When detecting collision against colliders, if the collider is an EnergyCatcher
and the energy catcher has not already activated, the energy catcher should “catch” the pellet. When a pellet is caught:
- The pellet should not die
- The pellet should be positioned to be 40 units in front of the energy catcher (
EnergyCatcher
does not use quaternions for rotation) - The pellet should no longer move
- The
EnergyCatcher
should become “activated”
Hint: Remember that you can use dynamic_cast
to figure out if an actor is a specific subclass.
Confirm that if you direct a pellet to the energy catcher with portals, it gets “caught” by it:
Opening Doors on Activation
Finally, make it so that when an EnergyCatcher
becomes activated it opens the door associated with it (if any). Then, also make it so EnergyLauncher
s no longer shoot pellets if the door they’re associated with (if any) is open.
To “open” a door, for now just remove the door from the collider vector (we’ll add a simple animation for this in the next lab).
Hint: You will need some way to track in Game
which std::string
is associated with which Door*
.
Confirm that initially, you can’t travel through the door. But if the energy catcher catches the pellet, you should be able to travel through the door and the corresponding energy launcher should stop firing pellets, like this:
Energy Glass and Energy Cubes
The energy glass is a special green glass that normal pellets cannot travel through. However, an energy cube is a special cube with a green ball in the center. If a pellet collides with an energy cube, the pellet won’t die, turns green, and then can travel through energy glass.
Add an EnergyGlass
class. It:
- Has a
MeshComponent
(pass intrue
for the second parameter as it needs transparency) - Uses the
"Assets/Meshes/Cube.gpmesh"
- Uses texture index 17
- Has a
CollisionComponent
with size(1.0f, 1.0f, 1.0f)
- Is a collider
Next, add an EnergyCube
class. It:
- Has a
MeshComponent
using the"Assets/Meshes/EnergyCube.gpmesh"
mesh (don’t passtrue
for the second parameter because there’s no alpha for it) - Has a
CollisionComponent
with size(25.0f, 25.0f, 25.0f)
- Is a collider
Add the code in LevelLoader.cpp to load these two actors. They don’t have any specials keys in the JSON file to handle.
Confirm you see two energy glasses (one in the gap and one after the gap) and an energy cube past the first gap:
Now implement the logic that tests if the collider the pellet is intersecting with is an EnergyCube
, in which case:
- It shouldn’t die (and continue going through)
- Turn green (set the mesh component
TextureIndex
to2
)
Similarly add logic for the pellet colliding with EnergyGlass
:
- If it’s green, it should go through the energy glass
- Otherwise, it should die
If you look at the energy launchers in/after the gap, you should notice that the first energy launcher shoots a pellet that stays the normal color (and can’t go through the energy glass), but the second energy launcher shoots a pellet that turns green when it goes through the energy cube, and then is able to go through the energy glass, like this:
Once you’ve pushed this code, you’re ready to move on to part 3.