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

Theme: auto

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 the EnergyLauncher 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”
  • EnergyLauncher:
    • Uses the "Assets/Meshes/EnergyLauncher.gpmesh" mesh
    • Has a collision component with size (50.0f, 50.0f, 50.0f)
    • Is a “collider”
  • EnergyCatcher:
    • Uses the "Assets/Meshes/EnergyCatcher.gpmesh" mesh
    • Has a collision component with size (50.0f, 50.0f, 50.0f)
    • Is a “collider”

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: Door, EnergyLauncher, and EnergyCatcher created

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 EnergyLaunchers 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.

Pellets 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 EnergyLaunchers 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 in true 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 pass true 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: Energy Glass and Cubes

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 to 2)

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.