So in the last lesson, we learned about planes and anchors and implemented this delegate method to be 1
able to detect horizontal planes in the real world. 2
Now, in this lesson, I want to look at how we can start detecting touches on the screen and interpret it 3
as locations in the real world. 4
So to do that, I'm going to use a delegate method called touchesBegan and this gets called when a touch 5
is detected in the view or in the window. 6
So in here is where we're going to be receiving those touches that are coming from the user and use 7
ARKit to convert it into a real world location. 8
So the first thing we need to do is to check if there indeed were touches detected and this method wasn't 9
just called in error. 10
So to do that, we're going to use a "if let." 11
And we're going to call our object touch and it's going to be set to equal touches.first. 12
Now, if you option-click on touchesBegan, you can see that touches is actually a set of UI touch instances, 13
but they only have more than one object when you're using multi-touch. And to do that, you need to enable 14
multi-touch. But in our case, because that's not enabled and we're not interested in detecting multiple 15
touches, 16
we only want the first object in that set which is the location that the user touched on the screen. 17
So if this touches.first does indeed contain an object, then we're going to sign it to touch and 18
we're going to be using it in order to detect its location. 19
So let's create another constant code touchLocation and set it to the touch that we--the UITouch that 20
we got from earlier on, .location, and the "in" is where that location was detected. And you can see that 21
the location is expecting a node that is a descendant of a scene present in the window that receive 22
the touch event. 23
So this is going to be our sceneView because that is where our touch event was initiated. 24
All right. 25
So once we've got the touch location remember that this is a 2D coordinate because your iPhone or your 26
iPod screen is 2D. 27
You can't actually push through the iPad and touch a place in 3D. 28
So in order to convert that touch location into a 3D location inside our scene, we're going to use a 29
method that is from ARKit called hitTest. 30
And I'm going to show you how it works. 31
So we're going to call the results, results, and it's going to be created by calling one of the 32
sceneView methods called hitTest. And hitTest searches for real world objects or ARAnchors which is true 33
in our case because we're looking for planeAnchors that is in the captured camera image corresponding 34
to a point in the SceneKit view. 35
So, basically, we're converting a point that we're touching in 2D space on the screen into a 3D coordinate 36
that corresponds to one of our ARPlaneAnchors. And the hitTest method that we want 37
is this one where it expects a point that's going to be our touchLocation and it's also expecting a 38
type which is the type of result we're looking for. 39
So the point that we're going to run out hitTest on is going to be touchLocation. And the type is going 40
to be .existingPlanes using extent, and this is a planeAnchor that's already in the scene because 41
we put it on in this delegate method and it's respecting the plane's limited size. 42
And now, I just want to briefly explain how this hitTest works. 43
So let's say that you've got your app running and you tap a point on your screen. Now, that tap is interpreted 44
as a touchLocation and that will trigger the touchesBegan method, 45
and we're going to look for the location of that touch. Now that touchLocation is a point in 2D space. 46
It has a x and a y component on the iPhone or on the iPad screen. 47
Now, what we want, though, is we want to convert that 2D location and we want to let it traverse through 48
the camera image and hit a point in 3D space. 49
So a place on our plane that we've already added to the scene. 50
So, now that point that the hitTest has detected within the scene has a third positional component, 51
the z component. So it is now a position in 3D space. 52
And this is the point that we're going to be placing our dice. 53
So depending on the z component, your dice is going to be rendered larger or smaller. 54
So if the z was closer to you, then your dice would get rendered larger. 55
And if the z was further away, then it would be scaled down smaller. 56
So it's being placed in our 3D plane based on our real horizontal plane that was detected. 57
Now, if you're interested in finding out more about how ARHitTest works, then have a look in the 58
class documentation on Apple.com and you can read more about what are the different types of hitTests 59
and what are the parameters for this particular method that we're using, and how it works behind 60
the scenes. 61
Now, once we've gotten our result back, I want to be able to print to the console and, say, if the result 62
is empty, i.e., we didn't get one, then that means that our hit or our touch probably didn't hit one of our 63
existing planes. 64
So I'm going to say you touched somewhere else. 65
But if it was not empty, i.e., we did get a result back, then I'm going to print that you touched a point 66
on the plane. 67
So let's say if results.isEmpty, and we're using "isEmpty" because results is an array type. 68
So I'm going to put the exclamation mark in front of 69
!results.isEmpty to reverse it, 70
so we're now checking to see if results is not empty. 71
And in that case, that means we did get a result back from our hitTest and it did find a position on 72
an existing plane. 73
So we're going to print "touched the plane," but otherwise, our touchesBegan was triggered. 74
So the user did touch somewhere on the screen, just not on an existing plane, 75
then we're going to print "touched somewhere else." 76
All right, let's try that. 77
So, as you can see, when I touched the plane that is level with the desk, it says, "touch the plane." 78
And if I touch somewhere else, like, say, this slightly more elevated box that's wrapped in a pink shirt, 79
"touched somewhere else," and it works even if I move the camera somewhere else, and the original plane 80
is out of the view.