Unreal Engine 5 RTS/Tycoon Camera Beginner Tutorial – How and Why

Difficulty: New Beginner IntermediateAdvanced ExpertProfessional
Dev-Platform: Windows
Unreal Version: 5.0.0 Early Access 2
Features: Top-Down-Camera
Movable with WASD
Movable with mouse on screen edges
Zoomable with Mousewheel
Rotatable with QE
Rotatable with mouse
Switch back and forth between First-Person-Camera and Top-Down-Camera
Assisting Video:

Table of Content

1 Preparation
1.1 Create Project
1.2 Base Blueprints
1.3 Project Settings
2 Implementation
2.1 Create Camera
2.2 Move Camera
2.2.1 With WASD
2.2.2. With mouse on screen edges
2.2.3. Frame Independence
2.3 Zoom Camera
2.4 Rotate Camera
2.4.1 With QE
2.4.2 Update Movement
2.4.3. With mouse
2.5 Switch between FPS and RTS Camera

1 Preparation

1.1 Create Project

If you do not have created a project already, open Unreal Engine and create a Top-Down-Template.

Creating a new project

If you used the Top-Down-Template, you have to remove the TopDownCharacter from the level. Select the TopDownCharacter in the top right corner and press DEL.

Background Knowledge: Otherwise it will not let our RTSCamera spawn later on, because the TopDownCharacter has “auto possess” set. This knowledge is not essential for this tutorial.

TopDownCharacter selected

1.2 Base Blueprints

We first have to create our own blueprints. Open the Content Drawer at the bottom left or press CTRL + SPACE.

Open Content Drawer

For a better overview create a new folder first. Use the “+ADD” button at the top left. Afterwards create a PlayerController Blueprint and a Pawn Blueprint and name them for example “RTSController” and “RTSCamera”.

Create Blueprint
Create Player Controller

Your folder should look like this, when you’re done.

Blueprints created

1.3 Project Settings

The PlayerController Blueprint is used to process player input, like keyboards, gamepads, etc. and perform actions in the game. There can only be one PlayerController Blueprint per Game(Mode) and we have to tell Unreal which one should be used. We want Unreal to take our new RTSController. Go to the top right Settings and select Project Settings.

Open Project Settings

Select Maps & Modes on the left side.

Select Maps & Modes

Change the controller of the Default GameMode to the RTSController, which we just created.

Set RTSController

There is another option, “Default Pawn Class”, as well. When the game/level starts, a instance/object of this Blueprint will be spawned for each player on the PlayerStart object. We want to spawn our camera, when the game starts, so we set it to RTSCamera.

Controller and Camera set

When you’re done, simple close the Project Settings window.

2 Implementation

2.1 Create Camera

Now open the RTSCamera Blueprint by double clicking it.

Open RTSCamera Blueprint

Hint: You can drag and drop the RTSCamera tab near the TopDownExampleMap tab to make it fullscreen.

On the top left is a list of all objects that the blueprint spawns, when an instance of it is spawned in the game. Currently there is only the invisible DefaultSceneRoot. Press “+ADD” to add a Spring Arm to the hierarchy.

Add Spring Arm

We will use the Spring Arm to adjust the camera distance. But first we add a Camera to the Spring Arm. Make sure you have selected the Spring Arm. The hierarchy is important, because if something moves or rotates everything below in the hierarchy also moves and rotates with it.

Add Camera

Your hierarchy should look like this, when you’re done.

RTSCamera hierarchy

Save and compile your blueprint in the top left corner.

Your game should be playable by now. Click on the green Play button in the top center and see what happens.

Current Game View

The RTSCamera spawns in the Game and you can see the level. You can press ESC to close the game. As you have probably noticed, this is not really a good RTSCamera, so let’s get a better view from above.

First select your Spring Arm and click on the Rotate icon on the top center.

Select Rotate Object

Click and drag the green arc to change the camera angle.

Rorate the Spring Arm to change the Camera angle

To zoom out a bit, we have to adjust the Spring Arm Target Arm Length and switch off the collision with level objects. Set the Target Arm Length to something which feels right for you.

Switch off collision with the level
Set Target Arm Length

