This Saturday, I’m speaking at Tampa Code Camp 2017, a free community event run by developers for developers. My topic will be ARKit, the framework for augmented reality programming for the iPhone and iPad.
Among the topics I’ll be covering in my presentation will be the ARKit equivalent of “Hello World”…
…a simple iPhone version of the 3D painting program Tilt Brush…
…a game where you have to poke the creepy floating eyeballs coming at you…
I gave a talk at BarCamp Tampa Bay 2017 titled Programming Games in (Mostly) Plain English. I my talk, I presented the audience with a couple of tools that would allow them to build interactive fiction or “Choose Your Own Adventure” games with minimal programming or a programming language that looks a lot like plain English.
One of the tools that I showed the audience was Twine, a tool whose developers describe it as “an open-source tool for telling interactive, nonlinear stories.” You can use it to create “Choose Your Own Adventure”-style games without any programming. If you’re willing and able to do some programming — and it’s nothing terribly fancy or complex — you can throw in some additional sophistication to your Twine-based interactive creations.
In this article, I’ll walk you through the Twine “story” — that’s what the interactive stories or games that you create with Twine are called — that I presented at BarCamp Tampa Bay. You can follow along and try out Twine either by downloading the MacOS, Windows, or Linux desktop versions, or by using the online version (which is pretty close to the desktop versions).
An Aunt’s Story is a simple “choose your own adventure” tale starring an oft-overlooked character from a film that you may or may have not heard of. She lived on a desert planet a long time ago in a galaxy far, far away with two characters that I’ll call Grumpy Husband and Whiny Nephew, and she was plotted to free herself and live a better life. This story is told from her point of view.
The adventure begins
Let’s start by creating a new story. Click the + Story button on Twine’s home screen:
You’ll be asked to give the story a name. Enter An Aunt’s Story:
After you click the Add button, you’ll be taken to Twine’s storyboard, which shows a single passage, which represents a “page” in a story:
It has the default title of Untitled Passage. The icon beside the title marks the passage as the one that the story will begin with.
Let’s try editing the passage. Double-click on the passage. You should see something like this:
Do the following:
Change the title of the passage from Untitled Passage to kitchen.
Double-click on the passage text and change it to:
You could [[try talking to Grumpy Husband]] or perhaps it might be better to [[see what your Whiny Nephew is up to]].
What you just entered is the text that will appear on the page that corresponds to the passage. The text in [[double square brackets]] does a couple of things:
It links to another passage, whose name is the text in the brackets. For example, [[try talking to Grumpy Husband]] links to another passage named try talking to Grumpy Husband.
If the other passage that it links to doesn’t already exist, it creates that passage. Since the try talking to Grumpy Husband passage didn’t already exist, Twine creates it.
The passage editing window should look like this:
Click the X in the upper right-hand corner to exit the passage editing window. You’ll return to the storyboard, which will now look like this:
Note that there are two newly-created passages: try talking to Grumpy Husband and see what your Whiny Nephew is up to. Twine inferred that you’d need them because the kitchen passage links to them, and they didn’t exist yet.
To make the story a little more complete, do the following:
Edit the try talking to Grumpy Husband passage so that its text is “This is the Grumpy Husband passage.”
Edit the see what your Whiny Nephew is up to passage so that its text is “This is the Whiny Nephew passage.”
The storyboard should now look like this:
Now we have enough of a story to play. Press the Play button to play the story. You should see this:
If you click on the try talking to Grumpy Husband link, you get taken to this passage:
And if you click on the see what your Whiny Nephew is up to link, you get taken to this passage:
Congratulations — not only have you written your first twine interactive story, but you also now know enough to write basic “Choose Your Own Adventure” stories!
Separating link text from passage titles
With simple links in Twine, a link called [[link text]] links the text “link text” to a passage whose title is link text. If you’ve done wiki or Markdown links, you’re probably wondering if there’s a way to make links whose text is different from the title of the passage that it should link to.
Such a way exists, and the format is like this:
[[link text|name of passage to link to]]
For example, to link the text try talking to Grumpy Husband to a passage titled talk to owen, you would format the link like this:
[[try talking to Grumpy Husband|talk to owen]]
This format of link lets you link long passages of text to passages with shorter names that might be more meaningful to you as a story author. Let’s take advantage of these links by doing the following:
Change the title of the try talking to Grumpy Husband passage to talk to owen.
Change the title of the see what your Whiny Nephew is up to passage to talk to luke.
Open the kitchen passage. You’ll see that Twine has changed the text in the links:
You could [[talk to owen]] or perhaps it might be better to [[talk to luke]].
Edit the kitchen passage so that it looks like this:
You could [[try talking to Grumpy Husband|talk to owen]] or perhaps it might be better to [[see what your Whiny Nephew is up to|talk to luke]].
The storyboard should now look something like this:
Now that we’ve got a way to give passages short titles that are useful to the author and link to them with long strings of text that are meaningful to the reader, we can now craft our story.
Let’s make a story!
Now that you know the basic mechanics of working with Twine, let’s make a story.
In this interpretation of the story, Beru’s fed up with her life— she’s as a moisture farmer on a desert planet who’s married to a guy who seems never to be anything other than grumpy and stuck with a whiny nephew.
Your best way to get a feel for the game is to play it online. Go and try out all the options — there are only 9 passages in the story, so I shouldn’t take you too long to see them all.
1. Edit “kitchen”
We’ll start by setting the editing the starting passage, kitchen, to give it a more complete text:
<h1>An Aunt’s Story</h1>
Wiping away the last of the blue milk from the table, you realize that the chores are done. You sigh as once again, the men in the house have failed to help clean up and stuck you with all the work.
Perhaps it’s time to talk to them.
You could [[try talking to Grumpy Husband|talk to owen]] or perhaps it might be better [[to see what your Whiny Nephew is up to|talk to luke]].
Note that there’s an <h1> tag in the text. HTML tags work in Twine in the same way they work on web pages. Here’s how the passage will look:
2. Edit “talk to owen”
Change the text in the talk to owen passage to this:
Grumpy Husband did what he always does does after dinner: slouched into the living room sofa, flipped on the holoprojector, and put on the pod races. He’s mesmerized by the action, taking occasional sips from his beer. He’s halfway through the 12-pack as you enter.
“Don’t bother me, woman,” he slurs, his eyes not moving from the race.
Looking at him, it becomes clear to you that [[going ahead with your big plan to change everything|proceed with plan – owen]] is the right way to go. But there’s a part of you — the part that always tells you to “stay in your lane” — that tells you that sometimes he’s nice, that he’s a good provider, and hey, what other prospects do I have living on this rock? Maybe I should just [[accept things as they are|accept fate]].
Since this text includes links to passages that don’t yet exist, Twine automatically creates them: proceed with plan – owen and accept fate. The storyboard will look like this:
3. Edit “accept fate”
Edit the accept fate passage so that it has this text:
The movie continues as scripted, which is good for Whiny Nephew; not so good for you.
Note that there are no links in accept fate. That’s because it’s one of the story endings. In a more fully-produced story, you might want to provide a link that allows the reader to start over from the beginning.
4. Edit “talk to luke”
Edit the talk to luke passage so that it has this text:
You walk into the garage, where Whiny Nephew spends what little time he has when he’s not helping Grumpy Husband on the farm, eking the scant moisture from Tattooine’s arid atmosphere.
He’s sitting at his tool table doing what he does best: moping and bellyaching. So what else is new? At least he has those droids to keep him busy.
Whiny Nephew turns to you. “Aunt Beru,” he says, “I think these droids are stolen.”
Oh, great, you think to yourself. That throws a wrench in my plans.
“I think you should report this,” says Whiny Nephew, who’s always been a bit too much of a goody two-shoes for his own good. You wonder if his dad was this much of a crybaby, and what his mom saw in the guy.
You could [[get the cops involved|call cops]], or simply [[proceed with your original plan|proceed with plan – luke]].
once again, you’ve provided text that includes links to passages that don’t yet exist, Twine automatically creates them: proceed with plan – luke and call cops. The storyboard will look like this:
At this point, you might want to drag the passages around so that it’s easier to follow and the arrows don’t overlap. Twine will preserve the connections between passages, so don’t feel leery about moving those boxes around.
Here’s how I rearranged the passages:
5. Edit “call cops”
This is one of the story’s endings. Edit this passage’s text so that it looks like this:
You slip into your room and quietly call up the local constabulary on your comlink. In a matter of minutes, a couple of nice friendly stormtroopers arrive.
The ’troopers put your Grumpy Husband and Whiny Nephew under arrest, slapping binders on their hands behind their backs. You allow a slight smirk to cross your face as they are led away, never to be seen again.
They put restraining bolts on the stolen droids. Now immobilized, it’s very easy for them to use laser cutters to slice into the R2 unit, from which they retrieve some kind of data tape (this movie was made the 1970s, so yes, data is stored on tapes).
“You’ve done a great service to the Empire, ma’am,” says the commanding officer. “There’s a 250,000-credit reward for these droids.”
“Oh dear,” are the last words you hear the protocol droid say before it and the now-headless R2 unit are taken away for scrap.
After all this fuss, it’s time for a nice vacation. With a quarter million credits in your account, you can go anywhere and do anything you like! Hours later, you’re flying first class to a place you’ve always wanted to visit: the lush, beautiful, fantastic vacation desination of Alderaan.
6. Edit “proceed with plan – luke”
Edit the proceed with plan – luke passage so that it has this text:
“Don’t worry,” you reassure Whiny Nephew, giving him a gentle kiss on his forehead. “There aren’t my first stolen droids. I’ve got a bulk eraser in the closet, and we can wipe their memories clean tomorrow. I’ll also show you how to file off their serial numbers.”
Whiny Nephew looks at you with big bantha eyes and nods. You send him off to bed. The protocol droid shuts down for the night. That leaves the R2 unit.
[[Looking at the R2 unit, you get an idea|deal with R2]].
This text includes a links to passage that doesn’t yet exist, so Twine automatically creates it: deal with R2. The storyboard will look like this:
7. Edit “proceed with plan – owen”
Edit the proceed with plan – owen passage so that it has this text:
Your plan to deal with Grumpy Husband requires no witnesses. You need to get Whiny Nephew away from the house for a few hours tomorrow morning.
You get an idea. Later that night, after you’re sure that everyone has fallen asleep, you [[sneak into the garage to check up on the droids|deal with R2]].
Note that the link in this text is to a passage that already exists, so Twine simply makes the connection:
8. Edit “deal with R2”
Edit the proceed with plan – owen passage so that it has this text:
Looking at the R2 unit’s head, you see that it’s got some kind of data tape inserted into it. You press the “eject” button below its eye, and out pops the tape.
You recognize the tape’s case and markings not just as Imperial data storage, but highly secure Imperial data storage. This droid’s way too hot, but it gives you an idea.
You reinsert the tape back into the R2 unit, boot it up, and tell it that you know where to find the master it’s been beeping and booping about since its arrival.
“Of course your master is the crazy old hermit who lives on the far side of Beggar’s Canyon. EVERYBODY knows that old BEN Kenobi is OBI-WAN Kenobi. That has got to be the DUMBEST witness protection program name.”
You pull the restraining bolt from the R2 unit. It lets out a quiet “squeeee!” of delight, and wheels away. (Once outside of the camera’s field of vision, it pops little rockets out of its sides and FLIES to Beggar’s Canyon.)
Now it’s time to [[deal with Grumpy Husband|deal with owen]].
This text includes a links to passage that doesn’t yet exist, so Twine automatically creates it: deal with owen. The storyboard will look like this:
9. Edit “deal with owen”
This is the last passage in the story, and it’s also one of its endings. Edit the deal with owen passage so that it has this text:
In the morning, Whiny Nephew realizes that the R2 unit has broken free of its restraining bolt. He and the protocol droid hop into the landspeeder in the direction of Beggar’s Canyon.
With all witnesses out of the way, you take something from a hidden panel in the pantry and walk into the living room, where Grumpy Husband passed out last night. He slowly wakes as you walk in, staring dumbly at you, a single drop of spittle dangling from his lips.
“Owen,” you say as you level the blaster at him, “it’s over.”
One shot would’ve been sufficient, but you wanted to be sure. You fire repeatedly until the blaster becomes too hot to hold.
Hours later, you’re at Mos Eisley spaceport, flying off into a brand new life. You left a fake corpse beside Grumpy Husband’s ruins; Whiny Nephew’s not all the bright and will simply assume that you and Grumpy Husband were killed by itinerant Tuskens, meandering Jawas, or who-know-what-else.
Much later, you find out that Whiny Nephew made the news. He’s a terrorist now!
The storyboard will end up looking like this:
You now have a Twine story with 9 passages and 3 endings!
Publishing the story
When you have a complete story, you may want other people to play it. You do this by publishing it to a file.
To publish your story, go back to Twine’s home page by clicking on the Home icon at the lower left-hand corner of the storyboard screen. You should see the icon for your story:
Click on the Settings icon. This menu will appear:
Select Publish to File from the menu. You’ll be asked for a location to save the file to. The end result is a self-contained HTML file that you can load in your browser, or even publish on your site!
Want the source?
If you want the source file for this story, get it here, then use Twine’s Import From File command to load it.
At the last gathering of Tampa iOS Meetup, I walked the group through the creation of a couple of simple ARKit apps. The first was one that created shapes with random locations and orientations in the room you were in. You can see the evolution of the app from start to finish in the screenshot montage above.
This article walks you through the steps of creating this ARKit app. In order to develop it (or any other ARKit app), you’ll need the following:
A Mac running the latest version of Xcode, Xcode 9
An ARKit-compatible iPhone or iPad with an A9 or later processor, which is one of the following: iPhone 6S and 6S Plus, iPhone 7 and 7 Plus, iPhone SE, any of the first- or second-generation iPad Pros, iPad 2017, and eventually, the iPhone 8, 8 Plus, and X
iOS 11 installed on your ARKit-compatible iPhone or iPad
Once you’ve gathered all these, you can get started!
Start with the File → New → Project… dance and create a new project in Xcode. Choose the Single View App template and not Augmented Reality App, then continue through the usual steps until you’ve got a new project:
3D rendered objects courtesy of the SceneKit framework
Real world camera views, real world tracking and horizontal plane detection courtesy of the ARKit framework
Let’s build the app’s single view. Open Main.storyboard. Look for ARKit SceneKit View in the Object Library. You may find it helpful to type ARKit or ARSCN into the Object Library’s search box:
Drag an ARKit SceneKit view onto the view. Expand it so that it takes up the entire view and add these 4 constraints, as shown in the screenshot below:
By definition, ARKit apps make use of one of the cameras, which means that they require the user’s permission to do so. Open info.plist and add the following key/value pair:
Key: Privacy – Camera Usage Description
Value: This app uses the rear camera to make augmented reality images.
(Feel free to change the value to whatever text you feel is appropriate.)
We need to be able to refer to the newly-added ARKit SceneKit View in our code, so we need to create an outlet for it. Switch back to Main.storyboard and then click the Assistant Editor button — — which should cause Xcode to show both Main.storyboardandViewController.swift.
Create an outlet for the ARKit SceneKit view by control-dragging from the ARKit SceneKit view on Main.storyboard to an empty spot in ViewController.swift — inside the class body, and outside any methods:
Once you’re done dragging, Xcode should display a pop-up box, as shown in the screenshot below. Do the following:
Make sure that the Connection type is Outlet.
Enter sceneView in the Name textbox.
Click the Connect button.
You should now have a new instance property in your class:
…but it also comes with a couple of error messages:
These messages are the result of your adding the ARKit SceneKit view and an outlet to it to the view controller code. That’s because your view controller has references to ARKit or all the goodies that come with it.
You can fix this by adding this line just below the import UIKit line:
When you do this, the error messages should disappear:
With an ARKit SceneKit view laid out on our view and an outlet for it in our code, it’s now time to initialize it.
The first thing we need to do create a configuration instance to determine the kind of augmented reality experience that we want to provide to the user. ARKit gives us three choices:
ARFaceTrackingConfiguration: For “selfie” AR apps that use the front-facing camera to track the user’s facial movements and expressions. This is probably the technology behind Animoji.
AROrientationTrackingConfiguration: For apps that provide a basic AR experience. This uses the rear-facing camera and tracks only the device’s orientation — the direction it’s facing, or more precisely, its Euler angles.
ARWorldTrackingConfiguration: For apps that provide high-quality AR experiences. This uses the rear-facing camera to precisely track both the device’s position and orientation, and it can do plane detection and hit testing.
For this app, we want the user to be able to create objects in the room they’re in and then be able to walk around them and view them from every possible angle, so we’ll go with ARWorldTrackingConfiguration.
Add this line below the declaration for the sceneView outlet:
// We'll use the AR configuration that provides the best AR experience,
// which tracks the device’s position and orientation, and allows for
// plane detection and hit testing.
Now that we’ve defined the configuration instance, let’s initialize our ARKit SceneKit view.
Update the viewDidLoad method so that it looks like this:
Here’s what’s happening in the code above:
This line turns on a couple of options which are useful for debugging ARKit apps. In most cases, you’ll want to turn them off when the app is ready for the general public:
ARSCNDebugOptions.showWorldOrigin: This causes SceneKit to display a group of three line segments that indicate the x-, y-, and z-axes of the coordinate system that ARKit will use for the real world. The x-axis is red, the y-axis is green, and the z-axis is blue. The point where the they meet is the origin, which is set as the location of the device when the augmented reality session is started. This point has the coordinates (0, 0, 0).
ARSCNDebugOptions.showFeaturePoints: This causes SceneKit to display a number of yellow dots that represent points on horizontal planes that ARKit is using to “feel” its way around the real world.
This line tells ARKit to start doing its thing using the given configuration, which we’ve specified as the “track the device’s motion in the real world with 6 degrees of freedom”.
Run the app. Of course, the real-world images you’ll see are different from the ones shown in the screenshot below, but you should see the x-, y-, and z-axes and feature points that we specified as debug options:
A screen capture from the app. The origin is where the positive x-axis (the red line), positive y-axis (the green line), and the positive z-axis (the blue line) meet. The yellow dots on the chair are the feature points.
Adding a button and a shape
It’s time to add a button that the user will press to add objects to the AR world.
Open Main.storyboard, choose Button from the Object Library and drag it to the lower left corner of the view, leaving the default amount of distance from the left and bottom margin:
Give the button the following constraints:
Constrain to margins: checked
With the button still selected, switch to the Attributes Inspector — — and set the following attributes as follows:
Type: Add Contact
The button needs to respond to taps, ]so we need to create an action for it. Click the Assistant Editor button — — which should cause Xcode to show both Main.storyboardandViewController.swift.
Create an action for the button by control-dragging from the button on Main.storyboard to an empty spot in ViewController.swift — inside the class body, and outside any methods:
Once you’re done dragging, Xcode should display a pop-up box, as shown in the screenshot below. Do the following:
Make sure that the Connection type is Action.
Enter addButtonPressed in the Name textbox.
Make sure that the Event type is Touch Up Inside.
Click the Connect button.
The view controller will now have a new method:
Add one line to this method — a call to the addShape() method:
You’ve probably figured out that we need to define that method now:
There’s a lot going on in this method, so let’s take it line by line:
As the name addShape() implies, the method adds a shape to the augmented reality environment we’re creating. We do this creating a SceneKit node — an instance of SCNNode — which represents a point in 3D space and its properties. We’ll then define some of those properties so that the node appears as a shape when we add it to the environment.
This line gives the node a shape. In this case, we’re assigning it a sphere geometry — an instance of SCNSphere — with a radius of 0.2 meters or 20 centimeters to the node we just created to the node.
This line gives the shape a color. It has to go through a number of properties to do so:
firstMaterial: An instance of SCNMaterial, which is a set of shading attributes that defines the appearance of an SCNNode’s geometry. You can add many materials to a geometry to give it a complex appearance, but you must specify at least one if you want it to be visible. firstMaterial is a convenience method that returns the first material in a geometry’s materials array.
diffuse: This is a material property that describes how light reflects from all directions from the material. Think of this as the material’s “base” color.
contents: This specifies the visual content of a material property, such as color, image, or source of animated content. In this case we’re using it to specify a color.
This one’s pretty simple: it sets the coordinates of the node relative to the origin of the AR environment, which is the location of the phone at the start of the AR session. In SceneKit, you specify coordinates and many other things that can be described as related 3-number groups using SCNVector3 instances.
Now that we’ve properly defined the node, we add it to the scene. Every node in a SceneKit scene is a child of the root node or some other node in the scene.
Run the app. You should see something like this:
Remember, a sphere with a 0.2-meter radius has a 0.4-meter diameter, which is big enough to swallow up the axis guides around the origin. I made it big so that you wouldn’t miss it.
Changing the shape and size
Let’s give the node a different geometry and make it a little smaller. Change the node.geometry = SCNSphere(radius: 0.2) line in addShape() to:
This line gives the node a box geometry — an instance of SCNBox — with a length, width, and height of 0.1 meters or 10 centimeters, and no chamfer.
In case you’re not familiar with the term, chamfering is the rounding of the corners; the greater the chamfer radius, the more rounded the corners.
Run the app again. You should now see something like this:
Adding lighting effects
You may have noticed that it can be hard to see the edges of the box from certain angles. Some lighting effects will help with that. In the viewDidLoad() method, make the AR SceneKit view’s turn on default lighting by adding a line:
With the default lighting turned on, it’s as if there’s an omnidirectional light source located right where the camera is, and this light will illuminate and be reflected by all SceneKit objects in the view. Since it’s virtual light, it won’t affect any real-world objects in the view.
If you run the app now, the box appears more defined:
Let’s add another lighting effect. In the addShape() method, add a line so that the shape gives off specular reflection in addition to diffuse reflection:
It’s easier to show you what specular reflection is than it is to describe it. Run the app, and you should see something like this:
Remember, we’ve turned on the default lighting, which creates a virtual light source right where the camera is. You can see that light source’s specular reflection when you look at the box from certain angles.
Now that you’ve seen both diffuse and specular reflection in action, here’s the science that explains the difference between the two:
In diffuse reflection, light rays that hit the surface get scattered at many angles. Diffuse reflection is what makes objects visible and gives them their base color and texture.
In specular reflection, light rays that hit the surface reflect off the surface at the same angle. The more specular reflection an object exhibits, the more mirror-like it is.
Here’s a diagram showing how differing combinations of diffuse and specular reflection appear on a computer-generated sphere:
So far, we’ve been drawing what appears to be a single shape at the same location, (0, 0, 0). In fact, every time you press the button, you’re adding another shape to the AR world, but in the exact same place, which is why it seems that there’s only one shape there.
Let’s fix that by changing the addShape() method so that it draws its shape in a random location within a half-meter radius of the origin:
With this change, the app now draws cubes in random positions around the origin:
Stop the app and run it again, press the button over and over, and pay attention to where the cubes are drawn. You may notice that they seems to be appearing in the same places as the previous run. In fact, if you run the app with your device connected to the computer, you’ll see in Xcode’s debug console that every time you run the app and press the button, it always generates the same “random” coordinates. For one particular session, the app always generated these coordinates for the cubes:
This happens because drand48(), like most random number generating functions, isn’t truly random. It’s a pseudorandom function that starts with a “seed” value and then performs some mathematical operation on that value to get a new, seemingly-random number. If you don’t give drand48() a new seed value for each session, it will always generate the same sequence of pseudorandom numbers.
Fortunately, seeding drand48() is simple: all you have to do provide its seeding function, srand48() with an integer as a seed value. If you use an integer that you know will be different every time you run the app, drand48() will provide a different series of pseudorandom numbers every time you run the app. Many pseudorandom number-generating systems use the current time as the seed value, and that’s what we’ll do.
Change the code in viewDidLoad() so that it looks like this:
The Date class’ timeIntervalSince1970 property returns a Double representing the number of seconds that have passed since midnight UTC on January 1, 1970. As a constantly-changing value, it’s a pretty good one to use to seed drand48().
If you run the app with the above change in place, you’ll see that it generates cubes in different locations for every run.
Right now, all the shapes we’re drawing are in different positions, but all have the same orientations. Just as node positions are set using the Node.position property, node orientations are set during the Node.eulerAngles property, which sets the node’s angles of rotation around the x-, y-, and z-axes:
Euler is a reference to superstar mathematician Leonhard Euler, and it’s pronounced “Oiler”.
Update theaddShape() method so that it randomizes the shapes’ Euler angles: