Zoom & Rotate/3D to 2D Camera Volume | Unreal Engine 5.6 Tutorial

 

Introduction - 

One of the core mechanics for an upcoming game I'm working on is seamlessly swapping between 3D and 2D. This includes not just rotating the camera but also locking the players movement so that it is only on one axis, so for the fun of it I thought I'd share out how I did it.

For the tutorial I will be breaking it down into two parts, Part 1: Zoom & Rotate Volume and Part 2: 2D to 2D Camera Volume. I decided to break these into two parts for clarity since Part 1 can stand on its own.


Final Product

Prerequisites - 

One important note is our character camera is locked meaning the player has no control over it. While Part 1 might still apply to you Part 2 might not. Other than that, have a working character of some sort set up with a functioning spring arm and camera.


Now that we got the introduction out of the way lets start....


Part 1 - Zoom & Rotate Volume

Goal 

To give a brief summary of what we're going to want to accomplish....
we want to create a volume that when the player enters their camera zoom/rotation, or both are changed.

Zoom
Zoom + Rotate


1. Creating the Camera Volume Actor 

  1. Right click in the content draw and click "Blueprint Class".
  2. Click "Actor".
  3. Name the actor anything you want. I'm going to name mine "CameraVolume". 

2. Creating the Volume - 

Before we start adding logic, we need some sort of collision box so that our player has something to hit. To do this....
  1. Open up our newly created box and go into the viewport.
  2. Click "Add" at the top left and search for "Box Collision". I'm going to leave mine with the default name of "Box"


3. Creating the Logic

1.Saving our player as a reference + Creating variables

Starting off it's important to save a copy of our player character. We do this because we are going to be constantly accessing them and instead of trying to constantly fetch them it's easier to save them immediately.
  1. If not there create an "Event Begin Play" event.
  2. Create a "Cast to " + your character name and then for the object use "Get Player Pawn".

  3. Right click the output and click "Promote to Variable". For this tutorial it will be called "GeriRef" however name this however you want it too and I'll be referring it to as player reference.


  4. In the bottom left add two variables. Call one "Rotate?" set this to a Boolean, and add another called "ZoomDist" and set this to a float. Click the eye to the right of both of them so its open. This will allow us to edit the value in the world.

2.Creating Zoom

Making the zoom isn't complicated but can take some time to set up. To make life easier lets create and event that will do this so we can call it whenever.




  1. Create a new event by adding "Custom Event"


  2. after this connect a "Flip Flop" node to our new "ZoomOut" event

  3. Drag out from "A" and create a new timeline. Name this whatever you'd like im calling it "ZoomOut/ZoomIn". Also from "B" drag this into "Reverse" this will reset the camera once were finished.

  4. Open up the timeline by double clicking it and add a "float track" lets name it "ZoomDistance". Before adding any keyframes you'll notice the "Length" section up top. Adjusting this will give make your zoom faster or slower.



  5. Now that we've added the float track and adjusted the length lets add our keyframes. To do this right click on the timeline and press "Add key to Curvefloat" twice. Change the first one to "Time" = 0 and "Value" = 0. Change the second one's "Time" to the value of "Length" and set the "Value" to -1. We're setting the value to negative so that the camera zooms out by default, so for example if you wanted a zoom value of 400 to zoom the camera in, set "Value" to 1. Compare that to mine a "ZoomDist" of 400 would zoom out by 400. Of course, you could just negate the value to get the inverse effect meaning this is just personal preference. *"Value" == -1 "ZoomDist" == -400 you'd zoom in by 400 and vice versa.




  6. With the timeline being completed let's head back to our event graph. Once there drag out from the "Zoom Distance" pin or whatever you called your float track. From there let's add a "Lerp" to our graph.

  7. You're probably going to have to disconnect this as I believe it always goes to the "A" pin, so disconnect that and drag it into the "Alpha" pin. From there though let's drag in our get ZoomDist and plug that into "A" on the lerp.

  8. Here's where things might get complicated but drag out your player reference, drag out from that and search for "Get SpringArm". From there drag out from "Spring Arm" to "Set Target Arm Length". Now that everything is here it's just time for cleanup. From the timeline drag "Update" to the "Set Target Arm Length" we just created. and finally, from the lerp connect the return value to the "Target Arm Length", and just like that you're done.






    Final Product