Hint: When we have finished the WASD movement, you can activate “Do Collision Test” again and move around with the camera. You will see, why we deactivate it.

Save and compile and press Play again. It now should look much more like an RTSCamera.

View when starting game

2.2 Move Camera

2.2.1 With WASD

As we already have a good view, we will now make the camera movable to look around. Open the RTSController Blueprint from the Content Drawer in the bottom left.

When you open an empty Blueprint, it will only show the blueprint options. To be able to program something, click on the blue “Open Full Blueprint Editor” in the top center.

Open Full Blueprint Editor

It will automatically open the Event Graph for the Blueprint, where we can start to program our movement.

Blueprint Event Graph

Hint: You can hold down the right mouse button in the Event Graph to move around with the mouse. Use the mouse wheel to scroll out and in. Dragging left click is a box selection. Click and drag nodes around with left click.

To move our camera, we first have to know when the user presses WASD. The TopDownExample already comes with the WASD keys configured. If you are using another project, go to this section, where you can see how to add player controls.

Right click somewhere in the Event Graph and type “move forward” and click on the Move Forward event.

Add the MoveForward Event Node

Do the same with “move right”. You can select and drag around nodes with leftclick. It should look like this, when you’re done.

Added MoveForward and MoveRight Events

Background Knowledge: The red nodes you can see, are events. For example the “Event Begin Play” will be triggered, when the game starts (or a new instance/object of the blueprint spawns). It is triggered exactly once for each instance/object of the blueprint. For example, if we have 2 Players, each having a RTSCamera, the “Event Begin Play” of the RTSCamera will be triggered 2 times. Mind that each instance/object of the same Blueprint in the game uses separate data – they only share the same program but otherwise are independent of each other.
The “InputAxis MoveForward” event is executed each frame and whenever a player presses W or S the axis value changes from 0 to either 1 or -1. It only changes for the RTSController object of the player pressing and not for all players. If you use a controller with a stick, all values between 1 and -1 are possible, depending on how far you move the stick in one direction.

Now we can start to program the real action. If I start to program something new, I first start to think of what is the goal and what we need to achieve it. So our goal is: “Move the camera forward and backwards”. So obviously we need the camera object and we need a function to move the camera object. Right click on a free space, like we did before, and add the nodes “Get Controlled Pawn” and “SetActorLocation”. It should look like this.

Added nodes to get Camera and move it

Background Knowledge: Do you remember the project settings, where we set the Default Pawn to our RTSCamera? That is why we get the RTSCamera with “GetControlledPawn”, as it is spawned and automatically possessed/controlled on game start. Further, when we would not have deleted the TopDownCharacter, we would get the TopDownCharacter object with “Get Controlled Pawn”.

When programming with Blueprints, you need to know some basics. The white arrows show the order of execution and all the other colored circles, called pins, are data. Pins on the left side are inputs to the function/node and pins on the right side are outputs of the function/node.

We can connect the white arrows, as we want to execute the function “SetActorLocation” and we connect the output of the “Get Controlled Pawn” function with the target input of “SetActorLocation”, as we want to move the camera. When you’re done it should look like this.

Connecting nodes

Hint: If you have connected something by accident, you can ALT + leftclick on a pin or line to remove the connection.

As you may have noticed, there is a pin called “New Location” and that is where the object should be moved to in the 3D space. You can see which axis is which direction, when you go to the TopDownExampleMap and look at the bottom left corner.

World Axis (X, Y, Z)

Hint: You can hold down right-click in the level to control the editor camera. Look around with your mouse and use WASD to move and QE to move upwards and downwards.

So to know to where we should move our camera, we first need to know where the camera currently is. We already have the camera object and to get data from an object, we can just drag the pin into an empty space. It looks like this.

Create context sensitive node

For most of the cases, if there is a “Set …” function, there also is a “Get …” function. So we want to have “GetActorLocation”. The only missing part now is, that we have to add how far we want to move to the current location. Drag the yellow pin “Return Value” of the “GetActorLocation” node, type “+” to search for the “Add” function and click it. When you’re done it should look like this.

Add vector to location

