I’m currently developing a prototype for a top down strategy game for Android which I hope will see the light of day sometime realtively soon. In it, I wanted to implement a simple “touch-and-drag” camera where the player can simply drag a finger across the screen to move the camera across the in-game world, just like in most top down mobile strategy games. Almost every problem seems simple enough until you actually approach it, and this particular problem is no exception. After googling a bit, surprisingly little information where to be found on the subject. But after taking bits and pieces of other people’s (incomplete) solutions and adding some ideas of my own, I managed to get it working just as I wanted to. Since the specific information I myself wanted cannot, at this time, be found on the web, I decided to write my own tutorial. My specific solution is written entirely in C++, but I’ve rewritten it entirely in Blueprints as well to be able to show you both versions. Although these systems are made specifically for touch devices, the same principles can be applied when working with a mouse e.g. This solution only registers drag movement for the first finger that is pushed upon the screen, but could be modified further to support some kind of multi-touch, if that’s what the game requires. This tutorial was created in Unreal Engine 4.14.0.

Blueprint version

First of all, in your Blueprint, create two new variables of “Vector 2D” type, and name name something useful (I named mine “Previous Touch Location” and “New Touch Location”). We will use these to store the touch location from every tick (or frame). Then if a finger is touching the screen we will compare the touch location from the previous tick with the new location. Now, right click in your Blueprint and create a “Touch 1” node. So now, everytime the player touches the screen, we will first get the player controller, and then from that, get the “Input Touch State” node to store a touch location in our “Previous Touch Location” variable. Use a “Make Vector 2D” node to store the touch X and Y locations in the variable. Following these steps, your Blueprint should look something like this:

Then, on every tick we will repeat this process. First, get the player controller and hook it up to “Get Input Touch State”. Drag the “Is Currently Pressed” value to a branch. In doing this, we will only proceed with further calculations if a finger is actually touching the screen. If the player is indeed touching the screen this specific tick, we will use the new location coordinates to store in our “New Touch Location” variable. Now we need to get the delta vector from the two vectors (the difference in the two locations), so subtract “Previous Touch Location” from “New Touch Location”. Depending on your camera setup in the level, you might need to invert either the X or the Y axis. My specific setup requires me to invert the X axis, so I simply multiply that float with -1. Now hook these two values into a “Make Vector” node to convert these into a 3D vector. The X axis is the horizontal axis, and the Y axis is the vertical axis, so plug these into whatever you want to these axes to be. In my setup, I want to move the camera in the X and the Z axis, so that’s what I plug them into. And finally, take this vector and plug it into an “Add Actor World Offset” node to move the camera. After this, we must not forget to update our “Previous Touch Location” variable – Just plug the value of “New Touch Location” in there, and we’re good. The finished tick portion of the blueprint should look just like this:

And that’s it! Worth mentioning, when trying this out on a computer and not an actual mobile device, you probably need to enable touch events. Just drag off from a “Get Player Controller” node and choose “Set Enable Touch Events”, set it to true and hook it up to an “Event Begin Play” node, so it enables it at the very start of the level. You might also want to set “Enable Show Cursor” to true as well, for easier playtesting.

C++

The C++ version follows the same basic principles as the Blueprint version, so I’ll just go over these in a real quick manner.

First of all, create our two variables, “previousTouchLocation” and “newTouchLocation”, in the class header. These are of “FVector2D” type. We will also create a variable to store the reference to the player controller, so we don’t need to manually get the reference everytime we need it (which is, as we saw in the blueprint version, very often). This is of “APlayerController*” type. Note that it’s a pointer to a player controller, so don’t forget that star! Go ahead and fill this reference up right away in your “BeginPlay()” function by writing:

playerController = UGameplayStatics::GetPlayerController(this, 0);

Secondly, we need to create an “OnTouchBegin” function that is called everytime the screen is touched. To be able to bind this correctly it needs to take two arguments of type “ETouchType::Type” and “FVector”. The function header should look likes this:

void AUI::OnTouchBegin(ETouchIndex::Type touchType, FVector newTouchLocation);

Of course the names of the arguments are optional, but name them something useful. In this function, we will do essentially the same as in the Blueprint version, so the function body looks like this:

Since this function takes references as arguments, the variables need to already be declared, so we need to create a bool variable to plug in the last argument slot, even if we don’t need it.

Now we need to bind this function. Every pawn class comes default with a prewritten “SetupPlayerInputComponent” function, so just add this line there:

InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AUI::OnTouchBegin);

And that’s everything for the “On Touch Begin” function. The tick function is fairly straightforward as well. Create a bool variable, name it something useful (e.g. “bIsCurrentlyPressed”) and plug that and the “newTouchLocation” into the “GetInputTouchState()” function that we get from the “playerController”. Then we just need an if statement to test “bIsCurrentlyPressed” to see if we should move along further.

If a finger is currently pressed against the screen, the rest of the function is very straightforward. Create a variable of “FVector2D” type and store the delta vector in there by subtracting “previousTouchLocation” from “newTouchLocation”. Negate either the X or Y axis if needed. Create an “FVector” to store the actor offset in 3D space, and plug that into the “AddActorWorldOffset()” function. Lastly, update the “previousTouchLocation” variable with the value from “newTouchLocation”. The finished tick function should look something like this:

And that’s it for the C++ version! And again, don’t forget to enable touch events and show mouse cursor, as that might cause a problem otherwise.

Worth mentioning is that during my own research, there were a great deal of people that instead wanted to use the “Get Hit Result Under Finger by Channel” node to get the coordinates for the function. Although you could certainly get it working with that approach, I instead chose to get the screen coordinates for the simple reason that they are constant and does not change during gameplay. Since the “Get Hit Result Under Finger by Channel” node returns the world coordinates in 3D space, the distance and scale between the two vectors we are comparing between each tick would change if we were to, say, implement a “drag-and-zoom” system. Then we would get into multiplying the vectors depending on zoom levels and fine-tweaking those to work fine and I didn’t want any of that. So I chose this route instead.

That’s my solution to the problem, and it works just as I’d like. Of course yours might differ, but at the very least I hope this will help you along the way if you are, just as I a couple of days ago, struggling to get it to work!