3.Creating Rotate - 

You may not have known this but you've basically created the rotate already. The rotate shares basically identical code with some minor differences, so if you’ve skipped the zoom look above this heading to copy the code. 

  1. To start off let's create a new custom event and call it "Rotate".


  2. From there let's copy every bit of code except the timeline, lerp, ZoomDist and set target arm length. It should look something like this.

  3. Once that's complete let's create a timeline in the same spot as before and let's call this "RotateIn/Out". Like before connect "A" from the flipflop to start and "B" to reverse.

  4. With the timeline being made let's open like before and add another float track. Let's call it "RotateSpeed".

  5. We can copy a lot of the code from before. While you can change the length, I recommend having a "Length" of 1 as anything higher can cause problems when exiting. With the "Value" we need to put the new rotation value. For this tutorial I'm doing -90 but you could put whatever you wanted. 

  6. Let's close out of that and now from "RotateSpeed" drag out to "Make Rotator". From there I recommend connecting the "RotateSpeed" to the Z pin. This will rotate the camera along that axis and this gets the 3D to 2D effect. Although if you wanted you could plug that value into the X or Y to get varied results.

  7. If you copied the code from before, drag out from the spring arm component and get a "set relative rotation". From there plug the return value from the rotator into our new rotation and the update into the new node.



4. Collision + Triggering the events

Now that the hard work is done its time to tie everything together. For this were going to add some collisions events to that box we created earlier. 
  1. Starting off create both an "On Component Begin" and "On Component End Overlap box" event. To do this click your collision box and in the properties, section scroll all the way to the bottom and click the plus on both the events mentioned previously. If you don't see these options, make sure you have "Generate Overlap Events" is turned on.




  2. Both these events will have identical collision logic so make sure to put this on both of them. Drag out from "Other Comp" and get a "==".


  3. From there get your player reference and get the player capsule using it. Connect the player capsule to the bottom part of the "==".

  4. Drag out from the return value (red circle on the right) and get a branch. If you haven't already do the previous steps on the other overlap event exactly as presented before.

  5. Right click in the graph and create a "Sequence". From there connect both branch events "True" to the newly created sequence.

  6. From "Then 0" lets create another branch. This will allow to check if we should zoom out/in.

  7. With the branch let's make the condition to see if "ZoomDist" != 0, so drag out a "Get ZoomDist" and a "!=". Put 0 in the "!=" condition and connect it to the branch.

  8. Once that's done from the true let's call the "Zoom" event.

  9. With the zoom done its time to move onto the rotate, so drag out from "Then 1" (if its not there hit "add pin") and add another branch.
    Reroute node added for neatness

  10. This branch is simple and all we want to check is "Rotate?" so, drag the get rotate node into the condition, and from there similar to before drag out form true and call "Rotate".

  11. When done this is what your code should look like...

5.Final Steps

Now that we've finished this let's test it in game, so let's add the volume into the world and set it up. Once dragged into the world click on it and under the "General" tab you'll see a "Default" section. This is where you set how far you want it to zoon or if you want to rotate your camera.



If you wanted to make the volume bigger it's as simple as scaling the volume to however big you want it. Note that if you're planning on putting a texture on this volume scaling MAY not the best option but there are plenty of resources online for that.

Part 2 - Creating the 3D to 2D gameplay

You might be saying "what is the point of this section?" and to an extent you might be right however while we did rotate the camera -90 degrees one problem still remains... the controls. Even though you are rotating the camera "W" would still be your forward movement and you may want that it could be confusing for some players. In this section were going to make it so that the player can go forward with D and back with A. This shouldn't take long but this entire section hinges on the fact you did part 1 so if you haven't, please go back and do so. One thing to note is a lot of this design piggie backs off the third person template. With that being said you can follow along if you want but it may not work for you.