Now we have to decide how far we want to move and on which axis. When you have placed the camera like I did, it is the X axis. Otherwise you can check the bottom left corner in the TopDownExampleMap, like stated earlier, which axis you need. How far is up to you and for now will depend on the FPS. We will make it frame independent later.

We have to multiply the Axis Value output of the MoveForward event with how far we want to move per frame. When the player presses W, the Axis Value is 1 and when the player presses S the Axis Value is -1. The result of the multiplication has to be set on the correct axis.

Drag out the Axis Value and search for “*” and select the Multiply node. From the Add node of the vector (yellow pin) drag out the left pin (input data) and select the Make Vector node. It should look like this.

Multiply axis value and make vector

Now you have to fill in a magic number, how far you want to move the camera – for me 25 feels good – and connect all the missing pins. I also multiplied the 25 with -1 or you can directly write -25, as the movement was inverted in my case. Instead you also could turn the RTSCamera by 180 degrees. But we will rewrite this anyway, when we get to the camera rotation.

Hint: You can add pins with the “Add pin” button on some nodes or with rightclicking on a pin. You can remove pins with right click and “Remove pin”.

When you’re done it should look like this and when you save, compile and press play, the camera should move by pressing W and S. You may have to click into the game window, so it gets the focus.

Finished WS movement

To make A and D working is easy now. Select all the nodes and copy/paste them with CTRL + C and CTRL + V.

Box selection
Copy/Paste the nodes

We only have to connect the missing pins and change the axis from X to Y. When you’re done it should look like this and WASD movement should work.

AD movement finished

What you should get used to from the beginning is, that when you have a similar code at 2 places, you should put it into a function. This is a general good advice when programming anything. In blueprints you can just mark all the nodes that you want to put into a function with CTRL + leftclick and press rightclick on a node and select “Collapse to Function”.

Collapse to function

Rename the function to something that tells what the function does. I named it “MoveCamera”.

Rename function

When you double click on the MoveCamera node, you jump into the function. So if you change something there, it changes everywhere, where the function is used. That’s the great advantage of using functions. You can go back to the Event Graph in the top, selecting its tab.

To use the function for the AD movement as well, simple copy/paste the function node and connect the pins to it. You then can delete the 4 old nodes. When you’re done it should look like this.

WASD Movement finished

Hint: Do you remember the “Do Collision Test” checkbox for our spring arm? Now you could set it again and test what it does. Try to move over and next to the walls and pillars. The spring arm will reduce the target arm length, if it would collide with a wall. This is good for 3rd person games, but not in our case.

2.2.2 With mouse on screen edges

Now we will do the camera movement with the mouse. As we start to program something new, we ask, what is our goal and what do we need to achieve it? Our goal is: “Move the camera, when the mouse is at the screen edge”. So we obviously need to know where the mouse is and where the edges are. As we have to check the mouse position all the time, we will use the EventTick node. The tick event is called every frame and gives us the duration of the last frame as output pin. We will get back to this later.

To start, build the following blueprint code with the nodes “Get Mouse Position on Viewport” and “Get Viewport Widget Geometry”. Get the local size of the Geometry and break all the 2D vectors to get the X and Y values. When you’re done it should look like this.

Begin with mouse camera movement

To show the cursor on the screen (by default mouse cursor is hidden) you have to tick the checkbox “Show Mouse Cursor” in the RTSController. Select the “RTSController (self)” on the left side and the checkbox on the right side.

Show Mouse Cursor

If you want to get a feeling about the mouse coordinates, I recommend to just print them on the screen. You can use the PrintString node and the Append node like this.

Print the x and y coordinates of the mouse

When you save, compile and play, you should see the coordinates of the mouse spamming out every frame. Try to move the mouse to 0/0 for example.

Printing mouse coordinates on screen

This is a great method to learn and also sometimes to debug your game. Keep in mind, that this is very expensive (expensive in regards to development means, that it slows down your game) and will not work in a shipped game. So you can not use this to show messages to your players ingame.

Alright, let’s continue with our camera movement. We now have to check, if the mouse is on an edge. We start with the left edge. As you have noticed the left edge has the X coordinate 0, so we have to check if the X coordinate of the mouse is smaller than, something. I will use the magic number of 50. To check this, we will use the Branch node and the “<” or “less” node. It should look like this.

