Working off of our basic framework, we’re going to create a camera that orbits around a focal point and is controlled by swiping motions on an iOS game. We’re going to learn a bit about how Mobile Input Zones are set up, how to deal with player input, and we’ll also be changing how the Tap To Move functionality works to fit into our orbit cam.
If you haven’t already gone through the Basic Framework tutorial, I would recommend reading that before going through this one. This tutorial assumes that you already have a custom GameInfo and PlayerController class set up. So with that, let’s begin!
The first thing we’re going to do is get the player’s camera into an orbit position, focusing at a point on the ground. We’re going to use Epic’s SimpleCourtyard map to test our code, so I’ve chosen a position 512 units above and 512 units away along the X axis to start.
CurrentCameraLocation and CurrentFocusLocation will hold the camera’s location and the point we want it to look at, we’ll be using the player input to alter these variables. Let’s compile the code and test it out! Open the editor and hit the Mobile Previewer button to start the game.
So far so good! The camera is above the ground and is pointing towards the focus point. We don’t have control of the camera, so let’s work on that next. This next step is going to involve a lot of code, but I’ll guide you through it so you know what I’m doing here.
The first variable we’re adding is CamDist. In PostBeginPlay I set it to the distance between the camera’s location and the focus location. Later on we’ll use it to make sure the camera stays the same distance away from the focus point. The GetPlayerViewPoint function doesn’t change much, just a VRot variable that we’ll use to figure out which way to move the camera. The real work for the orbit cam happens in PlayerTick.
The first thing we do in line 26 is to get the camera’s current location. The next two lines, at 30 and 34, move the camera according to the player’s input. aMouseX is a left-right swipe, and aMouseY is up-down. Saying “left” and “right” doesn’t mean much in a 3D environment, so we use the >> operator to orient the player input variables to VRot, which is the camera’s current rotation. That way we’re saying “left if we’re looking this way”. Make sense?
The next line is where we make sure the camera stays the same distance away from the focus location. We use the normal operator to get a unit vector, that is, a line that is exactly one unit in length. Then we multiply that by CamDist to move the camera to the distance it’s supposed to be from the focus location. Finally, on line 40, since the focus location will move when we get into the tap functionality, we need to move the camera to center on any new focus location.
With that code compiled, let’s test it out!
One thing you’ll notice pretty quickly is that the camera can go under the ground, and when you move up as far as it will go it spins out of control. We need to add code to limit the camera’s up-down movement. To do this we’ll create two variables to hold the upper and lower limit:
We’ll use 32 as the lower limit to keep the camera from going into the ground. As for the upper limit, if we use Pythagoras’ Theorem on our default CurrentCameraLocation we get about 724 for the camera’s distance. We’ll put the upper limit a little below that at 700. To see why we’re doing this, an unnecessarily complicated pic:
Setting the MaxGroundDist to 700 will prevent the camera from swinging up all the way to the top and spinning out of control, so let’s set both of them in the defaults.
Now for the code that will make all this work.
We’ve made some changes to this function. Instead of applying all the changes to NewCamLoc, we add a new variable called ZTest and make the changes to that. This way we can test if the new location will be in range or not. We also make a variable called CamHeight, and compare that to MinGroundDist and MaxGroundDist. If the ZTest variable ends up above or below these limits, we only apply the left-right player input to NewCamLoc. If ZTest is in range, we go ahead and set NewCamLoc to ZTest.
Let’s compile and test it out! Trying to move the camera below the ground or all the way up no longer works, so we’re good to go! Now, if only we could move the focus point so we’re not pointing at the same location all the time. Time for more code!
We don’t want the camera to snap to the new focus location, we’d rather have a smooth movement towards it. So instead of changing CurrentFocusLocation directly, we’re going to add two new variables to control the movement.
DesiredFocusLocation will be the location we tapped on the screen, and we’ll move CurrentFocusLocation towards it. To make sure it doesn’t move too fast, we’ll add a TapToMoveSmoothFactor and set it in the default properties in a bit. Now, when we touch the screen we’re interacting with a MobileInputZone, which we’ll talk about towards the end of this tutorial. But for now all we need to know is the one we’re swiping and tapping on to move the camera is called the FreeLookZone. By default it doesn’t have a tap function set, so let’s do that now:
Now when we tap on the screen, it will call the TapToMoveTap function, which we’re about to write.
In the function the first thing we do is get the size of the screen and find the percentage coordinates of where we tapped. The Deproject function turns these 2D coordinates into 3D world coordinates. Then we trace in that direction to see if we hit anything. If we do, the location that we hit will be the DesiredFocusLocation. Now that we have that, we need to move the focus and the camera towards it. We’ll make more changes to the PlayerTick function to do this.
In our updates to this function, we set NewFocusLoc to the CurrentFocusLocation, then move it a percentage along the line to the DesiredFocusLoc by multiplying it by our TapToMoveSmoothFactor. In order to keep the camera in the same relative location over our focus location, we change the NewCamLoc parts of the function to use NewFocusLoc instead of CurrentFocusLoc. Lastly, we save the CurrentFocusLocation at the end of the function. Since we’re already setting the view rotation to that CurrentFocusLocation in GetPlayerViewPoint, we don’t need to change that function any. Finally, we will set our TapToMoveSmoothFactor in our default properties.
Now with that compiled, we can tap on the screen and the camera will move towards the new focus location smoothly. We’re almost done!
We talked a bit about MobileInputZones earlier, and now we’re going to clean up our interface a bit by looking at how they work. Since we’re using swipes and taps on the screen, we don’t need the two thumbsticks on the HUD. We could use our HUD class to hide them, but we’ll do it the correct way by making our own mobile input group. To do this we’ll open MobileGame\Config\DefaultGame.ini and add our own section below the [MobileGame.CastleGame] section:
We can specify as many RequiredMobileInputConfigs as we want for our own GameInfo class, these are used to tell the game what zones we want to use for each group. In this case, since we only want the swipe and tap zone that covers the entire screen, we only need the UberLookZone. If you look at the UberGroup for MobileGame.MobileGame you can see that it also has the UberStickMoveZone and UberStickLookZone, which are the input zones used for the thumbsticks. Since we took those out of our group they won’t show up anymore, and you can save the file and go in game to see that they are gone.
Further down the ini file we can see where the UberLookZone is defined.
The X, Y, SizeX and SizeY variables show that this zone covers the entire screen, and you can also see the MouseY and MouseX inputs set which we used in our PlayerTick function to move the camera. You can see the other types of zones specified in this ini as well, and if you wanted to make a custom one this is where you would put it.
By default the first input group is active, to change it we would simply call MobilePlayerInput’s ActivateInputGroup function from our PlayerControllerClass like this:
Remember to change the World Info properties in any test map you make before you send it to your iOS device, see the Creating a Framework for a Basic iOS Game tutorial for more about that.
That’s it for this tutorial! I hope you learned a bit about the PlayerController class as well as MobileInputZones. Knowing how to use these is important to making a custom iOS game. If you’d like a challenge that will test your knowledge of both of these classes, try altering the AwesomeMobilePC to include a thumbstick that zooms the camera in and out!
Thanks for reading!