Creating 2D Input Action and Mapping Context -

    1. To create a new action, you must right click and search for "Input action" when selected name it. I'm going to be naming mine "IA_Move2D".

    2. Once created open it up and change the "Value Type" to "Axis 1D(float)". This will lock movement to 1 axis.

    3. After that lets duplicate the default mapping context. You could make another one however this saves a lot of time. If you used any preset the path should look like "content"->"input".

    4. Name this anything you want and open it up I'm calling it "IMC_2D". From there swap the move action to the new "IA_Move2D" action.


    5. Add the key binds you want to the action by pressing the plus button next to the action. It's important to note for action where you move backward make sure you have "negate" as a modifier. Modifiers can be seen be hitting the dropdown on an input. For this tutorial A will be left blank while A will be marked as "negate". If you're interested in adding controller support, I recommend "Gamepad Left Thmbstick 2D-Axis" and for your modifiers "Deadzone" and "Scalar".

Swapping Input Actions

1. With our newly created mapping context we need a way to assign it. to do that open up the player controller class. If you used a preset, it should be at "content" -> *template name -> "blueprints". Once found open it up. 

2. Create a new custom event and name it whatever you want. I'm calling it "3DTo2D"
From there create a "Flipflop" node.


3. With that node created drag form "A" and create a "Remove Mapping Context". To find this you'll have to turn off "Context Sensitive" in the top right.



4. The target for that will require you to use the "Get EnhancedInputLocalPlayerSubsystem", so once you've got that drag it into the target. from there under "mapping context" select your default mapping context. This will remove the current one selected.



5. One done drag out to add a new node and pull in "Add Mapping Context". The target is going to be the exact same as before, but we need to change the mapping context to our new one ("IMC_2D"). Along with that change "Priority" to 1.



6. Repeat these steps for B except flip flop the mapping contexts. Ie. you remove "IMC_2D" and add the default (mine is "IMC_Default").



Changing the player class

Now that we created the mapping context we have to change the player class around a bit. We need to do this for two reasons. One we need to make it so the input action IA_Move2D actually can move, and two we need someone to call the newly made "3DTo2D" event.

1. To start off let's create the movement so in the player class. To do this were basically going to copy the template code and make some minor changes. Start off by creating a new function and let's call it "Move2D".


2. Before creating any code, we need to create an input value for this function so clicks on the Move2D node and hit "Add input". Make it a float and call it "Y value".


3. Add a "Add Movement Input" node. 


4. Right click on the screen and add a "Get Control Rotation node and a "Get Forward Vector" node.


5. connect the "Z" value of the control rotation node the "Z" value in the forward vector node. Connect the return value to the world direction pin in the add movement input. Finally connect the "Y value" input pin to the "Scale Value" pin.


6. With that completed close out of the function and add the "IA_Move2D" event.



7. Connect the event to your newly made "Move2D" function and plug the "Action Value" into the "Y Value". With that your character can now move only on the X axis when the mapping context is set.


Now all we have to do is call the event to swap the controllers; however, we need the controller class to do this. To get this let's store a reference of it when we start the game.

8. Out of a event "Begin Play Event" get a "Get Actor of Class" node and in the "Actor of class" pin select your controller. Mine is "BP_ThirdPersonController".


9. Now right click the return value and hit promote to variable. I'm going to call mine "Geri Controller" however name yours anything you want. I'm going to be referring to it as player controller.



10. With the controller stored let's create a function to call our controller swap. Create another function and call it "SwitchController" 


11. Get your controller reference and from the pin get our "3DTo2D" event.


Now our character class is done and all we need to do is call the event when rotating so let's change the "CameraVolume".

Changing camera volume 

To wrap thing up we need to make some quick changes to the camera volume class. This shouldn't take long so I'm going to condense it into one step

1. In the camera volume class go to our reverse event. From there get your player reference and drag out to our "SwitchController" function. Once you have that put that in both before the start and reverse of the rotate timeline, and with that you're done. Now whenever you rotate the camera with this volume it locks your controls to one axis and swaps it back when exiting it.



Conclusion 

This concludes the tutorial as now you should have a fully functional 3D to 2D volume. Hope this helps and have a great day!!