Check if mouse is on the left edge

The Branch node takes in a condition (boolean value) and tests it. If the condition is true, the code continues with the “True” pin and otherwise with the “False” pin. We can define conditions with several nodes, in our case the “<” or “Less” node.

So when the X coordinate of the mouse is smaller than 50, the Branch will continue with the “True” pin. We use this pin now to move the camera, like we did with WASD. It should look like this.

Move the camera to the left

When you save, compile and play, the camera should move to the left, when you move to the edge with the mouse. If you have rotated the camera differently than me, you may have to use another axis. It is the same as for MoveRight.

Now we can do the same for the right side. We can use the “False” pin to check if the mouse is on the right edge, as it can not be on both edges at the same time. We have to check if the X coordinate of the mouse is greater than, a little bit less than the screen size. We already have the game screen size, so we subtract our magic number 50 from it and check if the mouse X is greater. It should look like this.

Move the camera to the right

As we already have a lot of magic numbers, we will do a small cleanup. We can make our magic numbers to variables and give them a name and a single point to change them. Simply drag out a pin and select “Promote to variable”.

Promote to variable

I named the magic number 50 to “CameraEdgeScrollThreshold”. You can connect the other pin with 50 to the variable as well. It should look like this.

CameraEdgeScrollThreshold variable

We can do the same with our camera scroll speed of 25.

Hint: You can use as many nodes of the same variable by simply dragging it from the left panel into the EventGraph. If you directly drag it on a pin, it will also automatically connect it.

CameraScrollSpeed variable for the mouse

Don’t forget to use the variable for the WASD movement as well.

CameraScrollSpeed variable for WASD

Now you can increase or decrease the camera speed on a single point. Click on the variable in the left panel and change the value on the right panel. You may have to compile first. Try it out!

Change value of variable

Now we can program the up/down movement. As we can not program it after the 2 branches, because they are conditional, we have to insert something before the branches. We will use the “Sequence” Node. It first moves along the first pin and when it reaches a dead end, will continue to execute the second pin and so on. This will ensure that moving the mouse in a corner will move the camera diagonal.

Inserted a sequence node

We start like we did with the mouse X coordinate. We use a Branch node and check if the Y coordinate is smaller than our threshold variable.

Check if Y is smaller than our threshold

When the condition is true, we move the camera.

Move the camera up

And do the same for the bottom edge.

Move the camera down – mouse movement finished

The camera should now be movable in all directions with the mouse.

As our blueprint code gets a bit overloaded we can use comment blocks to make it easier to grasp everything at the first glance. You can create a comment block, by selecting all nodes that you want to enclose and pressing C. You can also change the color of comment blocks on the right panel when selecting a comment (top bar of the comment block). So you could color everything that has to do with controlling the camara in the same color. As blueprints get more and more nodes this is necessary to be able to quickly tell which part does what.

Inserting comment blocks and change their color
2.2.3 Frame Independence

Our camera movement works, but it has a major flaw. It depends on the FPS (frames per second) of the computer running our game. If the computer is fast and runs the game with 120 FPS, it will move the camera much faster than a slow computer that runs the game with 30 FPS.

We can test this, by capping the FPS in the Unreal Engine editor. First let’s have a look how much FPS your editor currently has. In the bottom left you can enter commands for the editor. Enter “stat fps” to get a visualization of the FPS.

stat fps command

You can cap the FPS temporarly (until you close Unreal Engine) to for example 30 FPS with the command “t.MaxFPS 30”. The FPS on the top right should immediately drop to 30 FPS. If you want to cap the FPS in the editor permanently (for this project), you can go to the project settings (top right) and set “Use Fixed Frame Rate” in the General Settings (see left side).

Cap the FPS for the project

Now press Play and you will notice that the camera moves slower now. Leave your FPS setting lower as we are going to fix this now by making our camera movement frame independent.

Head back to our RTSController and have a look at the Event Tick node. As stated earlier it has one output pin and this pin gives us the duration of the last frame.

Event Tick – Delta Seconds

Things are easier to understand with small numbers. So imagine we have a slow computer, which runs the game with 2 FPS and a fast computer, which runs the game with 5 FPS. The Event Tick node is called 2 times on the slow computer and 5 times on the fast computer. So currently our code is called 2 times, which means the camera moves 2*25 units in my case on the slow computer and 5*25 units on the fast computer per second.

To fix this, we have to use the Delta Seconds output pin of the Event Tick. On the slow computer with 2 FPS the value is 0.5 and on the fast computer with 5 FPS the value is 0.2. You can do the quick maths 2*0.5 = 1 and 5*0.2 = 1 and a computer running the game with 60 FPS would have a value of 0.016666 because 60*0.016666 = 1. The output is the time that has passed since the last frame.

We now have to define how many units we want to move per second and multiply it with the Delta Seconds. For example: If we want to move 1000 units per second and the computer runs the game with 2 FPS, it has to move 500 units in the first frame and 500 units in the second frame (0.5*1000 = 500). For 5 FPS it is 200 units in each of the 5 frames (0.2*1000 = 200). For 60 FPS it is 16.6666 units in each of the 60 frames (0.016666*1000 = 16.66).

Take your time to understand this concept. It is a bit to chew if you have no number affinity. Read the last paragraphs again if necessary.

So in our blueprint we take the Delta Seconds and multiply it with our CameraScrollSpeed.

Delta Seconds * Camera Scroll Speed

We then use the result of the multiplication everywhere, where we used the CameraScrollSpeed variable before. You can delete the old variable nodes, when you’re done.

Replace the variable with the frame independent result

Last but not least, increase the CameraScrollSpeed and beware not to use WASD yet, as only the mouse movement is frame independent. Save, compile and test your game.

Change Camera Scroll Speed

To make the same changes for the WASD movement, we need to use the node GetWorldDeltaSeconds. It should look like this. You can delete the old variables nodes if you’re done.

Make WASD movement frame independent

2.3 Zoom Camera

Next we want to make our camera zoom in and out with the mouse wheel. To know when the player uses the mouse wheel we have to configure it first in the project settings. Head to the project settings (top right in TopDownExampleMap) and go to the Input section.

You can use the + symbol near the Action Mappings. Create 2 Actions “ZoomIn” and “ZoomOut”.

Configure ZoomIn and ZoomOut

Select the Mouse Wheel Up for ZoomIn and the Mouse Wheel Down for ZoomOut.

Set the Mouse Wheel Up and Down buttons

Now you can go back to our RTSController Blueprint and add the nodes “InputAction ZoomIn” and “InputAction ZoomOut”. It should look like this.

Insert ZoomIn and ZoomOut nodes

As we do not have an axis event the node looks a bit different. We could use an axis event, when we would use other keys or a stick, but the mouse wheel up and down can not be held down.

Background Knowledge: The event for an action mapping has 2 execution pins and one output pin. The execution pins are self-explanatory. The 2 pins are always executed both, when you press one of the configured keys. The only difference you can make is how much time passes between the “Pressed” and “Released” execution, when you hold the key down for a time. The blue key output pin is the key that is actually pressed. This is only useful, when you have configured more than 1 button that can be pressed for this event.

So our goal is to zoom the camera in and out. As our spring arm controls the distance of the camera we need the spring arm object first.

To get it, we will need to cast our controlled Pawn to the RTSCamera object. The process of casting means, in easy words, that you specify what a object is in more detail. For example you could say something is a toy, but in detail the toy could be a rubber duck. Casting is the process of telling Unreal “Im sure, that this toy is a rubber duck”. Do you remember, when we have created our RTSCamera Blueprint, we have selected Pawn in the creation process. We are telling Unreal now that our controlled pawn is a RTSCamera. To not have to cast all the time, we will do it once in the Event Begin Play and save our Spring Arm in a variable. When you’re done it should look like this.

Hint: Look at the next screenshots on how to get the correct nodes.

Get Spring Arm from the RTSCamera
Get Spring Arm Node
Promote Spring Arm to variable

Now we can jump back to our Zoom Events and use the spring arm variable there. As the code is very easy, here is how the solution should look like.

Camera Zoom

We can make some improvements here and create a new variable for the zoom speed. When you’re done it should look like this.

New variable CameraZoomSpeed

Further we can make a function “ZoomCamera”.

Create Zoom Function

The final result should look like this.

Camera Zoom finished

2.4 Rotate Camera

2.4.1 With QE

The camera rotation is a bit tricky, as we will have to update our camera movement code. But let’s start with the easy part, rotating the camera. We again start with the control mapping and set up the Q and E key.

Go to the project settings to the input section and add an axis mapping “RotateCamera”. Configure the key Q and E with scale 1 and -1.

Hint: You can press the button in front of the dropdown and press Q/E to quickly set them.

Axis Mapping RotateCamera

Now we can use the InputAxis RotateCamera and program the camera rotation. Use the node “AddActorWorldRotation” and try to program it on your own. When you’re done it should look like this.

Rotate Camera with QE finished
2.4.2 Update Movement

When you save, compile and play the game you can now rotate with Q and E. But you may have noticed that when you move while the camera is rotated, it does not move where we intend to move. This is because we move the camera on fixed world axis and not along the local axis of the RTSCamera. We have to update our movement code to use what is left, right, up and down from the perspective of the RTSCamera and not just X, -X, Y and -Y.

To visualize this a bit better, look at the following sketch.

World vs Local Space

So if the X axis would be the forward axis of the camera, when we have not rotated it, if we want to move forward now, we have to move along the local X axis. The difference between the world X axis and the local X axis is only the rotation of the object.

Thus to fix our issue we just have to rotate the movement vector the same amout as our RTSCamera is rotated. Now our MoveCamera function comes in handy. Go to the MoveCamera function and just add 2 nodes to rotate the input vector. We are now moving in the local space of the RTSCamera.

Update MoveCamera function

When you did everything exactly like I did, the camera movement will be inverted now, because we move the camera forward in the -X direction and the camera is currently facing in the X direction. You can see what is “forward” for the camera, when you open the RTSCamera Blueprint and head to the Viewport tab. Select the spring arm and the move icon (top center/right) and switch to world space with the icon a bit right of it. You can click it again to switch back and forth between local and world space. This is a great visualization of local vs world space.

Foward direction of the RTSCamera

To fix our invert problem, we could switch all the -1 multiplications in the blueprints or in the input settings (axis values) or we could rotate the camera 180 degrees. Latter is what I did. Select the spring arm and click on the rotate icon. Be sure to be in world space and rotate the spring arm 180 degrees by dragging the blue arc. If you did make a mistake you can undo your last step with CTRL + Z.

Switch rotation from local to world space
Rotate the spring arm by 180 degrees

Now as the movement is fixed you should be able to rotate and move your camera as intended.

2.4.3 With Mouse

As we will reuse the rotation code, we make all the nodes collapse into a function. I named the function RotateCameraLeftRight.

Collapse rotate left/right to a function

First we will do the left/right rotation (yaw) and afterwards we will do the up/down rotation (pitch). The controls should be, when the right mouse button is hold down, the mouse movement rotates the camera around. It will be an orbit camera that keeps the focus on the point, where our RTSCamera object currently is.

Go to the project settings to the input section and add the axis mappings RotateCameraLeftRight and RotateCameraUpDown. Set the RotateCameraLeftRight to Mouse X and RotateCameraUpDown to Mouse Y. When you’re done it should look like this.

Add controls for rotating with the mouse

When you have “Show Mouse Cursor” set to true in the RTSController, then the Mouse X and Mouse Y axis will only react when you hold down the left or right mouse button. As we only want to rotate the camera, when the right mouse button is down and not the left mouse button, we will check this with “Is Input Key Down”. As this already is everything, the result looks like this.

Rotate left/right with right click down

To do the up/down rotation we will copy our RotateCameraLeftRight function and change the rotation axis.

Duplicate rotation function
Change rotation axis

We have to change the GetControlledPawn to our Spring Arm and the AddActorWorldRotation to AddLocalRotation. When you’re done it should look like this.

Finished Rotate up/down function

The only missing part is, that we have to call the new function, when the mouse moves up/down while the right mouse button is held down. As this is an easy task again, the result looks like this.

Finished mouse rotation

Hint: You can play around a bit and see what happens if you use the GetControlledPawn with WorldRotation or LocalRotation in our function for a better understanding.

Our RTS camera is now fully functioning. We only have to fix some minor issue. For example, it is possible to rotate through the ground and look at the map from the bottom. To fix this, we have to limit the angle of the camera. When you have a look into the RTSCamera’s Viewport, you can see that 0 degrees is flat on the ground and -90 degrees is a perfect bird view.

Camera angle flat on the ground

So we have to limit the angle between 0 and -90. To limit the angle we have to know the current angle. We use the node “Get Relative Rotation” of the spring arm. With the Clamp node we can make sure, that a value is within a certain range. When we have the value in range we only have to rotate what is missing to get to the new rotation. The result should look like this.

Hint: You can check that the math is correct when you ignore the clamping. CurrentRotation + AddedRotation – CurrentRotation = AddedRotation. With clamping the formula is CurrentRotation + AddedRotation + ClampRotation – CurrentRotation = AddedRotation + ClampRotation. ClampRotation is 0 when the angle is already within the range and any positive or negative number that represents the exceeding value.

Limit the camera rotation angle

If you like you can change the angle limits to for example -75 and -15 and also promote them to variables.

2.5 Switch between FPS and RTS Camera

Depending on your game you may want to explore your world in first person. In this section we will implement a FPS Camera and the ability to switch between the 2 camera modes.

First we need a new blueprint for the FPSCamera. Open the Content Drawer (bottom left) and create a new Blueprint. I named it FPSCamera. It should look like this.

Create FPSCamera

Open the new Blueprint and go to the Viewport. Add a Camera component and move it up a bit. When you’re done it should look like this.

Add Camera component

Our Blueprint is finished, but we also need an object of it in the game. Head back to the RTSController and go to the BeginPlay event. When the game starts, our RTSCamera is spawned automatically, but we have to manually spawn our FPSCamera.

Add a SpawnActor node and set the transform to the RTSCamera transform. Additionally promote the FPSCamera and the RTSCamera to variables, as we will need them to switch between the modes. When you’re done it should look like this.

Background Knowledge: The transform of an object just is a collection of the location, rotation and scale of an object. You can see this, if you drag out any transform pin (orange) and select the Break/MakeTransform node.

Spawn FPSCamera

Next we need some key binding to switch between RTS and FPS mode. Go to the project settings to the input section and add an action mapping. I named it SwitchCameraMode and set it to T. When you’re done it should look like this.

Add SwitchCameraMode controls

Now we can use the SwitchCameraMode event in the RTSController. To be able to switch to the other mode, we have to know in which mode we currently are. We have to create a new boolean variable to save our current mode. Boolean variables only can be true or false (1 or 0) and we can use them as conditions (red pin in Branch node).

Create a new boolean (red) variable on the left side with the + button near Variables. I named the variable bCameraRTSMode. The b in front of it is an Unreal Engine convention which stands for boolean. It helps to distinguish the variables in C++ code, where there is no colorcode like in the Blueprints.

Create boolean variable and toggle it

We can now use the variable in the SwitchCameraMode event to branch between “go into FPS mode” and “go into RTS mode”. After we switched the mode, we have to make sure, that the variable has the correct value. We use a Sequence node like we did in the mouse movement and set the value of the variable to the inverted value with the NOT node. The NOT node makes true to false and false to true. You can see the result in the upper screenshot.

Be sure to compile the Blueprint and set the default value of the variable to true, as we start in the RTS mode by default. See the following screenshot.

Set default variable value

When bCameraRTSMode is true, we are currently in the RTS mode, which means, that we have to go to the FPS mode. To switch the camera modes we simply can use the Possess node. The result should look like this.

Background Knowledge: Every player controller can only possess a single pawn. The player will see what the camera of the possessed pawn sees by default.

Switch between RTS and FPS camera mode

If you want to switch on the place where you currently are, you have to set the location of the RTSCamera or FPSCamera object to the location of the other one. Otherwise you may jump a long distance to the other object (where you last have left the mode). The code for switching in place should look like this.

Switching the modes in the current location

If you save, compile and play you should be able to switch the modes with the T key. You also can move in the FPS mode a bit, but you may get errors when you close the game. This is, because we have not updated our movement code yet.

Our first step will be to put a Branch node everywhere in front of all RTSCamera movement. All controls should not do anything, if we are in the FPSCamera. Afterwards we will fill some False pins of the Branch nodes (like the WASD controls) and then we will add some new controls for the FPSCamera. The following screenshots show all places, where you have to insert a Branch node.

Branch the mouse movement
Branch the WASD movement
Branch the zoom
Branch the rotation

If you save, compile and play, you only can move the RTSCamera like usual but are not able to move the FPSCamera.

We can now start to program the FPSCamera movement and will start with looking around. For that open the project settings again and add the Axis Mappings TurnFPS and LookUpFPS. Set the TurnFPS to use the Mouse X with scale 1 and the LookUpFPS to Mouse Y with scale -1. When you’re done it should look like this.

Add FPS turn around controls

As stated earlier the Mouse X and Mouse Y axis only work when you hold down the left or right mouse button when “Show Mouse Cursor” is set to true. Therefor we will have to deactivate it when switching to the FPSCamera and activate it when switching back to the RTSCamera. The solution looks like this.

Enable/Disable Show Mouse Cursor

Now we can program the actual turning of the camera in the FPS mode. There are 2 nodes we simply can use, namely AddYawInput and AddPitchInput. The solution looks like this.

Turn around in FPS mode

Hint: If you have to click into the game again after switching to the FPSCamera for the first time, don’t worry, it is an Unreal Engine bug. I have already reported it.

You may notice that you can not look up or down. This is because the character Blueprint class can not be rotated in this direction (it is always upright). As the camera is a child component in the FPSCamera hierarchy it rotates with the character to the left/right. For the up/down rotation we have to tell the camera, that it should take the rotation that the character is ignoring. Go to the FPSCamera, select the Camera compontent on the left panel and set “Use Pawn Control Rotation” to true.

Set Use Pawn Control Rotation

Now we can program the WASD movement in the FPS mode. We will reuse the WASD controls of the RTSCamera. We simply have to use the False pin of the branches. To move a character we can use the node Add Movement Input.

Background Knowledge: The Add Movement Input node actually does use the CharacterMovement component in the FPSCamera, which is added by default to a character Blueprint. If you try Add Movement Input on our RTSCamera, it will not do anything. It will work, when you add a Floating Pawn Movement component to the RTSCamera. Why did we not use the Floating Pawn Movement component and Add Movement Input node for our RTSCamera? The Movement components use an acceleration, but usually you want that the camera reacts instantly and keeps a constant speed. If you would like to have acceleration for your RTSCamera, it is up to you to rewrite the movement to use the Movement component and Add Movement Input node. It actually makes the program much easier and after this tutorial you should be able to achieve it.

To know in which direction we want to move, we can simply take the Forward and Right vector of the FPSCamera. When you’re done it should look like this.

WASD movement for FPSCamera finished

Hint: You can double click on any line to get a little dot, which you can drag around to make things more clear.

The Scale Value pin should be connected to the Axis Value. The left side of the movement looks like this.

FPSCamera movement connections

Background Knowledge: As stated earlier the movement only works because of the Character Movement component. You may have noticed, that we do not use any movement speed variable. In fact the Character Movement component controls the movement speed. Go to the FPSCamera, select the Character Movement component and play around with the Max Walk Speed value. See the next screenshot.

Change Max Walk Speed

If you want to be able to jump in the FPS mode it is quite easy. Configure a jump event in the project settings (action mapping) and use the Jump node and Stop Jumping node in your RTSController. The solution looks like this.

Jump in FPS mode

If you have any questions, feel free to ask in the comments.

It’s always the right time, stay creative!

5 thoughts on “Unreal Engine 5 RTS/Tycoon Camera Beginner Tutorial – How and Why

  1. Thank you for your tutorial! It was really helpful. I found many solutions, but yours was the best in regard of quality and explanation. Good Luck with your Company. Greetings from Germany

    Like

Leave a comment