Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all 1836 articles
Browse latest View live

An Introduction to Quartz 2D

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24267

What Is Quartz 2D?

Quartz 2D is Apple's 2D drawing engine, an important component of the Core Graphics framework. You may often see Quartz 2D referred to as Core Graphics or simply CG.

Quartz 2D uses the "painter's model". In the painter’s model, each successive drawing operation applies a layer of “paint” to an output “canvas”, often called a page. Think of this as an artist working on a painting. If the artist were to paint the entire canvas blue and then paint some clouds onto the canvas then the clouds would cover the blue beneath them. Once something is "painted" onto the canvas, it cannot be changed but by adding more paint atop of it.

All drawing in Quartz 2D is done through a graphics context of type CGContextRef. With a reference to a graphics context, you can use the Quartz 2D functions to draw to the context, perform operations, such as translating the context, and change graphic state parameters, such as line width and fill color. Quartz 2D is a C-based API, as such you will invoke the C functions passing in the context as a parameter.

To draw to the screen on iOS, you must subclass a UIView and override its drawRect(_:)method. It is inside this drawRect(_:) method that you will do any custom drawing. You should never call the drawRect(_:) method directly in your code. If you need to update the screen with fresh drawing commands, you should call the methods setNeedsDisplay() or setNeedsDisplayInRect(_:).

When using Quartz 2D on iOS, the coordinate (0,0) is at the top left of the screen. The x coordinate increases as you move right and the y coordinate increases as you move down.

Throughout this tutorial, you may wish to consult the Quartz 2D programming guide. The purpose of this tutorial is to get started using Quartz 2D. There is much that will not be covered and to fully appreciate all that Quartz 2D has to offer I suggest you read the programming guide.

With this brief introduction out of the way, let's get started using Quartz 2D.

1. Preparing a UIView for Drawing

Assuming you have a project open and are ready to start working with Quartz 2D, the steps you need to take are fairly simple. You'll need to create a class that is a subclass of UIView, add a view from the Object library to your project in Interface Builder, and set that view's class to the UIView subclass you created. Let's go through this step by step.

Step 1: Subclassing UIView

Go to File> New> File.... Under the iOS section, select Source and then choose Cocoa Touch Class as the template.

New Cocoa Touch Class

On the screen that follows, give your class a name, make sure it's a UIView subclass, and set the language to Swift. Press Next and choose where to save your new class.

Set File Options

If you view the source of your newly created class, you will see the drawRect(_:) method. It's currently commented out, but we will change that in a few moments.

Step 2: Adding a View and Setting the Class

Open the project's storyboard and open the Object Library on the right. In the search field at the bottom, enter "UIView" to filter out objects we're not interested in.

Show Object Library

Drag a UIView instance onto the view controller. With the view selected, open the Identity Inspector on the right and change Class to whatever you named the subclass.

Set Class on View

Any code you add inside the drawRect(_:) method will be drawn when the UIView subclass is instantiated. The view automatically configures the drawing environment so that you can begin drawing immediately. The view configures the CGContextRef mentioned at the beginning of this lesson and it is inside the drawRect(_:) method that you will get a reference to it.

2. Starter Project

To get us started quickly, I have provided a starter project that has all the views already wired up and ready to use. The UIView subclasses are named after the drawing command we will be exploring. For example, when we are learning about drawing lines the corresponding class will be named DrawLinesView.

You can download the starter project from GitHub. We will get started coding in the next step.

3. Obtaining a Reference to the Graphics Context

Before you can do any drawing, you need to get a reference to the graphics context. This is accomplished as follows.

This returns an opaque type, CGContextRef, and you will pass this context into the C functions to do the custom drawing. Now that we know how to get a reference to the graphics context we can start exploring the drawing commands.

4. Drawing a Line

If you've downloaded the starter project, open DrawLineView.swift and add the following to the drawRect(_:) method.

We first get a reference to the drawing context as discuss earlier. Because this is something we will do for every example, I won't mention this in the coming examples.

The CGContextSetStrokeColorWithColor(_:_:) function sets the color with which the line will be drawn or stroked. The parameters we pass in are the graphics context and the new stroke color.

If you think of the graphics context as the canvas of a painter, then the CGContextMoveToPoint(_:_:_:) function moves the paintbrush to a particular point on the canvas from which to begin or continue drawing. Imagine drawing on a piece of paper, lifting your hand, and moving to a different part of the paper and continuing to draw. Essentially that is what this method accomplishes. We pass in the graphics context and an x and y coordinate to start the drawing from.

The CGContextAddLineToPoint(_:_:_:) function takes as parameters the graphics context, the x value for the end of the line segment, and the y value for the end of the line segment. After adding the line segment, the current point will be set to the endpoint of the line segment. We started the drawing operation at (0,0), after this drawing operation the cursor or paintbrush is at (200,200).

Finally, to do the actual drawing you need to call the CGContextStrokePath(_:) function passing in the graphics context.This function simply draws a line along the path we specified.

Build and run the sample project to see the effect.

5. Drawing a Rectangle

Open DrawRectangleView.swift and add the following to the drawRect(_:) method. You should be familiar with the first two lines by now.

The CGRectMake(_:_:_:_:) function is part of CGGeometry and provides an easy way to create a CGRect structure. As its name implies, CGRect  is a structure that contains the location and dimensions of a rectangle. A CGRect has two fields, origin and size, which are a CGPoint and a CGSize respectively. If you are not familiar with these data types, then have a quick read in the CGGeometry reference.

We create a constant, rectangle, using the CGRectMake(_:_:_:_:) function and call the CGContextAddRect(_:_:) function, which takes as parameters the graphics context and a CGRect. Lastly, we call CGContextStrokePath(context) to draw the rectangle.

Build and run the project to see the rectangle drawn to the screen.

6. Drawing a Circle

Open DrawCircleView.swift and update the drawRect(_:) method as follows.

You may be wondering why we are calling CGRectMake(_:_:_:_:) when we are drawing a circle? The rectangle is the area the circle must fit within. In the code above, we create a circle by using a square. If you want to draw an oval or ellipse, then you need to make the rectangle more rectangular in shape.

We then call the CGContextAddEllipseInRect(_:_:) function, which takes as parameters the graphics context and the rectangle into which to draw the ellipse. The circle is drawn by calling CGContextStrokePath(_:), passing in the graphics context.

7. Drawing an Arc

Open DrawArcView.swift and add the following code inside the drawRect(_:) method.


The CGContextAddArc(_:_:_:_:_:_:_:) function takes quite a few parameters:

  • the graphics context
  • the x value for the center of the arc
  • the y value for the center of the arc
  • the arc's radius
  • the angle to the starting point of the arc, measured in radians from the positive x-axis
  • the angle to the end point of the arc, measured in radians from the positive x-axis
  • a value of 1 to create a clockwise arc or a value of 0 to create a counterclockwise arc

8. Drawing a Path

To draw more complex shapes, you create a path and stroke it. Take a look at the drawRect(_:) method in DrawPathView.swift.

In the drawRect(_:) method, we call CGContextAddLineToPoint(_:_:_:) a number of times to create a triangle. Note that the triangle is not filled, only stroked. In the next step, we will see how to fill the triangle with color.

9. Filling a Path

Open FillPathView.swift and update the drawRect(_:) method as shown below.

In the previous step, we stroked a path, but you can also fill a path with a particular color. In the above drawRect(_:) method, we start by creating a path for the same triangle as in the previous example. This time we set a fill color using the CGContextSetFillColorWithColor(_:_:) function and call CGContextFillPath(_:) rather than CGContextStrokePath(_:).

10. Filling an Ellipse

Aside from filling paths, you can also fill ellipses and rectangles. In this example, we will fill an ellipse. Filling a rectangle, however, is very similar. Documentation will tell you how that's done. Update the drawRect(_:) method in FillEllipseView.swift as shown below.

Most of this code should be familiar by now. We are using a new function, CGContextSetLineWidth(_:_:), to set the line width and we call CGContextFillEllipseInRect(_:_:) to fill the ellipse. This function takes as parameters the graphics context and the rectangle in which to fill the ellipse.

11. Adding Lines

The CGContextAddLines(_:_:_:) function is a handy function when you have a number of connected straight line segments you wish to draw. Here we recreate the triangle from earlier in the examples, using the CGContextAddLines(_:_:_:) function. Add the following code to AddLinesView.swift.

The CGContextAddLines(_:_:_:) function takes as parameters the graphics context, an array of values that specify the start and end points of the line segments to draw as CGPoint structures, and the number of elements in the array. Note that the first point in the array specifies the starting point.

12. Drawing a Gradient

With Quartz 2D, it's easy to draw gradients. Both linear and radial gradients are supported. In this example, we will draw a linear gradient. The documentation will help you if you're interested in drawing radial gradients. Add the following to DrawGradientView.swift.

The CGContextDrawLinearGradient(_:_:_:_:_:) function takes as parameters:

  • the graphics context
  • a CGGradient structure
  • a start point
  • an end point
  • option flags that specify whether the fill is extended beyond the starting or ending point

A CGGradient structure defines a smooth transition between colors across an area. It has a color space, two or more colors, and a location for each color. The constants colorspace, colors, and locations in the above example represent these parts that make up the CGGradient.

To draw the gradient, we call the CGContextDrawLinearGradient(_:_:_:_:_:) function, passing in the graphics context, the CGGradient, start and end values, and 0 to indicate that the fill should extend beyond the starting location.

13. Drawing a Shadow

A shadow is an image drawn underneath, and offset from, a graphics object such that the shadow mimics the effect of a light source cast on the graphics object. — Quartz 2D Programming Guide

 There are two functions you can use to draw shadows, CGContextSetShadow(_:_:_:) and CGContextSetShadowWithColor(_:_:_:_:). When using CGContextSetShadow(_:_:_:), all objects drawn are shadowed using a black color with 1/3 alpha. The CGContextSetShadowWithColor(_:_:_:_: function allows you to specify a color for the shadow.

Let's see how this works in practice. Add the following to SetShadowWithColor.swift.

When drawing shadows, you should save the state of the graphics context, make any required changes, and then restore the graphics state. We call CGContextSaveGState(_:) to save the current state of the graphics context, specify an offset for the shadow, shadowOffset, and call the CGContextSetShadowWithColor(_:_:_:_:) function. This functions takes as parameters:

  • the graphics context
  • the offset for the shadow
  • the blur amount
  • the color of the shadow

The rest of the code should be familiar to you. Lastly, we restore the graphics context by calling CGContextRestoreGState(_:), passing in the graphics context.

14. Drawing a Happy Face

I thought it would be fun to end this tutorial by drawing a simple happy face using what we have learned throughout this tutorial. Add the following to DrawHappyFaceView.swift.

The implementation of the drawRect(_:) method should make sense by now and you should have a happy face drawn to the screen.

Conclusion

This brings this tutorial to an end. You should now have a basic understanding of how to perform custom drawing using the Quartz 2D drawing engine. I hope you have learned something useful by reading this tutorial.

2015-08-17T16:15:06.000Z2015-08-17T16:15:06.000ZJames Tyner

Understanding Permissions in Android M

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24443

Introduction

Prior to the M release, the Android permissions model has been an all-or-nothing decision for users at install time. This meant that if a user wanted to use an app, they first had to accept every permission included in the application or choose to not install it at all. This led to many developers losing out on app installs, a trust disconnect between users and developers, and other privacy concerns.

Legacy Install Time Permissions Dialog

Under the new permissions model, users will be able to approve permissions at runtime as they are needed and can deny those permissions at any time. In this article, you will learn how this change in handling permissions will affect you as a developer and how your users will experience your applications.

It should be noted that this article was written before the official release of Android M, so some information may change with the official release.

1. What Requires Permissions?

While Android M still requires permissions to be declared in AndroidManifest.xml, users will now be required to approve or deny the use of that permission at runtime. One important change in the new version of Android is that android.permission.INTERNET and android.permission.WRITE_EXTERNAL_STORAGE have been downgraded from a rating of dangerous to normal. This means that you do not need to prompt the user before use.

When requesting permission approval, the user will be prompted based on the permission's group, rather than being asked to approve every single permission within a group. This means that if your application needs to both send and receive SMS messages, your user will only be prompted to approve the SMS permission group. Below is a list of the currently supported permission groups in Android M Developer Preview 2 as seen from system settings.

List of currently supported permission groups

It should also be noted that Android features a robust Intent system, which allows developers to request data from other applications. Rather than needing to request the camera permission and develop an application that uses the Camera APIs from scratch, you can request that the user take a picture using an already trusted camera application in order to get an image into your app. The permissions involving the camera will be handled by the camera app.

2. How to Ask for Permission?

When you need to use a feature that requires a permission, there's a general flow of events that will happen. You first need to see if that permission has already been approved by your user.

If the user has not approved the permission, you can present them with a permission request dialog. The first time you present this to the user, they will have to either deny or approve the permission.

However, if they have previously denied the permission and are asked again, they will have the option to opt out of ever being asked for that permission again.

Requesting Permissions Flow Chart

You can check if a permission has been previously granted by calling checkSelfPermission before using a feature that will require that permission. This method returns an int value based on wether that permission is granted or not.

If it is equal to PackageManager.PERMISSION_GRANTED, then you can continue as expected. However, if that permission has not been previously granted, you can request it with requestPermissions, passing in an array of permission strings and a custom int request code for keeping track of your app's logic flow.

Once requestPermissions is called, the user is presented with a request dialog for each permission group that your application is asking permission for. It is best practice to only request permissions as needed, rather than in bulk when your user first starts your application.

Request dialog on Android M

When your user is done with the dialogs, onRequestPermissionsResult is called and can be accessed in your Activity. This is where you either start your feature or handle the situation where your user has denied one or more permissions.

An example of how to check if a permission has been granted or denied is shown below. If the user has denied any required permissions for your feature, you should disable that feature and let the user know why it doesn't work in your application.

3. Legacy Apps on Android M

While apps that are built targeting Android M are required to implement the new permissions dialogs and methods, apps built for previous versions of Android will still present users with a list of permissions at install time. Although permissions are accepted before users can use your app, they can still be revoked at any time.

Since the infrastructure for handling revoked permissions will not be available in applications targeting less than Android M, any features that would have required permissions will return null, 0, or an empty value when permissions are not granted. This can lead to unexpected behavior in apps, so it is recommended that developers prepare to upgrade their apps to support the new Android M permission model as soon as possible.

Conclusion

In this article, you have learned about the new Android M permission model and how to support updated permissions in your applications. We've also covered how apps will respond to the new version of Android when they have been built for previous versions. Using this information, you should be able to get your applications ready for the official release of the next update to Android.

2015-08-19T18:15:46.000Z2015-08-19T18:15:46.000ZPaul Trebilcox-Ruiz

Build a High-Performance Mobile App With Famo.us and Manifold.js

$
0
0

For the last few months I’ve been wanting to dive into this new JavaScript framework since I saw its launch event in October of 2014. Famo.us includes an open-source 3D layout engine fully integrated with a 3D physics animation engine that can render to DOM, Canvas, or WebGL. In short, you can get native performance out of a web application, largely due to the way Famo.us handles the rendering of its content.

Jenn Simmons of the Web Platform Podcast recently had Famo.us CEO, Steve Newcomb on the podcast to discuss the mobile performance and their upcoming mixed mode. This was perfect timing, as Microsoft had just released ManifoldJS, a tool which allows you to package your web experience as native apps across Android, iOS, and Windows. I wanted to put these two technologies to the test.

In short, I wanted to determine if Famo.us does actually have great mobile performance, as well as have an understanding of how straightforward the process was for packaging my web application as a mobile app.

What Problem Do These Two Things Solve?

The web isn’t necessarily known for creating high-performance applications, which is a shame because it truly is capable of blazing fast interactive apps, but sadly has been plagued by the DOM. With technologies like the HTML5 canvas, WebGL, and asm.js, the browser really can be a playground for cutting-edge interactivity. Famo.us aims to solve this, getting around the bottleneck for most web applications, which is the DOM, and utilizing WebGL and abstracting your work from the DOM. More on this later.

ManifoldJS aims to make the life of a mobile developer easier than ever by utilizing Web App Manifests, allowing websites to declare app-like properties. ManifoldJS uses that standard for those platforms that support it, but falls back to Cordova for those that don’t. Cordova is great, but the W3C also considers work done at Mozilla (Firefox Open Web Apps), Google (Chrome Hosted Apps) and Microsoft (Windows 8 had local web apps, Windows 10 extends over to hosted web apps). With this, we can now wrap websites and create hybrid applications that can be deployed in the various app stores, while still taking advantage of many native aspects for each device (contacts, calendar, file storage, gyro, GPS, etc.).

When we combine the two, we can create applications at native speed that can be deployed in a number of app stores, utilizing largely one code base. There is no silver bullet for mobile development, but this certainly makes the process easier.

Getting Started With Famo.us

Famo.us has a University page, which provides a great starting point for understanding how the framework works, as well as offering a few sample projects. I ran through all of the courses on the University site and came out with a pretty clear understanding of the framework. They also have integration with other libraries, such as Angular, but I haven’t had time to dive into that just yet.

Next, I clicked on the link at the top-right corner of the page to download their package of guides and two example projects. This is different from what is found on their GitHub page.

I opened the famous-starter-kit folder and navigated to /reference-tutorials and found folders for /slideshow and /timbre. Slideshow is pretty clever; it grabs images from Picasa and draws them to the screen as though they came fresh from a Polaroid camera. You can find a live version of this on my site.

Instant camera image of a dog

Out of the box, however, it didn’t work.

I soon realized what the issue was, though. Their sample pointed toward an invalid Picasa URL. It’s been more than six months since the sample was released, so I would hope that it would be corrected by now, as I’d imagine this would be a damper for a number of people learning to use this otherwise fantastic framework.

Once I changed the URL in the SlideData.js file, all was fine. What the project does is grab images from a Picasa album and draw them to screen. With each click, the camera drops the current image, and a fresh one is ejected from the front of the camera, and is quickly exposed before your eyes, along with some nice physics applied to the swaying back-and-forth of the image. The step-by-step instructions for creating this project can be found on the Famo.us website.

There is another project in the /timbre folder, but I wasn’t able to get that to work either. You can find the associated tutorial on the Famo.us website, though, and at least walk through the process of building it yourself.

How Does Famo.us Work?

I’m not going to spend too much time getting into the details of Famo.us here, but if you really want to dive deeper, there's an article on Medium that gives a great overview.

From the Famo.us website:

Interacting with the DOM is riddled with performance issues. Famo.us abstracts away DOM management […] If you inspect a website running Famo.us, you’ll notice the DOM is very flat: most elements are siblings of one another. […] Developers are used to nesting HTML elements because that’s the way to get relative positioning, event bubbling, and semantic structure. However, there is a cost to each of these: relative positioning causes slow page reflows on animating content; event bubbling is expensive when event propagation is not carefully managed; and semantic structure is not well separated from visual rendering in HTML. Famo.us promises a rich 60 FPS experience, and to do so, we needed to circumvent these inefficiencies.

By utilizing the CSS3 primitive -webkit-transform: matrix3d, along with the hardware acceleration it affords, we can get far greater performance than we could if we just tinkered with the DOM. Any time you touch the DOM, it is expensive. Nicole Sullivan, a fantastic web developer known for her CSS work, gives an excellent explanation of reflows and repainting inside the browser, and how we can avoid these issues. Fortunately, Famo.us abstracts all of this away from us.

Rather than write any HTML code, all of our Famo.us code will be done in JavaScript. Take a look at some of their samples on CodePen to get a good understanding for how little HTML you actually write (none) and what the JavaScript looks like. In an upcoming tutorial, I’ll dive far more in-depth with Famo.us than I do here.

Now we’re talking my language! Some high-performance applications in the browser!

How Does ManifoldJS Work?

The installation process for ManifoldJS is pretty straightforward. Check out their GitHub page for more information. Jeff Burtoft also walks you through the process of creating a hosted web app at ThisHereWeb.com.

This project will continue to evolve over the coming months. In the last week alone I’ve seen several additions. On platforms which natively support web applications, such as Windows 10, Chrome OS, and Firefox OS, ManifoldJS will create native packages. On platforms such as iOS and Android, Cordova is used, which allows a developer to write a web application but still access many of the native features of a device, either through Cordova itself, or the active plugin community.

the process of creating a hosted web app

Jeff Burtoft explains hosted web apps very well on his blog and in his recent //BUILD/ presentation. The video from //BUILD 2015 showcases exactly what you can do with this technology.

My Setup

I’m doing this tutorial from a MacBook Pro running Yosemite 10.10.3, Visual Studio Code as my IDE, and MAMP as my local web server. I then use Source Tree as my Git tool of choice, and host my open-source code on GitHub, and I’ll be deploying to iOS via Xcode.

I know, a Tech Evangelist at Microsoft using Apple products and telling you about open-source tools. What is the world coming to?

Putting It All Together

The first thing I did was download the Famo.us samples from their website. I made the appropriate changes to their SlideData.js file, as I mentioned above, so that my project was able to pull in feeds from Picasa. I’ve uploaded it to GitHub so that you have a sample that works immediately. View the live site, and head to GitHub to download the working project.

Afterwards, I logged in to Azure and created a new website. You can get $200 worth of Azure trial credits, or reach out to me about a free BizSpark membership for yourself or your startup, which grants $150/month of web hosting.

I then point this new Azure website to my GitHub repo. Scott Hanselman explains how to do this in a few steps. From there, I have Azure monitor my GitHub repo for this project, and any changes I push to that repository are immediately picked up by Azure, and the latest changes can be viewed on the website and manifest project immediately.

Azure setup page

Generating the App Manifest

Next up, we need to use ManifoldJS to "wrap" our web app so that we can deploy it to the various app stores. Firefox OS and Chrome support this natively, but for iOS, Android, and Windows 8 or 10, we need to utilize Cordova. ManifoldJS will generate an app manifest file for us, which has all of the information the app stores need to get our project going.

You have two options here: Use the Manifold Web App Generator, which will provide a GUI and step-by-step instructions, or run it through the command line.

Manifold Web App Generator

Alternatively, for the command line, you need to install ManifoldJS first. Make sure you have NPM installed, and then run:

With me so far? Now we can call ManifoldJS and have it generate a folder for us with projects for each of the platforms. In the terminal I entered:

The path following -d tells ManifoldJS which directory I want it to be stored in. Soon after, you should see the terminal building the project before your eyes.

terminal building the project before your eyes

Navigate to where you stored this project, and you’ll find a series of folders there. I then navigated to cordova/platforms/iOS and looked for the file ending in xcodeproj, as I wanted to test this out in the iOS simulator. Double click on that icon to open the project in Xcode.

Navigate to where you stored this project

And there we have it, a Famo.us application running inside of Cordova on iOS.

Famous application running inside of Cordova on iOS

Wrapping It All Up

I plan to try out Angular + Famo.us in one of my upcoming demos, as well as wrapping that in ManifoldJS to test for performance on iOS. If you’re looking to debug these apps, might I suggest looking at VorlonJS? It’s platform-agnostic, takes a minute to set up, and in the link above, I illustrate how I can test apps on a desktop browser, as well as mobile devices.

I’d really like to stress test what mobile browsers are capable of when combining a framework like Famo.us and Cordova, so look for a sample involving those two soon. As the web continues to evolve, Microsoft will continue to update its dev.modern.ie/platform/status/ site to reflect changes to the new Edge browser. The most exciting announcement to me, though, is the recent switch from "in development" to "in edge" tag for asm.js. Soon we’ll be able to run native applications inside of the browser. It’s an exciting time to be working on the web.

More Hands-On With JavaScript

It might surprise you a bit, but Microsoft has a bunch of free learning on many open-source JavaScript topics, and we’re on a mission to create a lot more with Microsoft Edge.

Here are some great resources from my team and colleagues:

And some free tools to get started: Visual Studio Code, Azure Trial, and cross-browser testing tools—all available for Mac, Linux, or Windows.

This article is part of the web dev tech series from Microsoft. We’re excited to share Microsoft Edge and the new EdgeHTML rendering engine with you. Get free virtual machines or test remotely on your Mac, iOS, Android, or Windows device @ http://dev.modern.ie/.

2015-08-20T16:30:46.000Z2015-08-20T16:30:46.000ZDavid Voyles

Build a High-Performance Mobile App With Famo.us and Manifold.js

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24496

For the last few months I’ve been wanting to dive into this new JavaScript framework since I saw its launch event in October of 2014. Famo.us includes an open-source 3D layout engine fully integrated with a 3D physics animation engine that can render to DOM, Canvas, or WebGL. In short, you can get native performance out of a web application, largely due to the way Famo.us handles the rendering of its content.

Jenn Simmons of the Web Platform Podcast recently had Famo.us CEO, Steve Newcomb on the podcast to discuss the mobile performance and their upcoming mixed mode. This was perfect timing, as Microsoft had just released ManifoldJS, a tool which allows you to package your web experience as native apps across Android, iOS, and Windows. I wanted to put these two technologies to the test.

In short, I wanted to determine if Famo.us does actually have great mobile performance, as well as have an understanding of how straightforward the process was for packaging my web application as a mobile app.

What Problem Do These Two Things Solve?

The web isn’t necessarily known for creating high-performance applications, which is a shame because it truly is capable of blazing fast interactive apps, but sadly has been plagued by the DOM. With technologies like the HTML5 canvas, WebGL, and asm.js, the browser really can be a playground for cutting-edge interactivity. Famo.us aims to solve this, getting around the bottleneck for most web applications, which is the DOM, and utilizing WebGL and abstracting your work from the DOM. More on this later.

ManifoldJS aims to make the life of a mobile developer easier than ever by utilizing Web App Manifests, allowing websites to declare app-like properties. ManifoldJS uses that standard for those platforms that support it, but falls back to Cordova for those that don’t. Cordova is great, but the W3C also considers work done at Mozilla (Firefox Open Web Apps), Google (Chrome Hosted Apps) and Microsoft (Windows 8 had local web apps, Windows 10 extends over to hosted web apps). With this, we can now wrap websites and create hybrid applications that can be deployed in the various app stores, while still taking advantage of many native aspects for each device (contacts, calendar, file storage, gyro, GPS, etc.).

When we combine the two, we can create applications at native speed that can be deployed in a number of app stores, utilizing largely one code base. There is no silver bullet for mobile development, but this certainly makes the process easier.

Getting Started With Famo.us

Famo.us has a University page, which provides a great starting point for understanding how the framework works, as well as offering a few sample projects. I ran through all of the courses on the University site and came out with a pretty clear understanding of the framework. They also have integration with other libraries, such as Angular, but I haven’t had time to dive into that just yet.

Next, I clicked on the link at the top-right corner of the page to download their package of guides and two example projects. This is different from what is found on their GitHub page.

I opened the famous-starter-kit folder and navigated to /reference-tutorials and found folders for /slideshow and /timbre. Slideshow is pretty clever; it grabs images from Picasa and draws them to the screen as though they came fresh from a Polaroid camera. You can find a live version of this on my site.

Instant camera image of a dog

Out of the box, however, it didn’t work.

I soon realized what the issue was, though. Their sample pointed toward an invalid Picasa URL. It’s been more than six months since the sample was released, so I would hope that it would be corrected by now, as I’d imagine this would be a damper for a number of people learning to use this otherwise fantastic framework.

Once I changed the URL in the SlideData.js file, all was fine. What the project does is grab images from a Picasa album and draw them to screen. With each click, the camera drops the current image, and a fresh one is ejected from the front of the camera, and is quickly exposed before your eyes, along with some nice physics applied to the swaying back-and-forth of the image. The step-by-step instructions for creating this project can be found on the Famo.us website.

There is another project in the /timbre folder, but I wasn’t able to get that to work either. You can find the associated tutorial on the Famo.us website, though, and at least walk through the process of building it yourself.

How Does Famo.us Work?

I’m not going to spend too much time getting into the details of Famo.us here, but if you really want to dive deeper, there's an article on Medium that gives a great overview.

From the Famo.us website:

Interacting with the DOM is riddled with performance issues. Famo.us abstracts away DOM management […] If you inspect a website running Famo.us, you’ll notice the DOM is very flat: most elements are siblings of one another. […] Developers are used to nesting HTML elements because that’s the way to get relative positioning, event bubbling, and semantic structure. However, there is a cost to each of these: relative positioning causes slow page reflows on animating content; event bubbling is expensive when event propagation is not carefully managed; and semantic structure is not well separated from visual rendering in HTML. Famo.us promises a rich 60 FPS experience, and to do so, we needed to circumvent these inefficiencies.

By utilizing the CSS3 primitive -webkit-transform: matrix3d, along with the hardware acceleration it affords, we can get far greater performance than we could if we just tinkered with the DOM. Any time you touch the DOM, it is expensive. Nicole Sullivan, a fantastic web developer known for her CSS work, gives an excellent explanation of reflows and repainting inside the browser, and how we can avoid these issues. Fortunately, Famo.us abstracts all of this away from us.

Rather than write any HTML code, all of our Famo.us code will be done in JavaScript. Take a look at some of their samples on CodePen to get a good understanding for how little HTML you actually write (none) and what the JavaScript looks like. In an upcoming tutorial, I’ll dive far more in-depth with Famo.us than I do here.

Now we’re talking my language! Some high-performance applications in the browser!

How Does ManifoldJS Work?

The installation process for ManifoldJS is pretty straightforward. Check out their GitHub page for more information. Jeff Burtoft also walks you through the process of creating a hosted web app at ThisHereWeb.com.

This project will continue to evolve over the coming months. In the last week alone I’ve seen several additions. On platforms which natively support web applications, such as Windows 10, Chrome OS, and Firefox OS, ManifoldJS will create native packages. On platforms such as iOS and Android, Cordova is used, which allows a developer to write a web application but still access many of the native features of a device, either through Cordova itself, or the active plugin community.

the process of creating a hosted web app

Jeff Burtoft explains hosted web apps very well on his blog and in his recent //BUILD/ presentation. The video from //BUILD 2015 showcases exactly what you can do with this technology.

My Setup

I’m doing this tutorial from a MacBook Pro running Yosemite 10.10.3, Visual Studio Code as my IDE, and MAMP as my local web server. I then use Source Tree as my Git tool of choice, and host my open-source code on GitHub, and I’ll be deploying to iOS via Xcode.

I know, a Tech Evangelist at Microsoft using Apple products and telling you about open-source tools. What is the world coming to?

Putting It All Together

The first thing I did was download the Famo.us samples from their website. I made the appropriate changes to their SlideData.js file, as I mentioned above, so that my project was able to pull in feeds from Picasa. I’ve uploaded it to GitHub so that you have a sample that works immediately. View the live site, and head to GitHub to download the working project.

Afterwards, I logged in to Azure and created a new website. You can get $200 worth of Azure trial credits, or reach out to me about a free BizSpark membership for yourself or your startup, which grants $150/month of web hosting.

I then point this new Azure website to my GitHub repo. Scott Hanselman explains how to do this in a few steps. From there, I have Azure monitor my GitHub repo for this project, and any changes I push to that repository are immediately picked up by Azure, and the latest changes can be viewed on the website and manifest project immediately.

Azure setup page

Generating the App Manifest

Next up, we need to use ManifoldJS to "wrap" our web app so that we can deploy it to the various app stores. Firefox OS and Chrome support this natively, but for iOS, Android, and Windows 8 or 10, we need to utilize Cordova. ManifoldJS will generate an app manifest file for us, which has all of the information the app stores need to get our project going.

You have two options here: Use the Manifold Web App Generator, which will provide a GUI and step-by-step instructions, or run it through the command line.

Manifold Web App Generator

Alternatively, for the command line, you need to install ManifoldJS first. Make sure you have NPM installed, and then run:

With me so far? Now we can call ManifoldJS and have it generate a folder for us with projects for each of the platforms. In the terminal I entered:

The path following -d tells ManifoldJS which directory I want it to be stored in. Soon after, you should see the terminal building the project before your eyes.

terminal building the project before your eyes

Navigate to where you stored this project, and you’ll find a series of folders there. I then navigated to cordova/platforms/iOS and looked for the file ending in xcodeproj, as I wanted to test this out in the iOS simulator. Double click on that icon to open the project in Xcode.

Navigate to where you stored this project

And there we have it, a Famo.us application running inside of Cordova on iOS.

Famous application running inside of Cordova on iOS

Wrapping It All Up

I plan to try out Angular + Famo.us in one of my upcoming demos, as well as wrapping that in ManifoldJS to test for performance on iOS. If you’re looking to debug these apps, might I suggest looking at VorlonJS? It’s platform-agnostic, takes a minute to set up, and in the link above, I illustrate how I can test apps on a desktop browser, as well as mobile devices.

I’d really like to stress test what mobile browsers are capable of when combining a framework like Famo.us and Cordova, so look for a sample involving those two soon. As the web continues to evolve, Microsoft will continue to update its dev.modern.ie/platform/status/ site to reflect changes to the new Edge browser. The most exciting announcement to me, though, is the recent switch from "in development" to "in edge" tag for asm.js. Soon we’ll be able to run native applications inside of the browser. It’s an exciting time to be working on the web.

More Hands-On With JavaScript

It might surprise you a bit, but Microsoft has a bunch of free learning on many open-source JavaScript topics, and we’re on a mission to create a lot more with Microsoft Edge.

Here are some great resources from my team and colleagues:

And some free tools to get started: Visual Studio Code, Azure Trial, and cross-browser testing tools—all available for Mac, Linux, or Windows.

This article is part of the web dev tech series from Microsoft. We’re excited to share Microsoft Edge and the new EdgeHTML rendering engine with you. Get free virtual machines or test remotely on your Mac, iOS, Android, or Windows device @ http://dev.modern.ie/.

2015-08-20T16:30:46.000Z2015-08-20T16:30:46.000ZDavid Voyles

Building a Shopping List Application With CloudKit: Introduction

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24674

In 2012, Apple introduced iCloud alongside iOS 5. At the same time, the company announced that developers would have access to iCloud through a number of APIs. Up until now, developers have had three options:

These APIs aren't perfect though. A major shortcoming is their lack of transparency. Core Data integration in particular has led to frustration and confusion among even the most experienced developers. When something went wrong, developers had no idea what or who the culprit was. It could be a problem in their code or in Apple's.

CloudKit

During last year's WWDC, Apple introduced CloudKit, a brand new framework that directly interacts with Apple's iCloud servers. The framework is comparable to a number of PaaS (Platform as a Service) solutions, such as Parse. Like Parse, Apple provides a flexible API and a dashboard that offers developers a peek into the data stored on Apple's iCloud servers.

What I like most about CloudKit is Apple's own commitment to the framework. According to the company, iCloud Drive and iCloud Photo Library are built on top of CloudKit. This shows that the CloudKit framework and infrastructure is robust and reliable.

As a developer, this sign of trust and commitment is important. In the past, Apple occasionally released APIs that were plagued by bugs or lacking key features simply because the company wasn't eating its own dog food. This isn't true for CloudKit. And that is promising.

Should You Use CloudKit

Key-value storage and document storage have their use and Apple emphasizes that CloudKit doesn't replace or deprecate existing iCloud APIs. The same is true for Core Data. CloudKit doesn't offer local storage, for example. This means that an application running on a device without a network connection is pretty much useless if it solely relies on CloudKit.

Apple also emphasizes that error handling is critical when working with CloudKit. If a save operation fails, for example, and the user isn't notified, then she may not even know that her data wasn't saved—and lost.

CloudKit is a great solution for storing structured as well as non-structured data in the cloud. If you need a solution to access data on multiple devices, then CloudKit is certainly an option to consider.

During this year's WWDC, Apple did what few developers had expected or hoped for. It announced a web service for CloudKit. This means that CloudKit can be used on virtually any platform, including Android and Windows Phone.

Apple's pricing is pretty competitive too. Getting started with CloudKit is free and it remains free for most applications. Again, CloudKit is certainly worth considering if you plan to store data in the cloud.

CloudKit Concepts

Developers struggling with Core Data are often unfamiliar with the building blocks of the framework. If you don't take the time to learn about and understand the Core Data stack, then you will inevitably run into problems. The same is true for CloudKit.

Before we start working on a sample application that uses CloudKit, I want to spend a few minutes introducing you to a number of key concepts of the CloudKit framework and infrastructure. Let's start with containers, databases, and sandboxing.

Privacy and Containment

Apple makes it very clear that privacy is an important aspect of CloudKit. The first thing to know is that each application has its own container in iCloud. This concept is very similar to how iOS applications each have their own sandbox. However, it is possible to share a container with other applications as long as those applications are associated with the same developer account. As you can imagine, this opens up a number of interesting possibilities for developers.

A CloudKit container contains several databases. Each container has one public database that can be used to store data that is accessible to every user of your application. In addition to the public database, a container also contains a private database for each user of your application. The user's private database is used to store data that is specific to that particular user. Data segregation and encapsulation is a key component of the CloudKit and iCloud infrastructure.

Even though an application's container can hold many databases, from a developer's perspective a container holds only two databases, the public database and the private database of the user that is currently signed in to their iCloud account. I'll talk more about iCloud accounts a bit later.

Records and Record Zones

The databases of an application's container store records. This isn't very different from a traditional database. At first glance, the records stored in a CloudKit database seem to be nothing more than wrappers for a dictionary of key-value pairs. They may look like glorified dictionaries, but that's only part of the story.

Each record also has a record type and a number of metadata fields. A record's metadata keeps track of when the record was created, which user created the record, when the record was last updated, and who updated the record.

The CKRecord class represents such a record and it's a pretty powerful class. The values you can store in a record aren't limited to property list types. You can store strings, numbers, dates, and blobs of data in a record, but the CKRecord class also treats location data, CLLocation, as a first-class data type.

You can even store arrays of the supported data types in a record. In other words, arrays of strings or numbers are no problem for a CKRecord instance.

Records are organized in record zones. A record zone groups related records. The public and private database each have a default record zone, but it is possible to create custom record zones if needed. Record zones are an advanced topic that we won't discuss in much detail in this series.

Relationships

Relationships between records are managed by instances of the CKReference class. Let's look at an example to better understand how exactly relationships work. The application we will create in this series will manage a number of shopping lists. Each list can have zero or more items in it. This means that each item needs to have a reference to the list it belongs to.

It's important to understand that the item keeps a reference to the list. While it is possible to create an array of CKReference instances for the items of a list, it is more convenient—and recommended—to keep the foreign key with the item, not the list. This is also what Apple recommends.

The way CloudKit manages relationships is fairly basic, but it does provide an option to automatically delete a record's children when the parent record is deleted. We'll take a closer look at relationships a bit later in this series.

Assets

I also would like to mention the CKAsset class. While it's possible to store blobs of data in a record, unstructured data, such as images, audio, and video, should be stored as CKAsset instances. A CKAsset instance is always associated with a record and it corresponds with a file on disk. We won't be working with the CKAsset class in this series.

Authentication

I'm sure you agree that CloudKit looks quite appealing. There is, however, an important detail that we haven't discussed yet, authentication. A user authenticates itself through its iCloud account. If a user isn't signed in to their iCloud account, then they're unable to write data to iCloud.

While this is true for any of the iCloud APIs, keep in mind that applications that solely rely on CloudKit won't be very functional in that case. All the user can do is access the data in the public database, if permitted by the developer.

Reading Data

If a user isn't signed in to their iCloud account, they can still read data from the public database. It goes without saying that the private database is not accessible since iCloud doesn't know who is using the application.

Reading and Writing

When signed in, the user can read and write to the public and their private database. I already mentioned that Apple takes privacy very seriously. As a result, the records stored in the private database are only accessible by the user. Even you, the developer, cannot see the data the user has stored in its private database. This is the downside of Apple managing your application's backend, but it's a definite win for the user.

Shopping List

The application we're about to build will manage your shopping lists. Each shopping list will have a name and zero or more items. After building the shopping list application, you should feel pretty comfortable using the CloudKit framework in a project of your own.

Prerequisites

For this tutorial, I will be using Xcode 7 and Swift 2. If you are using an older version of Xcode, then keep in mind that you are using a different version of the Swift programming language. This means that you will need to update the project's source code to satisfy the compiler. The changes are mostly minor, but it's important to be aware of this.

Because CloudKit is an advanced topic, I am going to assume that you are familiar with both Xcode and the Swift programming language. If you are new to iOS development, then I recommend reading an introductory tutorial first or take one of our courses on Swift development. Derek Jensen has created a course on the Swift programming language as well as a course on iOS development with Swift. Be sure to check those out if you are new to iOS development or the Swift language.

Project Setup

It's time to start writing some code. Launch Xcode and create a new project based on the Single View Application template.

Choose the Single View Application template

Give your project a name and an organization identifier. The resulting bundle identifier will be used to create the identifier of your application's default container. That identifier needs to be unique across developer accounts as they share one global namespace. It's therefore important to follow Apple's advise and use reverse domain name notation.

Configure the project

Enabling iCloud

The next step is enabling iCloud and CloudKit. Select the project in the Project Navigator on the left and select the target for your application from the list of targets. Open the General tab and set Team to the correct team. To avoid any problems in the next step, verify that your developer account has the required permissions to create an App ID.

Select the correct team

Next, open the Capabilities tab at the top and set the switch for iCloud to on. Xcode will need a moment to create an App ID on your behalf. It will also add the necessary entitlements to the App ID. If this doesn't work, then make sure the team is correctly set and you have the required permissions to create an App ID.

Enable iCloud
Xcode enables iCloud on your behalf

Enabling CloudKit is as simple as checking the checkbox labeled CloudKit. By default, your application will use the default container for your application. This container is automatically created for you when you enable CloudKit.

If your application needs access to a different container or it needs access to multiple containers, then check the checkbox labeled Specify custom containers and check the containers your application requires access to.

Enable CloudKit

You may have noticed that Xcode has automatically linked your target against the CloudKit framework. This means that you're ready to start using CloudKit in your application.

Getting Your Feet Wet

In the next tutorial of this series, we will add the ability to add, edit, and remove shopping lists. To finish this tutorial, however, I'd like to get your feet wet by showing you how to interact with the CloudKit API. All we're going to do is fetch the record of the currently signed in user.

Open ViewController.swift and add an import statement at the top to import the CloudKit framework.

To fetch the user record, we first need to fetch the record's identifier. Let's see how this works. I've created a helper method, fetchUserRecordID, to contain the logic for fetching the user's record identifier. We invoke this method in the view controller's viewDidLoad method.

The implementation of fetchUserRecordID is a bit more interesting than viewDidLoad. We first fetch a reference to the application's default container by invoking defaultContainer on the CKContainer class. We then call fetchUserRecordIDWithCompletionHandler(_:) on defaultContainer. This method accepts a closure as its only argument.

The closure accepts two arguments, an optional CKRecordID instance and an optional NSError instance. If error is nil, we safely unwrap recordID.

It's important to emphasize that the closure will be called on a background thread. This means that you need to be careful when updating the user interface of your application from within a closure invoked by CloudKit. In fetchUserRecordID, for example, I explicitly call fetchUserRecord(_:) on the main thread.

In fetchUserRecord(_:), we fetch the user record by telling CloudKit which record we're interested in. Notice that we call fetchRecordWithID(_:completionHandler:) on the privateDatabase object, a property of the defaultContainer object.

The method accepts a CKRecordID instance and a completion handler. The latter accepts an optional CKRecord instance and an NSError instance. If we successfully fetched the user record, we print it to Xcode's Console.

This should have given you a taste of the CloudKit framework. It's modern API is intuitive and easy to use. In the next tutorial, we will dig deeper in the possibilities of the CloudKit API.

Conclusion

You should now have a proper understanding of the basics of the CloudKit framework. The remainder of this series will be focused on building the shopping list application. In the next tutorial, we will start by adding the ability to add, edit, and remove shopping lists.

2015-08-21T21:15:53.000Z2015-08-21T21:15:53.000ZBart Jacobs

An Introduction to GameplayKit: Part 1

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24483

Introduction

Alongside all of the new features and frameworks in iOS 9 and OS X El Capitan, with this year's releases Apple also created an entirely new framework catered to game developers, GameplayKit. With existing graphics APIs (SpriteKit, SceneKit, and Metal) making it easy to create great looking games on iOS and OS X, Apple has now released GameplayKit to make it easy to create games that play well. This new framework contains many classes and functionalities that can be used to easily add complex logic to your games.

In this first tutorial, I will teach you about two major aspects of the GameplayKt framework:

  • entities and components
  • state machines

Prerequisites

This tutorial requires that you are running Xcode 7 on OS X Yosemite or later. While not required, it is recommended that you have a physical device running iOS 9 as you will get much better performance when testing the SpriteKit-based game used in this tutorial.

1. Getting Started

You will firstly need to download the starter project for this series of tutorials from GitHub. Once you've done this, open the project in Xcode and run it on either the iOS Simulator or your device.

You will see that it is a very basic game in which you control a blue dot and navigate around the map. When you collide with a red dot, you lose two points. When you collide with a green dot, you gain one point. When you collide with a yellow dot, your own dot becomes frozen for a couple of seconds.

Initial Game

At this stage, it is a very basic game, but throughout the course of this tutorial series, and with the help of GameplayKit, we are going to add in a lot more functionality and gameplay elements.

2. Entities and Components

The first major aspect of the new GameplayKit framework is a code-structuring concept based on entities and components. It works by allowing you, the developer, to write common code that is used by many different object types in your game while keeping it well organized and manageable. The concept of entities and components is meant to eliminate the common inheritance-based approach to share common functionality between object types. The easiest way to understand this concept is with some examples so imagine the following scenario:

You are building a tower defense game with three main types of towers, Fire, Ice, and Heal. The three types of towers would share some common data, such as health, size, and strength. Your Fire and Ice towers need to be able to target incoming enemies to shoot at whereas your Heal tower does not. All that your Heal tower needs to do is repair your other towers within a certain radius as they receive damage.

With this basic game model in mind, let's see how your code could be organized using an inheritance structure:

  • A parent Tower class containing common data such as health, size, and strength.
  • FireTowerIceTower, and HealTower classes that would inherit from the Tower class.
  • In the HealTower class, you have the logic responsible for healing your other towers within a certain radius.

So far, this structure is okay, but a problem now arises when you need to implement the Fire and Ice towers' targeting ability. Do you just copy and paste the same code into both of your FireTower and IceTower classes? If you need to make any changes, you will then need to change your code in more than one place, which is tedious and error-prone. On top of this, what happens if you want to add in a new tower type that also needs this targeting functionality. Do you copy and paste it a third time?

The best way seems to be to put this targeting logic in the parent Tower class. This would allow you to just have one copy of the code that only needs to be edited in one place. Adding this code here, however, would make the Tower class a lot larger and more complicated than it needs to be when not all of its subclasses need that functionality. If you also wanted to add more shared functionality between your tower types, your Tower class would gradually become larger and larger, which would make it hard to work with.

As you can see, while it is possible to create a game model based on inheritance, it can very quickly and easily become unorganized and difficult to manage.

Now, let's see how this same game model could be structured using entities and components:

  • We would create FireTowerIceTower, and HealTower entities. More entities could be created for any more tower types you want to add later on.
  • We'd also create a BasicTower component that would contain health, size, strength, etc.
  • To handle the healing of your towers within a certain radius, we'd add a Healing component.
  • Targeting component would contain the code needed to target incoming enemies.

Using GameplayKit and this structure you would then have a unique entity type for each tower type in your game. To each individual entity, you can add the desired components that you want. For example:

  • Your FireTower and IceTower entities would each have a BasicTower and Targeting component linked to it.
  • Your HealTower entity would have both a BasicTower and a Healing component.

As you can see, by using an entity- and component-based structure, your game model is now a lot simpler and more versatile. Your targeting logic only needs to be written once and only links to the entities that it needs to. Likewise, your basic tower data can still be easily shared between all of your towers without bulking up all of your other common functionality.

Another great thing about this entity- and component-based structure is that components can be added to and removed from entities whenever you want. For example, if you wanted your Heal towers to be disabled under certain conditions, you could simply remove the Healing component from your entity until the right conditions are met. Likewise, if you wanted one of your Fire towers to gain a temporary healing ability, you could just add a Healing component to your FireTower entity for a specific amount of time.

Now that you are comfortable with the concept of an entity- and component-based game model structure, let's create one within our own game. In Xcode's File Inspector, find the Entities folder within your project. For convenience, there are already three entity classes for you, but you are now going to create a new entity from scratch.

Choose File > New > File... or press Command-N to create a new class. Make sure to select the Cocoa Touch Class template from the iOS > Source section. Name the class Player and make it a subclass of GKEntity.

Creating a player entity

You will see that immediately upon opening your new file Xcode will display an error. To fix this, add the following import statement below the existing import UIKit statement:

Go back to PlayerNode.swift and add the following property to the PlayerNode class:

Next, navigate to the Components folder in your Xcode project and create a new class just as you did before. This time, name the class FlashingComponent and make it a subclass of GKComponent as shown below.

Creating a flashing component

The component you've just created is going to handle the visual flashing of our blue dot when it is hit by a red dot and is in its invulnerable state. Replace the contents of FlashingComponent.swift with the following:

The implementation simply keeps a reference to an SKNode object and repeats fade in and fade out actions in sequence as long as the component is active.

Go back to GameScene.swift and add the following code somewhere within the didMoveToView(_:) method:

We create a FlashingComponent object and set it up to perform its flashing on the player's dot. The last line then adds the component to the entity to keep it active and executing.

Build and run your app. You will now see that your blue dot slowly fades in and out repeatedly.

Fading blue dot

Before moving on, delete the code that you just added from the didMoveToView(_:) method. Later, you will be adding this code back but only when your blue dot enters its invulnerable state.

3. State Machines

In GameplayKit, state machines provide a way for you to easily identify and perform tasks based on the current state of a particular object. Drawing from the earlier tower defense example, some possible states for each tower could include Active, Disabled, and Destroyed. One major advantage of state machines is that you can specify which states another state can move to. With the three example states mentioned above, using a state machine, you could set the state machine up so that:

  • a tower can become Disabled when Active and vice versa
  • a tower can become Destroyed when either Active or Disabled
  • a tower can not become Active or Disabled once it has been Destroyed

In the game for this tutorial, we are going to keep it very simple and only have a normal and invulnerable state.

In your project's State Machine folder, create two new classes. Name them NormalState and InvulnerableState respectively, with both being a subclass of the GKState class.

Creating an invulnerable state class

Replace the contents of NormalState.swift with the following:

The NormalState class contains the following:

  • It implements a simple initializer to keep a reference to the current player's node.
  • It has an implementation for the isValidNextState(_:) method. This method's implementation returns a boolean value, indicating whether or not the current state class can move to the state class provided by the method parameter.
  • The class also includes an implementation for the didEnterWithPreviousState(_:) callback method. In the method's implementation, we check if the previous state was the InvulnerableState state and, if true, remove the flashing component from the player's entity.

Now open InvulnerableState.swift and replace its contents with the following:

The InvulnerableState class is very similar to the NormalState class. The main difference is that upon entering this state you add the flashing component to the player's entity rather than removing it.

Now that your state classes are both complete, open PlayerNode.swift again and add the following lines to the PlayerNode class:

This code snippet adds a new property to the PlayerNode class and implements a convenience method to go back to the normal state.

Now open GameScene.swift and, at the end of the didMoveToView(_:) method, add the following two lines:

In these two lines of code, we create a new GKStateMachine with the two states and tell it to enter the NormalState.

Finally, replace the implementation of the handleContactWithNode(_:) method of the GameScene class with the following implementation:

When the player's blue dot collides with a red enemy dot, the player will enter the InvulnerableState state for five seconds and then revert back to the NormalState state. We also check what the current state of the player is and only perform any enemy-related logic if it is the NormalState state.

Build and run your app one last time, and move around the map until you find a red dot. When you collide with the red dot, you will see that your blue dot enters its invulnerable state and flashes for five seconds.

Entering the invulnerable state

Conclusion

In this tutorial, I introduced you to two of the major aspects of the GameplayKit framework, entities and components, and state machines. I showed you how you can use entities and components to structure your game model and keep everything organized. Using components is a very easy way to share functionality between objects in your games.

I also showed you the basics of state machines, including how you can specify which states a particular state can transition to as well as executing code when a particular state is entered.

Stay tuned for the second part of this series where we are going to take this game to another level by adding in some artificial intelligence, better known as AI. The AI will enable enemy dots to target the player and find the best path to reach the player.

As always, if you have any comments or questions, leave them in the comments below.

2015-08-24T17:30:53.000Z2015-08-24T17:30:53.000ZDavis Allie

watchOS 2: Communicating With a Counterpart

$
0
0

Ever since the release of Apple Watch, developers have been debating and presenting techniques to overcome the limitations of watchOS 1. Developers have wondered, for example, how to reliably communicate between a watchOS app and its parent iOS app, and vice versa.

A number of solutions have been available to solve this problem, such as MMWormhole. Of course, Apple has been well aware of the limitations of watchOS 1 and the release of watchOS 2 resolves a number of the limitations of watchOS 1. Communicating between a watchOS 2 app and its parent iOS app, for example, has become much simpler thanks to the introduction of the Watch Connectivity framework.

Watch Connectivity

The Watch Connectivity framework provides several ways to communicate between an iOS and a watchOS 2 app. With the Watch Connectivity framework, you can update information on a counterpart, send messages, transfer data in the background, and even transfer files. To learn more about all the framework's features and capabilities, I recommend browsing Apple's documentation for the Watch Connectivity framework.

In this tutorial, I will show you how to exchange data between a watchOS 2 app and its parent iOS app, and vice versa. The API we'll use to accomplish this is sendMessage(_:replyHandler:errorHandler:). This method lets developers transfer data between the watchOS 2 app and its parent iOS app.

It's important to note that the iOS and the watchOS 2 app respond differently when sendMessage(_:replyHandler:errorHandler:) is invoked. If this method is invoked by the watchOS 2 app, the iOS app will be woken up by the operating system. If you send data from the parent iOS app to the watchOS 2 app, however, the latter will not wake up. This is an important detail to keep in mind.

Prerequisites

Since this tutorial is about Apple Watch development, I assume that you're already familiar with iOS development and the Swift programming language. The Watch Connectivity framework is only available on watchOS 2, which means that you need to have the latest version of Xcode installed, Xcode 7. You can download Xcode from Apple's developer website.

1. Project Setup

Open Xcode and select New > Project... from the File menu. Go to watchOS> Application, select the iOS App with WatchKit App project template and click Next. Name your app SendMessageWatch, set Language to Swift, and Devices to iPhone. Uncheck Include Notification Scene and make sure that every checkbox at the bottom is unchecked. Hit Next and choose a location to save your project.

Creating the Xcode project

2. Creating the User Interface

In this step, we'll add a label and a button to both apps. The label will be used to display the messages we're sending while the button will send the message to the counterpart, the iOS app or the watchOS 2 app.

We'll start with the iOS app. Open Main.storyboard and add a label and a button. Next, create an outlet for both user interface elements, and add an action for the button. The below screenshot shows the result.

iOS App - Creating Controls and Connect IBOutlets and IBAction

Let's now focus on the watchOS 2 app. Open Interface.storyboard and add a label and a button to the scene. Next, open InterfaceController.swift in the Assistant Editor and create an outlet for the label and the button, and add an action for the button.

Watch App - Creating Controls and Connect IBOutlets and IBAction

With the user interface in place, it's time to zoom in on the main topic of this tutorial, sending messages from the iOS app to the watchOS 2 app, and vice versa.

3. Using the Watch Connectivity Framework

Using the Watch Connectivity framework to exchange messages requires the use of the WCSession class. For this to work, both the iOS app and the watchOS 2 app must create and configure a WCSession instance. When the session is configured, we can communicate immediately back and forth.

We obtain an instance of the WCSession class by calling the defaultSession class method. This returns the singleton session object for the device. We then need to set the session's delegate and activate the session.

Before we configure and use the WCSession object, we need to verify that the WCSession class is supported on the device. We do this by calling the isSupported class method on the WCSession class. We do all this in the willActivate method of the InterfaceController class. Note that activateSession will throw an exception if the session's delegate is nil. In other words, the order of the below statements is important.

The watchOS 2 app is now able to send and receive messages. With the session activated, we just need to invoke the sendMessage(_:replyHandler:errorHandler:) method to send messages. The first argument needs to be a dictionary of type [String : AnyObject] and it should not be nil.

The replyHandler is a closure that accepts a dictionary of the same type. This dictionary is the response from the counterpart. The errorHandler is also a closure, which can be nil if you don't need to catch any errors.

If we hit the send button on the Apple Watch, it will immediately send a Hello iPhone message and the iPhone will reply with a Hello Watch message. After hitting the send button on the iPhone, it will send a question Hi watch, can you talk to me? and the Apple Watch will answer with Yes.

This is what the implementation of the sendMessage method should look like in InterfaceController.swift.

To handle the message on the iOS device, we need to implement thesession(_:didReceiveMessage:) delegate method of the WCSessionDelegate protocol, which is invoked when a message is received by the counterpart. This is what the implementation looks like in InterfaceController.swift.

The implementation of both methods looks very similar for the iOS app. With the above implementations, give it a try by implementing the sendMessage and session(_:didReceiveMessage:replyHandler:) methods. This is what the implementation of the ViewController class should look like.

Build and run the apps to see the final result. When you tap the button on Apple Watch, a message should appear on the paired iPhone running the iOS app. When you tap the button of the iOS app, a message should appear on Apple Watch running the watchOS 2 app.

Final Result

4. Exploring the WCSessionDelegate Protocol

The delegate method we implemented to receive the message has a simpler sibling, session(_:didReceiveMessage:). This method is called when sendMessage(_:replyHandler:errorHandler:) is invoked without a reply handler. This simply indicates that the app sending the message doesn't expect a response.

In addition to sending a dictionary to a counterpart, it's also possible to send a NSData object using the sendMessageData(_:replyHandler:errorHandler:) method. The counterpart receives the message through the session(_:didReceiveMessageData:) and session(_:didReceiveMessageData:replyHandler:) delegate methods of the WCSessionDelegate protocol.

Conclusion

If you need to communicate immediately with a counterpart, then the Watch Connectivity framework is the best choice on watchOS 2. The messages are queued and delivered in the same order that they were sent in.

The Watch Connectivity framework has a lot more to offer than what is covered in this tutorial. In future tutorials, we will dive deeper into this new framework to further explore its features and capabilities.

2015-08-26T15:45:05.000Z2015-08-26T15:45:05.000ZJorge Costa

watchOS 2: Communicating With a Counterpart

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24372

Ever since the release of Apple Watch, developers have been debating and presenting techniques to overcome the limitations of watchOS 1. Developers have wondered, for example, how to reliably communicate between a watchOS app and its parent iOS app, and vice versa.

A number of solutions have been available to solve this problem, such as MMWormhole. Of course, Apple has been well aware of the limitations of watchOS 1 and the release of watchOS 2 resolves a number of the limitations of watchOS 1. Communicating between a watchOS 2 app and its parent iOS app, for example, has become much simpler thanks to the introduction of the Watch Connectivity framework.

Watch Connectivity

The Watch Connectivity framework provides several ways to communicate between an iOS and a watchOS 2 app. With the Watch Connectivity framework, you can update information on a counterpart, send messages, transfer data in the background, and even transfer files. To learn more about all the framework's features and capabilities, I recommend browsing Apple's documentation for the Watch Connectivity framework.

In this tutorial, I will show you how to exchange data between a watchOS 2 app and its parent iOS app, and vice versa. The API we'll use to accomplish this is sendMessage(_:replyHandler:errorHandler:). This method lets developers transfer data between the watchOS 2 app and its parent iOS app.

It's important to note that the iOS and the watchOS 2 app respond differently when sendMessage(_:replyHandler:errorHandler:) is invoked. If this method is invoked by the watchOS 2 app, the iOS app will be woken up by the operating system. If you send data from the parent iOS app to the watchOS 2 app, however, the latter will not wake up. This is an important detail to keep in mind.

Prerequisites

Since this tutorial is about Apple Watch development, I assume that you're already familiar with iOS development and the Swift programming language. The Watch Connectivity framework is only available on watchOS 2, which means that you need to have the latest version of Xcode installed, Xcode 7. You can download Xcode from Apple's developer website.

1. Project Setup

Open Xcode and select New > Project... from the File menu. Go to watchOS> Application, select the iOS App with WatchKit App project template and click Next. Name your app SendMessageWatch, set Language to Swift, and Devices to iPhone. Uncheck Include Notification Scene and make sure that every checkbox at the bottom is unchecked. Hit Next and choose a location to save your project.

Creating the Xcode project

2. Creating the User Interface

In this step, we'll add a label and a button to both apps. The label will be used to display the messages we're sending while the button will send the message to the counterpart, the iOS app or the watchOS 2 app.

We'll start with the iOS app. Open Main.storyboard and add a label and a button. Next, create an outlet for both user interface elements, and add an action for the button. The below screenshot shows the result.

iOS App - Creating Controls and Connect IBOutlets and IBAction

Let's now focus on the watchOS 2 app. Open Interface.storyboard and add a label and a button to the scene. Next, open InterfaceController.swift in the Assistant Editor and create an outlet for the label and the button, and add an action for the button.

Watch App - Creating Controls and Connect IBOutlets and IBAction

With the user interface in place, it's time to zoom in on the main topic of this tutorial, sending messages from the iOS app to the watchOS 2 app, and vice versa.

3. Using the Watch Connectivity Framework

Using the Watch Connectivity framework to exchange messages requires the use of the WCSession class. For this to work, both the iOS app and the watchOS 2 app must create and configure a WCSession instance. When the session is configured, we can communicate immediately back and forth.

We obtain an instance of the WCSession class by calling the defaultSession class method. This returns the singleton session object for the device. We then need to set the session's delegate and activate the session.

Before we configure and use the WCSession object, we need to verify that the WCSession class is supported on the device. We do this by calling the isSupported class method on the WCSession class. We do all this in the willActivate method of the InterfaceController class. Note that activateSession will throw an exception if the session's delegate is nil. In other words, the order of the below statements is important.

The watchOS 2 app is now able to send and receive messages. With the session activated, we just need to invoke the sendMessage(_:replyHandler:errorHandler:) method to send messages. The first argument needs to be a dictionary of type [String : AnyObject] and it should not be nil.

The replyHandler is a closure that accepts a dictionary of the same type. This dictionary is the response from the counterpart. The errorHandler is also a closure, which can be nil if you don't need to catch any errors.

If we hit the send button on the Apple Watch, it will immediately send a Hello iPhone message and the iPhone will reply with a Hello Watch message. After hitting the send button on the iPhone, it will send a question Hi watch, can you talk to me? and the Apple Watch will answer with Yes.

This is what the implementation of the sendMessage method should look like in InterfaceController.swift.

To handle the message on the iOS device, we need to implement thesession(_:didReceiveMessage:) delegate method of the WCSessionDelegate protocol, which is invoked when a message is received by the counterpart. This is what the implementation looks like in InterfaceController.swift.

The implementation of both methods looks very similar for the iOS app. With the above implementations, give it a try by implementing the sendMessage and session(_:didReceiveMessage:replyHandler:) methods. This is what the implementation of the ViewController class should look like.

Build and run the apps to see the final result. When you tap the button on Apple Watch, a message should appear on the paired iPhone running the iOS app. When you tap the button of the iOS app, a message should appear on Apple Watch running the watchOS 2 app.

Final Result

4. Exploring the WCSessionDelegate Protocol

The delegate method we implemented to receive the message has a simpler sibling, session(_:didReceiveMessage:). This method is called when sendMessage(_:replyHandler:errorHandler:) is invoked without a reply handler. This simply indicates that the app sending the message doesn't expect a response.

In addition to sending a dictionary to a counterpart, it's also possible to send a NSData object using the sendMessageData(_:replyHandler:errorHandler:) method. The counterpart receives the message through the session(_:didReceiveMessageData:) and session(_:didReceiveMessageData:replyHandler:) delegate methods of the WCSessionDelegate protocol.

Conclusion

If you need to communicate immediately with a counterpart, then the Watch Connectivity framework is the best choice on watchOS 2. The messages are queued and delivered in the same order that they were sent in.

The Watch Connectivity framework has a lot more to offer than what is covered in this tutorial. In future tutorials, we will dive deeper into this new framework to further explore its features and capabilities.

2015-08-26T15:45:05.000Z2015-08-26T15:45:05.000ZJorge Costa

Building a Shopping List Application With CloudKit: Adding Records

$
0
0

In the first tutorial of this series, we explored the CloudKit framework and infrastructure. We also laid the foundation for the sample application that we're going to build, a shopping list application. In this tutorial, we are focusing on adding, editing, and removing shopping lists.

Prerequisites

As I mentioned in the previous tutorial, I will be using Xcode 7 and Swift 2. If you are using an older version of Xcode, then keep in mind that you are using a different version of the Swift programming language.

In this tutorial, we will continue working with the project we created in the first tutorial. You can download it from GitHub.

1. Setting Up CocoaPods

The shopping list application will make use of the SVProgressHUD library, a popular library created by Sam Vermette that makes it easy to display a progress indicator. You can add the library manually to your project, but I strongly recommend using CocoaPods for managing dependencies. Are you new to CocoaPods? I've written an introductory tutorial to CocoaPods that will help you get up to speed.

Step 1: Creating a Podfile

Open Finder and navigate to the root of your Xcode project. Create a new file, name it Podfile, and add the following lines of Ruby to it.

The first line specifies the platform, iOS, and the project's deployment target, iOS 8.0. The second line is important if you're using Swift. Swift does not support static libraries, but CocoaPods does provide the option since version 0.36 to use frameworks. We then specify the dependencies for the Lists target of the project. Replace Lists with your target's name if your target is named differently.

Step 2: Installing Dependencies

Open Terminal, navigate to the root of your Xcode project, and run pod install. This will do a number of things for you, such as installing the dependencies specified in Podfile and creating an Xcode workspace.

After completing the CocoaPods setup, close the project and open the workspace CocoaPods created for you. The latter is very important. Open the workspace, not the project. The workspace includes two projects, the Lists project and a project named Pods.

2. Listing Shopping Lists

Step 1: Housekeeping

We're ready to refocus on the CloudKit framework. First, however, we need to do some housekeeping by renaming the ViewController class to the ListsViewController class.

Start by renaming ViewController.swift to ListsViewController.swift. Open ListsViewController.swift and change the name of the ViewController class to the ListsViewController class.

Next, open Main.storyboard, expand View ControllerScene in the Document Outline on the left and select View Controller. Open the Identity Inspector on the right and change Class to ListsViewController.

Step 2: Adding a Table View

When the user opens the application, it is presented with their shopping lists. We'll display the shopping lists in a table view. Let's start by setting up the user interface. Select the Lists View Controller in the Lists View Controller Scene and choose Embed In > Navigation Controller from Xcode's Editor menu.

Add a table view to the view controller's view and create the necessary layout constraints for it. With the table view selected, open the Attributes Inspector and set Prototype Cells to 1. Select the prototype cell and set Style to Basic and Identifier to ListCell.

With the table view selected, open the Connections Inspector. Connect the table view's dataSource and delegate outlets to the Lists View Controller.

Step 3: Empty State

Even though we're only creating a sample application to illustrate how CloudKit works, I'd like to display a message if something goes wrong or if no shopping lists were found on iCloud. Add a label to the view controller, make it as large as the view controller's view, create the necessary layout constraints for it, and center the label's text.

Since we're dealing with network requests, I also want to display an activity indicator view as long as the application is waiting for a response from iCloud. Add a activity indicator view to the view controller's view and center it in its parent view. In the Attributes Inspector, tick the checkbox labeled Hides When Stopped.

Lists View Controller

Step 4: Connecting Outlets

Open ListsViewController.swift and declare an outlet for the label, the table view, and the activity indicator view. This is also a good time to make the ListsViewController class conform to the UITableViewDataSource and UITableViewDelegate protocols.

Note that I've also added an import statement for the SVProgressHUD framework and that I've declared a static constant for the reuse identifier of the prototype cell we created in the storyboard.

Head back to the storyboard and connect the outlets with the corresponding views in the Lists View Controller Scene.

Step 5: Preparing the Table View

Before we fetch data from iCloud, we need to make sure the table view is ready to display the data. We first need to create a property, lists, to hold the records we're about to fetch. Remember that records are instances of the CKRecord class. This means the property that will hold the data from iCloud is of type [CKRecord], an array of CKRecord instances.

To get started, we need to implement three methods of the UITableViewDataSource protocol:

  • numberOfSectionsInTableView(_:)
  • numberOfRowsInSection(_:)
  • cellForRowAtIndexPath(_:)

If you have any experience working with table views, then the implementation of each of these methods is straightforward. However, cellForRowAtIndexPath(_:) may require some explanation. Remember that a CKRecord instance is a supercharged dictionary of key-value pairs. To access the value of a particular key, you invoke objectForKey(_:) on the CKRecord object. That's what we do in cellForRowAtIndexPath(_:). We fetch the record that corresponds with the table view row and ask it for the value for key "name". If the key-value pair doesn't exist, we display a dash to indicate the list doesn't have a name yet.

Step 6: Preparing the User Interface

There's one more step for us to take, prepare the user interface. In the view controller's viewDidLoad method, remove the fetchUserRecordID method call and invoke setupView, a helper method.

The setupView method prepares the user interface for fetching the list of records. We hide the label and the table view, and tell the activity indicator view to start animating.

Build and run the application on a device or in the iOS Simulator. If you've followed the above steps, you should see an empty view with a spinning activity indicator view in the center.

Busy Pretending to Be Fetching Data

Step 7: Creating a Record Type

Before we fetch any records, we need to create a record type for a shopping list in the CloudKit dashboard. The CloudKit dashboard is a web application that lets developers manage the data stored on Apple's iCloud servers.

Select the project in the Project Navigator and choose the Lists target from the list of targets. Open the Capabilities tab at the top and expand the iCloud section. Below the list of iCloud containers, click the button labeled CloudKit Dashboard.

Open CloudKit Dashboard

Sign in with your developer account and make sure the Lists application is selected in the top left. On the left, select Record Types from the Schema section. Every application has by default a Users record type. To create a new record type, click the plus button at the top of the third column. We will follow Apple's naming convention and name the record type Lists, not List.

Adding a New Record Type

Note that the first field is automatically created for you. Set Field Name to name and verify that Field Type is set to String. Don't forget to click the Save button at the bottom to create the Lists record type. We'll revisit the CloudKit Dashboard later in this series.

Step 8: Performing a Query

With the Lists record type created, it's finally time to fetch some records from iCloud. The CloudKit framework provides two APIs to interact with iCloud, a convenience API and an API based on the NSOperation class. We will use both APIs in this series, but we're going to keep it simple for now and use the convenience API.

In Xcode, open ListsViewController.swift and invoke the fetchLists method in viewDidLoad. The fetchLists method is another helper method. Let's take a look at the method's implementation.

Because a shopping list record is stored in the user's private database, we first get a reference to the default container's private database. To fetch the user's shopping lists, we need to perform a query on the private database, using the CKQuery class.

We initialize a CKQuery instance by invoking the init(recordType:predicate:) designated initializer, passing in the record type and an NSPredicate object. To avoid typos, I've created a constant for the record type. The constant, RecordTypeLists, is declared at the top of ListsViewController.swift.

Before we execute the query, we set the query's sortDescriptors property. We create an array containing an NSSortDescriptor object with key "name" and ascending set to true.

Executing the query is as simple as calling performQuery(_:inZoneWithID:completionHandler:) on privateDatabase, passing in query as the first argument. The second parameter specifies the identifier of the record zone on which the query will be performed. By passing in nil, the query is performed on the default zone of the database.

The third argument is a completion handler. The closure accepts an optional array of CKRecord objects and an optional NSError instance. The CloudKit documentation explicitly mentions that the completion handler can be invoked from any thread. We therefore dispatch the processing of the response to the main thread by wrapping the processResponseForQuery(_:error:) method call in a dispatch_async closure. That's how easy it is to perform a query. Let's see how we handle the query's response.

Step 9: Processing the Response

The implementation of processResponseForQuery(_:error:) isn't difficult if you're familiar with the Swift language. We inspect the contents of the records and error parameters, and update the message variable accordingly.

At the end of the method, we invoke updateView. In this helper method, we update the user interface based on the contents of the lists property.

Build and run the application to test what we've got so far. We currently don't have any records, but we'll fix that in the next section of this tutorial.

No Records Found

3. Adding a Shopping List

Step 1: Creating the AddListViewController Class

Because adding and editing a shopping list are very similar, we are going to implement both at the same time. Create a new file and name it AddListViewController.swift. Open the newly created file and create a UIViewController subclass named AddListViewController. At the top, add import statements for the UIKit, CloudKit, and SVProgressHUD framework. Declare two outlets, one of type UITextField! and one of type UIBarButtonItem!. Last but not least, create two actions, cancel(_:) and save(_:).

Step 2: Creating the User Interface

Open Main.storyboard and add a view controller to the storyboard. With the view controller selected, open the Identity Inspector on the right and set Class to AddListViewController.

The user will be able to navigate to the add list view controller by tapping a button in the lists view controller. Drag a bar button item from the Object Library to the navigation bar of the lists view controller. With the bar button item selected, open the Attributes Inspector and set System Item to Add. Press Control and drag from the bar button item to the add list view controller and select push from the menu that appears.

It's important that you choose push from the Action Segue section. It should be the first item in the menu. Select the segue you jus created and set Identifier to ListDetail in the Attributes Inspector on the right.

Add two bar button items to the navigation bar of the add list view controller, one on the left and one on the right. Set System Item of the left bar button item to Cancel and that of the right bar button item to Save. Finally, add a text field to the add list view controller. Center the text field and set its Alignment to center in the Attributes Inspector.

Add List View Controller

It is possible that, after creating the segue from the lists view controller to the add list view controller, no navigation item was created for the Add List View Controller Scene. I believe this is a bug in Xcode 7.

To resolve this issue, select the segue and, in the Attributes Inspector, set Segue to Deprecated Segues > Push. This will add a navigation item to the scene. Next, set Segue back to Adaptive Segues > Show.

Finally, connect the outlets and actions you created in AddListViewController.swift to the corresponding user interface elements in the scene.

Step 3: AddListViewControllerDelegate Protocol

Before we implement the AddListViewController class, we need to declare a protocol that we'll use to communicate from the add list view controller to the lists view controller. The protocol defines two methods, one for adding and one for updating a shopping list. This is what the protocol looks like.

We also need to declare three properties, one for the delegate, one for the shopping list that is created or updated, and a helper variable that indicates whether we're creating a new shopping list or editing an existing record.

The implementation of the AddListViewController class is no rocket science. The methods related to the view life cycle are short and easy to understand. In viewDidLoad, we first invoke the setupView helper method. We'll implement this method in a moment. We then update the value of the newList helper variable based on the value of the list property. If list is equal to nil, then we know that we're creating a new record. In viewDidLoad, we also add the view controller as an observer for UITextFieldTextDidChangeNotification notifications.

In viewDidAppear(_:), we call becomeFirstResponder on the text field to present the keyboard to the user.

In setupView, we invoke two helper methods, updateNameTextField and updateSaveButton. In updateNameTextField, we populate the text field if list is not nil. In other words, if we're editing an existing record, then we populate the text field with the name of that record.

The updateSaveButton method is in charge of enabling and disabling the bar button item in the top right. We only enable the save button if the name of the shopping list is not an empty string.

Step 4: Implementing Actions

The cancel(_:) action is as simple as it gets. We pop the top view controller from the navigation stack. The save(_:) action is more interesting. In this method, we extract the user's input from the text field and get a reference to the default container's private database.

If we're adding a new shopping list, then we create a new CKRecord instance by invoking init(recordType:), passing in RecordTypeLists as the record type. We then update the name of the shopping list by setting the value of the record for the key "name".

Because saving a record involves a network request and can take a non-trivial amount of time, we show a progress indicator. To save a new record or any changes to an existing record, we call saveRecord(_:completionHandler:) on privateDatabase, passing in the record as the first argument. The second argument is another completion handler that is invoked when saving the record completes, successfully or unsuccessfully.

The completion handler accepts two arguments, an optional CKRecord and an optional NSError. As I mentioned before, the completion handler can be invoked on any thread, which means that we need to code against that. We do this by explicitly invoking the processResponse(_:error:) method on the main thread.

In processResponse(_:error:), we verify if an error was thrown. If we did run into problems, we display an alert to the user. If everything went smoothly, we notify the delegate and pop the view controller from the navigation stack.

Last but not least, when the view controller receives a UITextFieldTextDidChangeNotification notification, it invokes updateSaveButton to update the save button.

Step 5: Tying Everything Together

In the ListsViewController class, we still need to take care of a few things. Let's start by conforming the class to the AddListViewControllerDelegate protocol.

This also means that we need to implement the methods of the AddListViewControllerDelegate protocol. In the controller(_:didAddList:) method, we add the new record to the array of CKRecord objects. We then sort the array of records, reload the table view, and invoke updateView on the view controller.

The sortLists method is pretty basic. We call sortInPlace on the array of records, sorting the array based on the record's name.

The implementation of the second method of the AddListViewControllerDelegate protocol, controller(_:didUpdateList:), looks almost identical. Because we're not adding a record, we only need to sort the array of records and reload the table view. There's no need to call updateView on the view controller since the array of records is, by definition, not empty.

To edit a record, the user needs to tap the accessory button of a table view row. This means that we need to implement the tableView(_:accessoryButtonTappedForRowWithIndexPath:) method of the UITableViewDelegate protocol. Before we implement this method, declare a helper property, selection, to store the user's selection.

In tableView(_:accessoryButtonTappedForRowWithIndexPath:), we store the user's selection in selection and tell the view controller to perform the segue that leads to the add list view controller. If you're curious, I've created a constant in ListsViewController.swift for the segue identifier, SegueListDetail.

We're almost there. When the segue with identifier ListDetail is performed, we need to configure the AddListViewController instance that is pushed onto the navigation stack. We do this in prepareForSegue(_:sender:?).

The segue hands us a reference to the destination view controller, the AddListViewController instance. We set the delegate property, and, if a shopping list is updated, we set the view controller's list property to the selected record.

Build and run the application to see the result. You should now be able to add a new shopping list and edit the name of existing shopping lists.

4. Deleting Shopping Lists

Adding the ability to delete shopping lists isn't much extra work. The user should be able to delete a shopping list by swiping a table view row from right to left and tapping the delete button that is revealed. To make this possible, we need to implement two more methods of the UITableViewDataSource protocol:

  • tableView(_:canEditRowAtIndexPath:)
  • tableView(_:commitEditingStyle:forRowAtIndexPath:)

The implementation of tableView(_:canEditRowAtIndexPath:) is trivial as you can see below.

In tableView(_:commitEditingStyle:forRowAtIndexPath:), we fetch the correct record from the array of records and invoke deleteRecord(_:) on the view controller, passing in the record that needs to be deleted.

The deleteRecord(_:) method should look familiar by now. We show a progress indicator and call deleteRecordWithID(_:completionHandler:) on the default container's private database. Note that we're passing in the record identifier, not the record itself. The completion handler accepts two arguments, an optional CKRecordID and an optional NSError.

In the completion handler, we dismiss the progress indicator and invoke processResponseForDeleteRequest(_:recordID:error:) on the main thread. In this method, we inspect the values of recordID and error that the CloudKit API has given us and we update message accordingly. If the delete request was successful, then we update the user interface and the array of records.

That's it. It's time to properly test the application with some data. Run the application on a device or in the iOS Simulator and add a few shopping lists. You should be able to add, edit, and delete shopping lists.

Conclusion

Even though this article is fairly long, it's good to remember that we only briefly interacted with the CloudKit API. The convenience API of the CloudKit framework is lightweight and easy to use.

This tutorial, however, has also illustrated that your job as a developer isn't limited to interacting with the CloudKit API. It's important to handle errors, show the user when a request is in progress, update the user interface, and tell the user what is going on.

In the next article of this series, we take a closer look at relationships by adding the ability to fill a shopping list with items. An empty shopping list isn't of much use and it certainly isn't fun. Leave any questions you have in the comments below or reach out to me on Twitter.

2015-08-28T21:30:35.000Z2015-08-28T21:30:35.000ZBart Jacobs

Building a Shopping List Application With CloudKit: Adding Records

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24731

In the first tutorial of this series, we explored the CloudKit framework and infrastructure. We also laid the foundation for the sample application that we're going to build, a shopping list application. In this tutorial, we are focusing on adding, editing, and removing shopping lists.

Prerequisites

As I mentioned in the previous tutorial, I will be using Xcode 7 and Swift 2. If you are using an older version of Xcode, then keep in mind that you are using a different version of the Swift programming language.

In this tutorial, we will continue working with the project we created in the first tutorial. You can download it from GitHub.

1. Setting Up CocoaPods

The shopping list application will make use of the SVProgressHUD library, a popular library created by Sam Vermette that makes it easy to display a progress indicator. You can add the library manually to your project, but I strongly recommend using CocoaPods for managing dependencies. Are you new to CocoaPods? I've written an introductory tutorial to CocoaPods that will help you get up to speed.

Step 1: Creating a Podfile

Open Finder and navigate to the root of your Xcode project. Create a new file, name it Podfile, and add the following lines of Ruby to it.

The first line specifies the platform, iOS, and the project's deployment target, iOS 8.0. The second line is important if you're using Swift. Swift does not support static libraries, but CocoaPods does provide the option since version 0.36 to use frameworks. We then specify the dependencies for the Lists target of the project. Replace Lists with your target's name if your target is named differently.

Step 2: Installing Dependencies

Open Terminal, navigate to the root of your Xcode project, and run pod install. This will do a number of things for you, such as installing the dependencies specified in Podfile and creating an Xcode workspace.

After completing the CocoaPods setup, close the project and open the workspace CocoaPods created for you. The latter is very important. Open the workspace, not the project. The workspace includes two projects, the Lists project and a project named Pods.

2. Listing Shopping Lists

Step 1: Housekeeping

We're ready to refocus on the CloudKit framework. First, however, we need to do some housekeeping by renaming the ViewController class to the ListsViewController class.

Start by renaming ViewController.swift to ListsViewController.swift. Open ListsViewController.swift and change the name of the ViewController class to the ListsViewController class.

Next, open Main.storyboard, expand View ControllerScene in the Document Outline on the left and select View Controller. Open the Identity Inspector on the right and change Class to ListsViewController.

Step 2: Adding a Table View

When the user opens the application, it is presented with their shopping lists. We'll display the shopping lists in a table view. Let's start by setting up the user interface. Select the Lists View Controller in the Lists View Controller Scene and choose Embed In > Navigation Controller from Xcode's Editor menu.

Add a table view to the view controller's view and create the necessary layout constraints for it. With the table view selected, open the Attributes Inspector and set Prototype Cells to 1. Select the prototype cell and set Style to Basic and Identifier to ListCell.

With the table view selected, open the Connections Inspector. Connect the table view's dataSource and delegate outlets to the Lists View Controller.

Step 3: Empty State

Even though we're only creating a sample application to illustrate how CloudKit works, I'd like to display a message if something goes wrong or if no shopping lists were found on iCloud. Add a label to the view controller, make it as large as the view controller's view, create the necessary layout constraints for it, and center the label's text.

Since we're dealing with network requests, I also want to display an activity indicator view as long as the application is waiting for a response from iCloud. Add a activity indicator view to the view controller's view and center it in its parent view. In the Attributes Inspector, tick the checkbox labeled Hides When Stopped.

Lists View Controller

Step 4: Connecting Outlets

Open ListsViewController.swift and declare an outlet for the label, the table view, and the activity indicator view. This is also a good time to make the ListsViewController class conform to the UITableViewDataSource and UITableViewDelegate protocols.

Note that I've also added an import statement for the SVProgressHUD framework and that I've declared a static constant for the reuse identifier of the prototype cell we created in the storyboard.

Head back to the storyboard and connect the outlets with the corresponding views in the Lists View Controller Scene.

Step 5: Preparing the Table View

Before we fetch data from iCloud, we need to make sure the table view is ready to display the data. We first need to create a property, lists, to hold the records we're about to fetch. Remember that records are instances of the CKRecord class. This means the property that will hold the data from iCloud is of type [CKRecord], an array of CKRecord instances.

To get started, we need to implement three methods of the UITableViewDataSource protocol:

  • numberOfSectionsInTableView(_:)
  • numberOfRowsInSection(_:)
  • cellForRowAtIndexPath(_:)

If you have any experience working with table views, then the implementation of each of these methods is straightforward. However, cellForRowAtIndexPath(_:) may require some explanation. Remember that a CKRecord instance is a supercharged dictionary of key-value pairs. To access the value of a particular key, you invoke objectForKey(_:) on the CKRecord object. That's what we do in cellForRowAtIndexPath(_:). We fetch the record that corresponds with the table view row and ask it for the value for key "name". If the key-value pair doesn't exist, we display a dash to indicate the list doesn't have a name yet.

Step 6: Preparing the User Interface

There's one more step for us to take, prepare the user interface. In the view controller's viewDidLoad method, remove the fetchUserRecordID method call and invoke setupView, a helper method.

The setupView method prepares the user interface for fetching the list of records. We hide the label and the table view, and tell the activity indicator view to start animating.

Build and run the application on a device or in the iOS Simulator. If you've followed the above steps, you should see an empty view with a spinning activity indicator view in the center.

Busy Pretending to Be Fetching Data

Step 7: Creating a Record Type

Before we fetch any records, we need to create a record type for a shopping list in the CloudKit dashboard. The CloudKit dashboard is a web application that lets developers manage the data stored on Apple's iCloud servers.

Select the project in the Project Navigator and choose the Lists target from the list of targets. Open the Capabilities tab at the top and expand the iCloud section. Below the list of iCloud containers, click the button labeled CloudKit Dashboard.

Open CloudKit Dashboard

Sign in with your developer account and make sure the Lists application is selected in the top left. On the left, select Record Types from the Schema section. Every application has by default a Users record type. To create a new record type, click the plus button at the top of the third column. We will follow Apple's naming convention and name the record type Lists, not List.

Adding a New Record Type

Note that the first field is automatically created for you. Set Field Name to name and verify that Field Type is set to String. Don't forget to click the Save button at the bottom to create the Lists record type. We'll revisit the CloudKit Dashboard later in this series.

Step 8: Performing a Query

With the Lists record type created, it's finally time to fetch some records from iCloud. The CloudKit framework provides two APIs to interact with iCloud, a convenience API and an API based on the NSOperation class. We will use both APIs in this series, but we're going to keep it simple for now and use the convenience API.

In Xcode, open ListsViewController.swift and invoke the fetchLists method in viewDidLoad. The fetchLists method is another helper method. Let's take a look at the method's implementation.

Because a shopping list record is stored in the user's private database, we first get a reference to the default container's private database. To fetch the user's shopping lists, we need to perform a query on the private database, using the CKQuery class.

We initialize a CKQuery instance by invoking the init(recordType:predicate:) designated initializer, passing in the record type and an NSPredicate object. To avoid typos, I've created a constant for the record type. The constant, RecordTypeLists, is declared at the top of ListsViewController.swift.

Before we execute the query, we set the query's sortDescriptors property. We create an array containing an NSSortDescriptor object with key "name" and ascending set to true.

Executing the query is as simple as calling performQuery(_:inZoneWithID:completionHandler:) on privateDatabase, passing in query as the first argument. The second parameter specifies the identifier of the record zone on which the query will be performed. By passing in nil, the query is performed on the default zone of the database.

The third argument is a completion handler. The closure accepts an optional array of CKRecord objects and an optional NSError instance. The CloudKit documentation explicitly mentions that the completion handler can be invoked from any thread. We therefore dispatch the processing of the response to the main thread by wrapping the processResponseForQuery(_:error:) method call in a dispatch_async closure. That's how easy it is to perform a query. Let's see how we handle the query's response.

Step 9: Processing the Response

The implementation of processResponseForQuery(_:error:) isn't difficult if you're familiar with the Swift language. We inspect the contents of the records and error parameters, and update the message variable accordingly.

At the end of the method, we invoke updateView. In this helper method, we update the user interface based on the contents of the lists property.

Build and run the application to test what we've got so far. We currently don't have any records, but we'll fix that in the next section of this tutorial.

No Records Found

3. Adding a Shopping List

Step 1: Creating the AddListViewController Class

Because adding and editing a shopping list are very similar, we are going to implement both at the same time. Create a new file and name it AddListViewController.swift. Open the newly created file and create a UIViewController subclass named AddListViewController. At the top, add import statements for the UIKit, CloudKit, and SVProgressHUD framework. Declare two outlets, one of type UITextField! and one of type UIBarButtonItem!. Last but not least, create two actions, cancel(_:) and save(_:).

Step 2: Creating the User Interface

Open Main.storyboard and add a view controller to the storyboard. With the view controller selected, open the Identity Inspector on the right and set Class to AddListViewController.

The user will be able to navigate to the add list view controller by tapping a button in the lists view controller. Drag a bar button item from the Object Library to the navigation bar of the lists view controller. With the bar button item selected, open the Attributes Inspector and set System Item to Add. Press Control and drag from the bar button item to the add list view controller and select push from the menu that appears.

It's important that you choose push from the Action Segue section. It should be the first item in the menu. Select the segue you jus created and set Identifier to ListDetail in the Attributes Inspector on the right.

Add two bar button items to the navigation bar of the add list view controller, one on the left and one on the right. Set System Item of the left bar button item to Cancel and that of the right bar button item to Save. Finally, add a text field to the add list view controller. Center the text field and set its Alignment to center in the Attributes Inspector.

Add List View Controller

It is possible that, after creating the segue from the lists view controller to the add list view controller, no navigation item was created for the Add List View Controller Scene. I believe this is a bug in Xcode 7.

To resolve this issue, select the segue and, in the Attributes Inspector, set Segue to Deprecated Segues > Push. This will add a navigation item to the scene. Next, set Segue back to Adaptive Segues > Show.

Finally, connect the outlets and actions you created in AddListViewController.swift to the corresponding user interface elements in the scene.

Step 3: AddListViewControllerDelegate Protocol

Before we implement the AddListViewController class, we need to declare a protocol that we'll use to communicate from the add list view controller to the lists view controller. The protocol defines two methods, one for adding and one for updating a shopping list. This is what the protocol looks like.

We also need to declare three properties, one for the delegate, one for the shopping list that is created or updated, and a helper variable that indicates whether we're creating a new shopping list or editing an existing record.

The implementation of the AddListViewController class is no rocket science. The methods related to the view life cycle are short and easy to understand. In viewDidLoad, we first invoke the setupView helper method. We'll implement this method in a moment. We then update the value of the newList helper variable based on the value of the list property. If list is equal to nil, then we know that we're creating a new record. In viewDidLoad, we also add the view controller as an observer for UITextFieldTextDidChangeNotification notifications.

In viewDidAppear(_:), we call becomeFirstResponder on the text field to present the keyboard to the user.

In setupView, we invoke two helper methods, updateNameTextField and updateSaveButton. In updateNameTextField, we populate the text field if list is not nil. In other words, if we're editing an existing record, then we populate the text field with the name of that record.

The updateSaveButton method is in charge of enabling and disabling the bar button item in the top right. We only enable the save button if the name of the shopping list is not an empty string.

Step 4: Implementing Actions

The cancel(_:) action is as simple as it gets. We pop the top view controller from the navigation stack. The save(_:) action is more interesting. In this method, we extract the user's input from the text field and get a reference to the default container's private database.

If we're adding a new shopping list, then we create a new CKRecord instance by invoking init(recordType:), passing in RecordTypeLists as the record type. We then update the name of the shopping list by setting the value of the record for the key "name".

Because saving a record involves a network request and can take a non-trivial amount of time, we show a progress indicator. To save a new record or any changes to an existing record, we call saveRecord(_:completionHandler:) on privateDatabase, passing in the record as the first argument. The second argument is another completion handler that is invoked when saving the record completes, successfully or unsuccessfully.

The completion handler accepts two arguments, an optional CKRecord and an optional NSError. As I mentioned before, the completion handler can be invoked on any thread, which means that we need to code against that. We do this by explicitly invoking the processResponse(_:error:) method on the main thread.

In processResponse(_:error:), we verify if an error was thrown. If we did run into problems, we display an alert to the user. If everything went smoothly, we notify the delegate and pop the view controller from the navigation stack.

Last but not least, when the view controller receives a UITextFieldTextDidChangeNotification notification, it invokes updateSaveButton to update the save button.

Step 5: Tying Everything Together

In the ListsViewController class, we still need to take care of a few things. Let's start by conforming the class to the AddListViewControllerDelegate protocol.

This also means that we need to implement the methods of the AddListViewControllerDelegate protocol. In the controller(_:didAddList:) method, we add the new record to the array of CKRecord objects. We then sort the array of records, reload the table view, and invoke updateView on the view controller.

The sortLists method is pretty basic. We call sortInPlace on the array of records, sorting the array based on the record's name.

The implementation of the second method of the AddListViewControllerDelegate protocol, controller(_:didUpdateList:), looks almost identical. Because we're not adding a record, we only need to sort the array of records and reload the table view. There's no need to call updateView on the view controller since the array of records is, by definition, not empty.

To edit a record, the user needs to tap the accessory button of a table view row. This means that we need to implement the tableView(_:accessoryButtonTappedForRowWithIndexPath:) method of the UITableViewDelegate protocol. Before we implement this method, declare a helper property, selection, to store the user's selection.

In tableView(_:accessoryButtonTappedForRowWithIndexPath:), we store the user's selection in selection and tell the view controller to perform the segue that leads to the add list view controller. If you're curious, I've created a constant in ListsViewController.swift for the segue identifier, SegueListDetail.

We're almost there. When the segue with identifier ListDetail is performed, we need to configure the AddListViewController instance that is pushed onto the navigation stack. We do this in prepareForSegue(_:sender:?).

The segue hands us a reference to the destination view controller, the AddListViewController instance. We set the delegate property, and, if a shopping list is updated, we set the view controller's list property to the selected record.

Build and run the application to see the result. You should now be able to add a new shopping list and edit the name of existing shopping lists.

4. Deleting Shopping Lists

Adding the ability to delete shopping lists isn't much extra work. The user should be able to delete a shopping list by swiping a table view row from right to left and tapping the delete button that is revealed. To make this possible, we need to implement two more methods of the UITableViewDataSource protocol:

  • tableView(_:canEditRowAtIndexPath:)
  • tableView(_:commitEditingStyle:forRowAtIndexPath:)

The implementation of tableView(_:canEditRowAtIndexPath:) is trivial as you can see below.

In tableView(_:commitEditingStyle:forRowAtIndexPath:), we fetch the correct record from the array of records and invoke deleteRecord(_:) on the view controller, passing in the record that needs to be deleted.

The deleteRecord(_:) method should look familiar by now. We show a progress indicator and call deleteRecordWithID(_:completionHandler:) on the default container's private database. Note that we're passing in the record identifier, not the record itself. The completion handler accepts two arguments, an optional CKRecordID and an optional NSError.

In the completion handler, we dismiss the progress indicator and invoke processResponseForDeleteRequest(_:recordID:error:) on the main thread. In this method, we inspect the values of recordID and error that the CloudKit API has given us and we update message accordingly. If the delete request was successful, then we update the user interface and the array of records.

That's it. It's time to properly test the application with some data. Run the application on a device or in the iOS Simulator and add a few shopping lists. You should be able to add, edit, and delete shopping lists.

Conclusion

Even though this article is fairly long, it's good to remember that we only briefly interacted with the CloudKit API. The convenience API of the CloudKit framework is lightweight and easy to use.

This tutorial, however, has also illustrated that your job as a developer isn't limited to interacting with the CloudKit API. It's important to handle errors, show the user when a request is in progress, update the user interface, and tell the user what is going on.

In the next article of this series, we take a closer look at relationships by adding the ability to fill a shopping list with items. An empty shopping list isn't of much use and it certainly isn't fun. Leave any questions you have in the comments below or reach out to me on Twitter.

2015-08-28T21:30:35.000Z2015-08-28T21:30:35.000ZBart Jacobs

An Introduction to GameplayKit: Part 2

$
0
0

This is the second part of An Introduction to GameplayKit. If you haven't yet gone through the first part, then I recommend reading that tutorial first before continuing with this one.

Introduction

In this tutorial, I am going to teach you about two more features of the GameplayKit framework you can take advantage of:

  • agents, goals, and behaviors
  • pathfinding

By utilizing agents, goals, and behaviors, we are going to build in some basic artificial intelligence (AI) into the game that we started in the first part of this series. The AI will enable our red and yellow enemy dots to target and move towards our blue player dot. We are also going to implement pathfinding to extend on this AI to navigate around obstacles.

For this tutorial, you can use your copy of the completed project from the first part of this series or download a fresh copy of the source code from GitHub.

1. Agents, Goals, and Behaviors

In GameplayKit, agents, goals and behaviors are used in combination with each other to define how different objects move in relation to each other throughout your scene. For a single object (or SKShapeNode in our game), you begin by creating an agent, represented by the GKAgent class. However, for 2D games, like ours, we need to use the concrete GKAgent2D class.

The GKAgent class is a subclass of GKComponent. This means that your game needs to be using an entity- and component-based structure as I showed you in the first tutorial of this series.

Agents represent an object's position, size, and velocity. You then add a behavior, represented by the GKBehaviour class, to this agent. Finally, you create a set of goals, represented by the GKGoal class, and add them to the behavior object. Goals can be used to create many different gameplay elements, for example:

  • moving towards an agent
  • moving away from an agent
  • grouping close together with other agents
  • wandering around a specific position

Your behavior object monitors and calculates all of the goals that you add to it and then relays this data back to the agent. Let's see how this works in practice.

Open your Xcode project and navigate to PlayerNode.swift. We first need to make sure the PlayerNode class conforms to the GKAgentDelegate protocol.

Next, add the following code block to the PlayerNode class.

We start by adding a property to the PlayerNode class so that we always have a reference to the current player's agent object. Next, we implement the two methods of the GKAgentDelegate protocol. By implementing these methods, we ensure that the player dot displayed on screen will always mirror the changes that GameplayKit makes.

The agentWillUpdate(_:) method is called just before GameplayKit looks through the behavior and goals of that agent to determine where it should move. Likewise, the agentDidUpdate(_:) method is called straight after GameplayKit has completed this process.

Our implementation of these two methods ensures that the node we see on screen reflects the changes GameplayKit makes and that GameplayKit uses the last position of the node when performing its calculations.

Next, open ContactNode.swift and replace the file's contents with the following implementation:

By implementing the GKAgentDelegate protocol in the ContactNode class, we allow for all of the other dots in our game to be up to date with GameplayKit as well as our player dot.

It's now time to set up the behaviors and goals. To make this work, we need to take care of three things:

  • Add the player node's agent to its entity and set its delegate.
  • Configure agents, behaviors, and goals for all of our enemy dots.
  • Update all of these agents at the correct time.

Firstly, open GameScene.swift and, at the end of the didMoveToView(_:) method, add the following two lines of code:

With these two lines of code, we add the agent as a component and set the agent's delegate to be the node itself.

Next, replace the implementation of the initialSpawn method with the following implementation:

The most important code that we've added is located in the if statement that follows the switch statement. Let's go through this code line by line:

  • We first add the agent to the entity as a component and configure its delegate.
  • Next, we assign the agent's position and add the agent to a stored array, agents. We'll add this property to the GameScene class in a moment.
  • We then create a GKBehavior object with a single GKGoal to target the current player's agent. The weight parameter in this initializer is used to determine which goals should take precedence over others. For example, imagine that you have a goal to target a particular agent and a goal to move away from another agent, but you want the targeting goal to take preference. In this case, you could give the targeting goal a weight of 1 and the moving away goal a weight of 0.5. This behavior is then assigned to the enemy node's agent.
  • Lastly, we configure the massmaxSpeed, and maxAcceleration properties of the agent. These affect how fast the objects can move and turn. Feel free to play around with these values and see how it affects the movement of the enemy dots.

Next, add the following two properties to the GameScene class:

The agents array will be used to keep a reference to the enemy agents in the scene. The lastUpdateTime property will be used to calculate the time that has passed since the scene was last updated.

Finally, replace the implementation of the update(_:) method of the GameScene class with the following implementation:

In the update(_:) method, we calculate the time that has passed since the last scene update and then update the agents with that value.

Build and run your app, and begin moving around the scene. You will see that the enemy dots will slowly begin moving towards you.

Targeting enemies

As you can see, while the enemy dots do target the current player, they do not navigate around the white barriers, instead they try to move through them. Let's make the enemies a bit smarter with pathfinding.

2. Pathfinding

With the GameplayKit framework, you can add complex pathfinding to your game by combining physics bodies with GameplayKit classes and methods. For our game, we are going to set it up so that the enemy dots will target the player dot and at the same time navigate around obstacles.

Pathfinding in GameplayKit begins with creating a graph of your scene. This graph is a collection of individual locations, also referred to as nodes, and connections between these locations. These connections define how a particular object can move from one location to another. A graph can model the available paths in your scene in one of three ways:

  • A continuous space containing obstacles: This graph model allows for smooth paths around obstacles from one location to another. For this model, the GKObstacleGraph class is used for the graph, the GKPolygonObstacle class for obstacles, and the GKGraphNode2D class for nodes (locations).
  • A simple 2D grid: In this case, valid locations can only be those with integer coordinates. This graph model is useful when your scene has a distinct grid layout and you do not need smooth paths. When using this model, objects can only move horizontally or vertically in a single direction at any one time. For this model, the GKGridGraph class is used for the graph and the GKGridGraphNode class for nodes.
  • A collection of locations and the connections between them: This is the most generic graph model and is recommended for cases where objects move between distinct spaces, but their specific location within that space is not essential to the gameplay. For this model, the GKGraph class is used for the graph and the GKGraphNode class for nodes.

Because we want the player dot in our game to navigate around the white barriers, we are going to use the GKObstacleGraph class to create a graph of our scene. To begin, replace the spawnPoints property in the GameScene class with the following:

The spawnPoints array contains some altered spawn locations for the purposes of this tutorial. This is because currently GameplayKit can only calculate paths between objects that are relatively close to each other.

Due to the large default distance between dots in this game, a couple of new spawn points must be added to illustrate pathfinding. Note that we also declare a graph property of type GKObstacleGraph to keep a reference to the graph we will create.

Next, add the following two lines of code at the start of the didMoveToView(_:) method:

In the first line, we create an array of obstacles from the physics bodies in the scene. We then create the graph object using these obstacles. The bufferRadius parameter in this initializer can be used to force objects to not come within a certain distance of these obstacles. These lines need to be added at the start of the didMoveToView(_:) method, because the graph we create is needed by the time the initialSpawn method is called.

Finally, replace the initialSpawn method with the following implementation:

We begin the method by creating a GKGraphNode2D object with the default player spawn coordinates. Next, we connect this node to the graph so that it can be used when finding paths.

Most of the initialSpawn method remains unchanged. I have added some comments to show you where the pathfinding portion of the code is located in the first if statement. Let's go through this code step by step:

  • We create another GKGraphNode2D instance and connect this to the graph.
  • We create a series of nodes which make up a path by calling the findPathFromNode(_:toNode:) method on our graph.
  • If a series of path nodes has been created successfully, we then create a path from them. The radius parameter works similar to the bufferRadius parameter from before and defines how much an object can move away from the created path.
  • We create two GKGoal objects, one for following the path and another for staying on the path. The maxPredictionTime parameter allows for the goal to calculate as best it can ahead of time whether anything is going to interrupt the object from following/staying on that particular path.
  • Lastly, we create a new behavior with these two goals and assign this to the agent.

You will also notice that we remove the nodes we create from the graph once we are finished with them. This is a good practice to follow as it ensures that the nodes you have created do not interfere with any other pathfinding calculations later on.

Build and run your app one last time, and you will see two dots spawn very close to you and begin moving towards you. You may have to run the game multiple times if they both spawn as green dots.

Pathfinding enemies

Important!

In this tutorial, we used GameplayKit's pathfinding feature to enable enemy dots to target the player dot around obstacles. Note that this was just for a practical example of pathfinding.

For an actual production game, it would be best to implement this functionality by combining the player targeting goal from earlier in this tutorial with an obstacle-avoiding goal created with the init(toAvoidObstacles:maxPredictionTime:) convenience method, which you can read more about in the GKGoal Class Reference.

Conclusion

In this tutorial, I showed you how you can utilize agents, goals, and behaviors in games that have an entity-component structure. While we only created three goals in this tutorial, there are many more available to you, which you can read more about in the GKGoal Class Reference.

I also showed you how to implement some advanced pathfinding in your game by creating a graph, a set of obstacles, and goals to follow these paths.

As you can see, there is a vast amount of functionality made available to you through the GameplayKit framework. In the third and final part of this series, I will teach you about GameplayKit's random value generators and how to create your own rule system to introduce some fuzzy logic into your game.

As always, please be sure to leave your comments and feedback below.

2015-08-31T16:45:39.000Z2015-08-31T16:45:39.000ZDavis Allie

An Introduction to GameplayKit: Part 2

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24528

This is the second part of An Introduction to GameplayKit. If you haven't yet gone through the first part, then I recommend reading that tutorial first before continuing with this one.

Introduction

In this tutorial, I am going to teach you about two more features of the GameplayKit framework you can take advantage of:

  • agents, goals, and behaviors
  • pathfinding

By utilizing agents, goals, and behaviors, we are going to build in some basic artificial intelligence (AI) into the game that we started in the first part of this series. The AI will enable our red and yellow enemy dots to target and move towards our blue player dot. We are also going to implement pathfinding to extend on this AI to navigate around obstacles.

For this tutorial, you can use your copy of the completed project from the first part of this series or download a fresh copy of the source code from GitHub.

1. Agents, Goals, and Behaviors

In GameplayKit, agents, goals and behaviors are used in combination with each other to define how different objects move in relation to each other throughout your scene. For a single object (or SKShapeNode in our game), you begin by creating an agent, represented by the GKAgent class. However, for 2D games, like ours, we need to use the concrete GKAgent2D class.

The GKAgent class is a subclass of GKComponent. This means that your game needs to be using an entity- and component-based structure as I showed you in the first tutorial of this series.

Agents represent an object's position, size, and velocity. You then add a behavior, represented by the GKBehaviour class, to this agent. Finally, you create a set of goals, represented by the GKGoal class, and add them to the behavior object. Goals can be used to create many different gameplay elements, for example:

  • moving towards an agent
  • moving away from an agent
  • grouping close together with other agents
  • wandering around a specific position

Your behavior object monitors and calculates all of the goals that you add to it and then relays this data back to the agent. Let's see how this works in practice.

Open your Xcode project and navigate to PlayerNode.swift. We first need to make sure the PlayerNode class conforms to the GKAgentDelegate protocol.

Next, add the following code block to the PlayerNode class.

We start by adding a property to the PlayerNode class so that we always have a reference to the current player's agent object. Next, we implement the two methods of the GKAgentDelegate protocol. By implementing these methods, we ensure that the player dot displayed on screen will always mirror the changes that GameplayKit makes.

The agentWillUpdate(_:) method is called just before GameplayKit looks through the behavior and goals of that agent to determine where it should move. Likewise, the agentDidUpdate(_:) method is called straight after GameplayKit has completed this process.

Our implementation of these two methods ensures that the node we see on screen reflects the changes GameplayKit makes and that GameplayKit uses the last position of the node when performing its calculations.

Next, open ContactNode.swift and replace the file's contents with the following implementation:

By implementing the GKAgentDelegate protocol in the ContactNode class, we allow for all of the other dots in our game to be up to date with GameplayKit as well as our player dot.

It's now time to set up the behaviors and goals. To make this work, we need to take care of three things:

  • Add the player node's agent to its entity and set its delegate.
  • Configure agents, behaviors, and goals for all of our enemy dots.
  • Update all of these agents at the correct time.

Firstly, open GameScene.swift and, at the end of the didMoveToView(_:) method, add the following two lines of code:

With these two lines of code, we add the agent as a component and set the agent's delegate to be the node itself.

Next, replace the implementation of the initialSpawn method with the following implementation:

The most important code that we've added is located in the if statement that follows the switch statement. Let's go through this code line by line:

  • We first add the agent to the entity as a component and configure its delegate.
  • Next, we assign the agent's position and add the agent to a stored array, agents. We'll add this property to the GameScene class in a moment.
  • We then create a GKBehavior object with a single GKGoal to target the current player's agent. The weight parameter in this initializer is used to determine which goals should take precedence over others. For example, imagine that you have a goal to target a particular agent and a goal to move away from another agent, but you want the targeting goal to take preference. In this case, you could give the targeting goal a weight of 1 and the moving away goal a weight of 0.5. This behavior is then assigned to the enemy node's agent.
  • Lastly, we configure the massmaxSpeed, and maxAcceleration properties of the agent. These affect how fast the objects can move and turn. Feel free to play around with these values and see how it affects the movement of the enemy dots.

Next, add the following two properties to the GameScene class:

The agents array will be used to keep a reference to the enemy agents in the scene. The lastUpdateTime property will be used to calculate the time that has passed since the scene was last updated.

Finally, replace the implementation of the update(_:) method of the GameScene class with the following implementation:

In the update(_:) method, we calculate the time that has passed since the last scene update and then update the agents with that value.

Build and run your app, and begin moving around the scene. You will see that the enemy dots will slowly begin moving towards you.

Targeting enemies

As you can see, while the enemy dots do target the current player, they do not navigate around the white barriers, instead they try to move through them. Let's make the enemies a bit smarter with pathfinding.

2. Pathfinding

With the GameplayKit framework, you can add complex pathfinding to your game by combining physics bodies with GameplayKit classes and methods. For our game, we are going to set it up so that the enemy dots will target the player dot and at the same time navigate around obstacles.

Pathfinding in GameplayKit begins with creating a graph of your scene. This graph is a collection of individual locations, also referred to as nodes, and connections between these locations. These connections define how a particular object can move from one location to another. A graph can model the available paths in your scene in one of three ways:

  • A continuous space containing obstacles: This graph model allows for smooth paths around obstacles from one location to another. For this model, the GKObstacleGraph class is used for the graph, the GKPolygonObstacle class for obstacles, and the GKGraphNode2D class for nodes (locations).
  • A simple 2D grid: In this case, valid locations can only be those with integer coordinates. This graph model is useful when your scene has a distinct grid layout and you do not need smooth paths. When using this model, objects can only move horizontally or vertically in a single direction at any one time. For this model, the GKGridGraph class is used for the graph and the GKGridGraphNode class for nodes.
  • A collection of locations and the connections between them: This is the most generic graph model and is recommended for cases where objects move between distinct spaces, but their specific location within that space is not essential to the gameplay. For this model, the GKGraph class is used for the graph and the GKGraphNode class for nodes.

Because we want the player dot in our game to navigate around the white barriers, we are going to use the GKObstacleGraph class to create a graph of our scene. To begin, replace the spawnPoints property in the GameScene class with the following:

The spawnPoints array contains some altered spawn locations for the purposes of this tutorial. This is because currently GameplayKit can only calculate paths between objects that are relatively close to each other.

Due to the large default distance between dots in this game, a couple of new spawn points must be added to illustrate pathfinding. Note that we also declare a graph property of type GKObstacleGraph to keep a reference to the graph we will create.

Next, add the following two lines of code at the start of the didMoveToView(_:) method:

In the first line, we create an array of obstacles from the physics bodies in the scene. We then create the graph object using these obstacles. The bufferRadius parameter in this initializer can be used to force objects to not come within a certain distance of these obstacles. These lines need to be added at the start of the didMoveToView(_:) method, because the graph we create is needed by the time the initialSpawn method is called.

Finally, replace the initialSpawn method with the following implementation:

We begin the method by creating a GKGraphNode2D object with the default player spawn coordinates. Next, we connect this node to the graph so that it can be used when finding paths.

Most of the initialSpawn method remains unchanged. I have added some comments to show you where the pathfinding portion of the code is located in the first if statement. Let's go through this code step by step:

  • We create another GKGraphNode2D instance and connect this to the graph.
  • We create a series of nodes which make up a path by calling the findPathFromNode(_:toNode:) method on our graph.
  • If a series of path nodes has been created successfully, we then create a path from them. The radius parameter works similar to the bufferRadius parameter from before and defines how much an object can move away from the created path.
  • We create two GKGoal objects, one for following the path and another for staying on the path. The maxPredictionTime parameter allows for the goal to calculate as best it can ahead of time whether anything is going to interrupt the object from following/staying on that particular path.
  • Lastly, we create a new behavior with these two goals and assign this to the agent.

You will also notice that we remove the nodes we create from the graph once we are finished with them. This is a good practice to follow as it ensures that the nodes you have created do not interfere with any other pathfinding calculations later on.

Build and run your app one last time, and you will see two dots spawn very close to you and begin moving towards you. You may have to run the game multiple times if they both spawn as green dots.

Pathfinding enemies

Important!

In this tutorial, we used GameplayKit's pathfinding feature to enable enemy dots to target the player dot around obstacles. Note that this was just for a practical example of pathfinding.

For an actual production game, it would be best to implement this functionality by combining the player targeting goal from earlier in this tutorial with an obstacle-avoiding goal created with the init(toAvoidObstacles:maxPredictionTime:) convenience method, which you can read more about in the GKGoal Class Reference.

Conclusion

In this tutorial, I showed you how you can utilize agents, goals, and behaviors in games that have an entity-component structure. While we only created three goals in this tutorial, there are many more available to you, which you can read more about in the GKGoal Class Reference.

I also showed you how to implement some advanced pathfinding in your game by creating a graph, a set of obstacles, and goals to follow these paths.

As you can see, there is a vast amount of functionality made available to you through the GameplayKit framework. In the third and final part of this series, I will teach you about GameplayKit's random value generators and how to create your own rule system to introduce some fuzzy logic into your game.

As always, please be sure to leave your comments and feedback below.

2015-08-31T16:45:39.000Z2015-08-31T16:45:39.000ZDavis Allie

Google I/O 2015 Through My Eyes: Part 1

$
0
0
file

6:30 AM, 27th May 2015, Moscone Center, San Francisco

I arrived early in the morning to find out that queue was already quite long. Most people, including me, had skipped their breakfast to get in first. Luckily I had a grey ribbon card, which meant I was eligible for the shorter queue meant only for press, Google Developer Expert (GDE) and Google Developer Group (GDG) attendees. The longer queue seemed to be growing exponentially around the venue.

file

Free donuts, bananas and coffee in the queue were definitely helping. The environment was full of technical buzz, and some reporters had started interviewing people in the queue. Press holders were let in at 8:10 and taken to a press room, whereas we still had time to wait.

8:30 AM

We were let in to the center and greeted by the Google Security Team in pink tees. Everyone quickly moved to the keynote arena where we saw probably the widest screen ever made, which resembled a VR headset.

file

The room got quickly filled with participants from all over the world. It was amazing to see so many GoPro selfies being taken. Luckily I had a reserved seat in the GDE/GDG Section, which was right beside the press seats. The front row was reserved for the Googlers.

Soon we saw a giant ping-pong game being played on the wide screen, which was probably the widest display a gamer could ever imagine.

file

The room was filled with people talking about Big Data and even the hex codes of the color on the screen. In between the games we saw a big Rube Goldberg animation with kick-ass music, which was followed by a whale which the crowd loved.

file

09:32 AM

Almost on time, the presentation got started with a breathtaking video, which took us from the Hubble Deep Space to the planet where Sundar Pichai greeted us to mark the starting of Google I/O.

The Keynote was full of announcements, which included:

  • HBO on Android PlayStore
  • Android M Developer Preview
  • Project Brillo
  • Weave
  • Google Now on Tap
  • Google Photos
  • Offline YouTube
  • Offline Maps
  • Android Studio 1.3
  • Polymer 1.0
  • JUMP
  • Android Nanodegree
  • AdMob and Google Analytics Integration
  • Google Play Developer Pages
  • Cardboard SDK for iOS and Android
  • VR Expeditions for Students and Teachers
  • Improved Google Loon
  • … and much more

After the keynote, all the attendees were given a Google Cardboard V2, which had quite a few improvements over its predecessor, like support for phablets, and a better button.

It was noon already, but I decided to check out the stalls on the top floor before having lunch. I had my full day planned with sessions using the Official I/O Android app.

Moving out of the arena, there was an Android Wear section on the left and Android Auto section on the right, but what caught my eye was the Google ATAP Arena. Looking like something out of fantasy, this area was full of technologies from a science fiction novel. I watched HELP, which is the first live-action Spotlight story which gave a 3D immersive experience on a mobile phone without a VR. It felt like actually being present at the site of the action. It was such an awesome experience that I recommended almost everyone during and after the I/O to try Google Stories, especially the HELP movie.

file

I talked to the team there, and Brian Collins, a Google Engineer working on the project, gave me an excellent demo of the SDK which was used to create a Spotlight Story. He also told me that the Spotlight SDK might get released publicly next year.

Next I moved to Project Jacquard, which allows you to replace buttons with a cloth surface. It was amazing to use cloth to operate a light bulb and play/pause a song on an Android phone.

12:52 PM

Time was passing by, and with less than 10 minutes remaining until my planned session, I quickly went to the ground floor to have lunch. After lunch I went to the “Promote your mobile apps in minutes” session, which focussed on useful insights on user acquisition, subscriber conversion and subscriber retention using Google Search, AdMob, Play, YouTube, etc.

After the session I took a break and went back to the top floor to continue where I had left. I went to Android Play for families, which is a new section on PlayStore added in this I/O. As the name suggests, it allows us to easily find family-friendly content on PlayStore.

After an intriguing discussion with the Google Engineers working on Android Play for families, I moved next to the Android for Work section, which solves the problems faced by many companies which use Android in their workflow. Android for Work provides granular control over what’s necessary for a business, and I intend to use it in one of my upcoming projects.

I then decided to take on the hands-on Codelabs on how to create a gRPC Service using Node.js. It was surprising how much support I received from Google developers, who were very nice and readily offered any kind of help. I enjoyed the Codelabs, and now the whole set of Codelabs are publicly accessible so you can try them yourself.

The day was almost over and I was so tired of walking around (yes, the center was huge, and the day involved constant walking around to different venues).

file

I decided to hang out on the middle floor, which literally had swings and play tools waiting for us. With baskets full of candies, drums full of cans, lots of coffee, ice-cream and so on, it was extremely fulfilling resting in the arena. After some time I decided it was time to get back to my motel which was only two blocks away from the venue.

6:45 PM

The day was still not over, and the After Hours party was waiting for us at the nearby Yerba Beuna Gardens. I reached the place at around 6:45 and a long queue was waiting for me. Luckily the queue was moving quite quickly, and I was soon in.

file

The party was full of drinks, food, props, live music and a huge merry-go-round karaoke setup.

file

After two back-to-back live performances, we had the geekiest DJ party one could ever imagine. Lightsabers and headphones were distributed to everyone. So these headphones had two frequencies which were playing two different tunes, and another tune was being played out loud. So you could choose any of the music and party. The karaoke was also very fun and I sang for over 30 minutes while reading the lyrics, and believe me it was awesome.

file

The night ended after I was tired from dancing, eating and singing, which is what one expects from a party. Everyone had a great time at the party. The next day had more surprises waiting for me. So just hang in there, because I will be back with lots of interesting buzz that happened on the second day.

2015-09-02T14:46:58.855Z2015-09-02T14:46:58.855Z Bhanu Chaudhary

Google I/O 2015 Through My Eyes: Part 1

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24282
file

6:30 AM, 27th May 2015, Moscone Center, San Francisco

I arrived early in the morning to find out that queue was already quite long. Most people, including me, had skipped their breakfast to get in first. Luckily I had a grey ribbon card, which meant I was eligible for the shorter queue meant only for press, Google Developer Expert (GDE) and Google Developer Group (GDG) attendees. The longer queue seemed to be growing exponentially around the venue.

file

Free donuts, bananas and coffee in the queue were definitely helping. The environment was full of technical buzz, and some reporters had started interviewing people in the queue. Press holders were let in at 8:10 and taken to a press room, whereas we still had time to wait.

8:30 AM

We were let in to the center and greeted by the Google Security Team in pink tees. Everyone quickly moved to the keynote arena where we saw probably the widest screen ever made, which resembled a VR headset.

file

The room got quickly filled with participants from all over the world. It was amazing to see so many GoPro selfies being taken. Luckily I had a reserved seat in the GDE/GDG Section, which was right beside the press seats. The front row was reserved for the Googlers.

Soon we saw a giant ping-pong game being played on the wide screen, which was probably the widest display a gamer could ever imagine.

file

The room was filled with people talking about Big Data and even the hex codes of the color on the screen. In between the games we saw a big Rube Goldberg animation with kick-ass music, which was followed by a whale which the crowd loved.

file

09:32 AM

Almost on time, the presentation got started with a breathtaking video, which took us from the Hubble Deep Space to the planet where Sundar Pichai greeted us to mark the starting of Google I/O.

The Keynote was full of announcements, which included:

  • HBO on Android PlayStore
  • Android M Developer Preview
  • Project Brillo
  • Weave
  • Google Now on Tap
  • Google Photos
  • Offline YouTube
  • Offline Maps
  • Android Studio 1.3
  • Polymer 1.0
  • JUMP
  • Android Nanodegree
  • AdMob and Google Analytics Integration
  • Google Play Developer Pages
  • Cardboard SDK for iOS and Android
  • VR Expeditions for Students and Teachers
  • Improved Google Loon
  • … and much more

After the keynote, all the attendees were given a Google Cardboard V2, which had quite a few improvements over its predecessor, like support for phablets, and a better button.

It was noon already, but I decided to check out the stalls on the top floor before having lunch. I had my full day planned with sessions using the Official I/O Android app.

Moving out of the arena, there was an Android Wear section on the left and Android Auto section on the right, but what caught my eye was the Google ATAP Arena. Looking like something out of fantasy, this area was full of technologies from a science fiction novel. I watched HELP, which is the first live-action Spotlight story which gave a 3D immersive experience on a mobile phone without a VR. It felt like actually being present at the site of the action. It was such an awesome experience that I recommended almost everyone during and after the I/O to try Google Stories, especially the HELP movie.

file

I talked to the team there, and Brian Collins, a Google Engineer working on the project, gave me an excellent demo of the SDK which was used to create a Spotlight Story. He also told me that the Spotlight SDK might get released publicly next year.

Next I moved to Project Jacquard, which allows you to replace buttons with a cloth surface. It was amazing to use cloth to operate a light bulb and play/pause a song on an Android phone.

12:52 PM

Time was passing by, and with less than 10 minutes remaining until my planned session, I quickly went to the ground floor to have lunch. After lunch I went to the “Promote your mobile apps in minutes” session, which focussed on useful insights on user acquisition, subscriber conversion and subscriber retention using Google Search, AdMob, Play, YouTube, etc.

After the session I took a break and went back to the top floor to continue where I had left. I went to Android Play for families, which is a new section on PlayStore added in this I/O. As the name suggests, it allows us to easily find family-friendly content on PlayStore.

After an intriguing discussion with the Google Engineers working on Android Play for families, I moved next to the Android for Work section, which solves the problems faced by many companies which use Android in their workflow. Android for Work provides granular control over what’s necessary for a business, and I intend to use it in one of my upcoming projects.

I then decided to take on the hands-on Codelabs on how to create a gRPC Service using Node.js. It was surprising how much support I received from Google developers, who were very nice and readily offered any kind of help. I enjoyed the Codelabs, and now the whole set of Codelabs are publicly accessible so you can try them yourself.

The day was almost over and I was so tired of walking around (yes, the center was huge, and the day involved constant walking around to different venues).

file

I decided to hang out on the middle floor, which literally had swings and play tools waiting for us. With baskets full of candies, drums full of cans, lots of coffee, ice-cream and so on, it was extremely fulfilling resting in the arena. After some time I decided it was time to get back to my motel which was only two blocks away from the venue.

6:45 PM

The day was still not over, and the After Hours party was waiting for us at the nearby Yerba Beuna Gardens. I reached the place at around 6:45 and a long queue was waiting for me. Luckily the queue was moving quite quickly, and I was soon in.

file

The party was full of drinks, food, props, live music and a huge merry-go-round karaoke setup.

file

After two back-to-back live performances, we had the geekiest DJ party one could ever imagine. Lightsabers and headphones were distributed to everyone. So these headphones had two frequencies which were playing two different tunes, and another tune was being played out loud. So you could choose any of the music and party. The karaoke was also very fun and I sang for over 30 minutes while reading the lyrics, and believe me it was awesome.

file

The night ended after I was tired from dancing, eating and singing, which is what one expects from a party. Everyone had a great time at the party. The next day had more surprises waiting for me. So just hang in there, because I will be back with lots of interesting buzz that happened on the second day.

2015-09-02T14:46:58.855Z2015-09-02T14:46:58.855Z Bhanu Chaudhary

Build an MP3 Player With AV Foundation

$
0
0
Final product image
What You'll Be Creating

AV Foundation is a framework for working with audio and visual media on iOS and OSX. Using AV Foundation, you can play, capture, and encode media. It is quite an extensive framework and for the purpose of this tutorial we will be focusing on the audio portion. Specifically, we will be using the AVAudioPlayer class to play MP3 files.

Starter Project

I have provided a starter project that has all the actions and outlets already configured, and with the appropriate methods stubbed out. The classes the project uses, are already stubbed out as well so we can dive right into the code. You can download the starter project from GitHub.

1. Linking the AV Foundation Framework

Before you can use AV Foundation, you have to link the project against the framework. In the Project Navigator, make sure your project is selected. Under the General tab, go to Linked Frameworks and Libraries and from there you choose AVFoundation.framework.

Linking the project against the AV Foundation framework

2.FileReader Class

In the starter project, you will find a file named FileReader.swift. Open this file to view its contents.

This is a simple stub of the class that we'll use to read files from disk. It inherits from NSObject. We will implement a method, readFiles, which will be a type method. Type methods allow you to call a method on the class itself, the type, as opposed to an instance of the class. Below is the implementation of the readFiles method.

The main bundle contains the code and resources for your project, and it is here that we will find the MP3s. We use the method pathsForResourcesOfType(_:inDirectory:) method, which returns an array containing the pathnames for the specified type of resource. In this case, we are searching for type "mp3". Because we are not interested in a specific directory, we pass in nil.

This class will be used by the MP3Player class, which we will work on next.

3.MP3Player Class

Next, open MP3Player.swift and view its contents.

Notice that we are adopting the AVAudioPlayerDelegate protocol. This protocol declares a number of useful methods, one of which is audioPlayerDidFinishPlaying(_:successfully:). By implementing the audioPlayerDidFinishPlaying(_:successfully:) method, we will be notified when the audio has finished playing.

Step 1: Properties

Add the following to MP3Player.swift.

The player property will be an instance of the AVAudioPlayer class, which we will use to play, pause, and stop the MP3s. The currentTrackIndex variable keeps track of which MP3 is currently playing. Finally, the tracks variable will be an array of the paths to the list of MP3s that are included in the application's bundle.

Step 2: init

During initialization, we invoke the FileReader's readFiles method to fetch the paths of the MP3s and store this list in the tracks array. Because this is a designated initializer, we must call the init method of the superclass. Finally, we call queueTrack, which we will be writing next.

Step 3: queueTrack

Add the following implementation for the queueTrack method to the MP3Player class.

Because we will be instantiating a new AVAudioPlayer instance each time this method is called, we do a little housekeeping by setting player to nil.

We declare an optional NSError and a constant url. We invoke fileURLWithPath(_:) to fetch the path to the current MP3 and store the value in url. We are passing the tracks array as a parameter using currentTrackIndex as the subscript. Remember the tracks array contains the paths to the MP3s, not a reference to the MP3 files themselves.

To instantiate the player, we pass the url constant and error variable into the AVAudioPlayer's initializer. If the initialization happens to fail, the error variable is populated with a description of the error.

If we don't encounter an error, we set the player's delegate to self and invoke the prepareToPlay method on the player. The prepareToPlay method preloads the buffers and acquires the audio hardware, which minimizes any lag when calling the play method.

Step 4: play

The play method first checks to see whether or not the audio is already playing by checking the aptly named playing property. If the audio is not playing, it invokes the play method of the player property.

Step 5: stop

The stop method first checks whether the audio player is already playing. If it is, it invokes the stop method and sets the currentTime property to 0. When you invoke the stop method, it just stops the audio. It does not reset the audio back to the beginning, which is why we need to do it manually.

Step 6: pause

Just like the stop method, we first check to see if the audio player is playing. If it is, we invoke the pause method.

Step 7: nextSong

The nextSong(_:Bool) method queues up the next song and, if the player is playing, plays that song. We don't want the next song playing if the player is paused. However, this method is also called when a song finishes playing. In that case, we do want to play the next song, which is what the parameter songFinishedPlaying is for.

The playerWasPlaying variable is used to tell whether or not the player was playing when this method was invoked. If the song was playing, we invoke the stop method on the player and set playerWasPlaying to true.

Next, we increment the currentTrackIndex and check to see if it is greater than or equal to tracks.count. The count property of an array gives us the total number of items in the array. We need to be sure that we don't try to access an element that doesn't exist in the tracks array. To prevent this, we set currentTrackIndex back to the first element of the array if that is the case.

Finally, we invoke queueTrack to get the next song ready and play that song if either playerWasPlaying or songFinishedPlaying is true.

Step 8: previousSong

The previousSong method works very similar to nextSong. The only difference is that we decrement the currentTrackIndex and check if it is equal to 0. If it is, we set it to the index of the last element in the array.

By utilizing both the nextSong and previousSong methods, we are able to cycle through all of the MP3s and start over when we reach the beginning or the end of the list.

Step 9: getCurrentTrackName

The getCurrentTrackName method gets the name of the MP3 without the extension.

We get a reference to whatever the current MP3 is by using tracks[currentTrackIndex]. Remember, however, that these are the paths to the MP3s and not the actual files themselves. The paths are rather long, because it is the full path to the MP3 files.

On my machine, for example, the first element of the tracks array is equal to "/Users/jamestyner/Library/Developer/CoreSimulator/Devices/80C8CD34-22AE-4F00-862E-FD41E2D8D6BA/data/Containers/Bundle/Application/3BCF8543-BA1B-4997-9777-7EC56B1C4348/MP3Player.app/Lonesome Road Blues.mp3". This path would be different on an actual device of course.

We've got a large string that contains the path to the MP3, but we just want the name of the MP3 itself. The NSString class defines two properties that can help us. As the name implies, the lastPathComponent property returns the last component of a path. As you might have guessed, the stringByDeletingPathExtension property removes the extension.

Step 10: getCurrentTimeAsString

The getCurrentTimeAsString method uses the currentTime property of the player instance and returns it as a human-readable string (e.g., 1:02).

The currentTime property is of type NSTimeInterval, which is just a typealias for a Double. We use some math to get the seconds and minutes, making sure we convert time to an Int since we need to work with whole numbers. If you are not familiar with the remainder operator (%), it finds the remainder after division of one number by another. If the time variable was equal to 65, then seconds would be equal to 5 because we are using 60.

Step 11: getProgress

The getProgress method is used by the UIProgressView instance to give an indication of how much of the MP3 has played. This progress is represented by a value from 0.0 to 1.0 as a Float.

To get this value, we divide the player's currentTime property by the player's duration property, we store these values in the variables theCurrentTime and theCurrentDuration. Like currentTime, the duration property is of type NSTimeInterval and it represents the duration of the song in seconds.

Step 12: setVolume

The setVolume(_:Float) method invokes the setVolume method of the player instance.

Step 13: audioPlayerDidFinishPlaying(_:successfully:)

The audioPlayerDidFinishPlaying(_:successfully:) method is a method of the AVAudioPlayerDelegate protocol. This method takes as parameters the AVAudioPlayer instance and a boolean. The boolean is set to true if the audio player has finished playing the current song.

If the song successfully finished playing, we call the nextSong method, passing in true since the song finished playing on its own.

This completes the MP3Player class. We will revisit it a bit later, after implementing the actions of the ViewController class.

4. ViewController Class

Open ViewController.swift and view its contents.

The mp3Player variable is an instance of the MP3Player class we implemented earlier. The timer variable will be used to update the trackTime and progressBar views every second.

In the next few steps, we will implement the actions of the ViewController class. But first, we should instantiate the MP3Player instance. Update the implementation of the viewDidLoad method as shown below.

Step 1: playSong(_: AnyObject)

Enter the following in the playSong(_: AnyObject) method.

In this method, we invoke the play method on the mp3Player object. We are at a point where we can start testing the app now. Run the app and press the play button. The song should start playing.

Step 2: stopSong(_: AnyObject)

The stopSong(_: AnyObject) method invokes the stop method on the mp3Player object.

Run the app again and tap the play button. You should now be able to stop the song by tapping the stop button.

Step 3: pauseSong(_: AnyObject)

As you might have guessed, the pauseSong(_: AnyObject) method invokes the pause method on the mp3Player object.

Step 4: playNextSong(_: AnyObject)

In playNextSong(_: AnyObject), we invoke the nextSong method on the mp3player object. Note that we pass false as a parameter, because the song didn't finish playing on its own. We are manually starting the next song by pressing the next button.

Step 5: previousSong(_: AnyObject)

As you can see, the implementation of the previousSong(_: AnyObject) method is very similar to that of nextSong(_: AnyObject). All the buttons of the MP3 player should be functional now. If you've not tested the app yet, now would be a good time to make sure everything is working as expected.

Step 6: setVolume(_: UISlider)

The setVolume(_: UISlider) method invokes the setVolume method on the mp3Player object. The volume property is of type Float. The value ranges from 0.0 to 1.0. The UISlider object is set up with 0.0 as its minimum value and 1.0 as its maximum value.

Run the app one more time and play with the volume slider to test that everything is working correctly.

Step 7: startTimer

The startTimer method instantiates a new NSTimer instance.

The scheduledTimerWithTimeInterval(_:target:selector:userInfo:repeats:) initializer takes as parameters the number of seconds between firing of the timer, the object to which to call a method on specified by selector, the method that gets called when the timer fires, an optional userInfo dictionary, and whether or not the timer repeats until it is invalidated.

We are using a method named updateViewsWithTimer(_: NSTimer) as the selector, so we will create that next.

Step 8: updateViewsWithTimer(_: NSTimer)

The updateViewsWithTimer(_: NSTimer) method calls the updateViews method, which we will implement in the next step.

Step 9: updateViews

The updateViews method updates the trackTime and progressBar views.

The text property of trackTime is updated with the currentTime property, formatted as a string by invoking the getCurrentTimeAsString method. We declare a constant progress using the mp3Player's getProgress method, and set progressBar.progress using that constant.

Step 10: Wiring Up the Timer

Now we need to call the startTimer method at the appropriate places. We need to start the timer in the playSong(_: AnyObject) method, the playNextSong(_ :AnyObject) method, and the playPreviousSong(_ :AnyObject) method.

Step 11: Stopping the Timer

We also need to stop the timer when the pause and stop buttons are pressed. You can stop the timer object by invoking the invalidate method on the NSTimer instance.

Step 12: setTrackName

The setTrackName method sets the text property of trackName by invoking getCurrentTrackName on the mp3Player object.

Step 13: setupNotificationCenter

When a song finishes playing, it should automatically show the next song's name and start playing that song. Also, when the user presses the play, next, or previous buttons, the setTrackName method should be invoked. The ideal place to do this is the queueTrack method of the MP3Player class.

We need a way to have the MP3Player class tell the ViewController class to invoke the setTrackName method. To do that, we will use the NSNotificationCenter class. The notification center provides a way to broadcast information throughout a program. By registering as an observer with the notification center, an object can receive these broadcasts and perform an operation. Another way to accomplish this task would be to use the delegation pattern.

Add the following method to the ViewController class.

We first obtain a reference to the default notification center. We then invoke the addObserver(_:selector:name:object:) method on the notification center. This method accepts four parameters:

  • the object registering as the observer, self in this case
  • the message that will be sent to the observer when the notification is posted
  • the name of the notification for which to register the observer
  • the object whose notifications the observer wants to receive

By passing in nil as the last argument, we listen for every notification that has a name of SetTrackNameText.

Now we need to call this method in the view controller's viewDidLoad method.

Step 14: Posting the Notification

To post the notification, we invoke the postNotificationName(_:object:) method on the default notification center. As I mentioned earlier, we will do this in the queueTrack method of the MP3Player class. Open MP3Player.swift and update the queueTrack method as shown below.

If you test the app now and let a song play all the way through, it should start playing the next song automatically. But you may be wondering why the song's name does not show up during the first song. The init method of the MP3Player class calls the queueTrack method, but since it has not finished initializing, it has no affect.

All we need to do is manually call the setTrackName method after we initialize the mp3Player object. Add the following code to the viewDidLoad method in ViewController.swift.

You'll notice that I also called the updateViews method. This way, the player shows a time of 0:00 at the start. If you test the app now, you should have a fully functional MP3 player.

Conclusion

This was a rather long tutorial, but you now have a functional MP3 player to build and expand on. One suggestion is to allow the user to choose a song to play by implementing a UITableView below the player. Thanks for reading and I hope you've learned something useful.



2015-09-04T15:15:46.000Z2015-09-04T15:15:46.000ZJames Tyner

Creating and Publishing an Android Library

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24582

Introduction

Our lives as Android developers would be a lot harder if not for all those third-party libraries out there that we love to include in our projects. In this tutorial, you will learn how to give back to the developer community by creating and publishing your own Android libraries, which people can effortlessly add and use in their projects.

1. Creating an Android Library

If your library is going to be composed of only Java classes, packaging it as a JAR and distributing it using a file host is perhaps the quickest and easiest way to share it. If you were to create it from the console, the following command would suffice:

This tutorial however, shows you how to work with more complex libraries that contain not just Java classes, but also various types of XML files and resources. Such libraries are created as Android library modules and are usually packaged as AAR files.

Let’s create a simple Android library that offers a custom View to developers who use it.

Step 1: Add a New Module

To begin, add a new Android module to your project by selecting New > New Module from the File menu. You will be shown the following screen, which offers lots of choices:

New module dialog

Select Android Library and press Next. In the form that follows, enter a name for your library and press Next. I’ll be calling this library mylittlelibrary.

In the last screen, select Add no Activity and press Finish.

Your project will now have two modules, one for the app and one for the library. Here’s what its structure looks like:

Structure of project

Step 2: Create a Layout

Create a new layout XML by right-clicking on the res folder of your library module and selecting New > XML > Layout XML File. Name it my_view.xml.

To keep this tutorial simple, we’ll be creating a custom View that has two TextView widgets inside a LinearLayout. After adding some text to the TextView widgets, the layout XML file should look like this:

Step 3: Create a Java Class

Create a new Java class and name it MyView.java. Make sure to put this file in the src directory of the library module–not the app module.

To make this class behave as a View, make it a subclass of the LinearLayout class. Android Studio will prompt you to add a few constructors to the class. After adding them, the new class should look like this:

As you can see, we now have two constructors. To avoid adding initialization code to each constructor, call a method named initialize from each constructor. Add the following code to each constructor:

In the initialize method, call inflate to associate the layout we created in the previous step with the class.

2. Using the Library Locally

Now that the library is ready, let’s make use of it in the app module of the same project in order to make sure that there are no issues. To do so, add it as a compile dependency in the build.gradle file of the app module:

Create a new Java class, MainActivity, inside the app module. Make it a subclass of the Activity class and override its onCreate method.

Inside the onCreate method, create an instance of the custom view using its constructor. Pass it to the setContentView method so that it fills all the screen space of the Activity:

Your Activity is now ready. After adding it to the app manifest, build your project and deploy your app to an Android device. You should be able to see the custom view when the app starts.

3. Publishing Your Library on Bintray

Bintray is a popular platform you can use to publish Android libraries. It is free and easy to use.

Start by creating an account on Bintray. After signing in to your account, you will see that you already own six repositories. You can either use one of them or create a new repository. For this tutorial, I will be using the repository called maven, which is a Maven repository.

Homepage

Visit your profile page and click the Edit button. On the next page, click the API Key link to view your API key.

API Key

Make a note of the key, because you will be needing it to authenticate yourself when using the Bintray plugin.

Step 1: Add Necessary Plugins

To interact with Bintray in Android Studio, you should include the Bintray plugin in the dependencies of your project’s build.gradle file.

Because you will be uploading the library to a Maven repository, you should also add the Maven plugin as shown below.

Step 2: Apply the Plugins

Open the build.gradle file of your library module and add the following code to apply the plugins we added in the previous step.

Step 3: Specify POM Details

The Bintray plugin will look for a POM file when it uploads the library. Even though the Maven plugin generates it for you, you should specify the value of the groupId tag and the value of the version tag yourself. To do so, use the group and version variables in your gradle file.

If you are familiar with Maven and you are wondering why we didn’t specify the value of the artifactId tag, it is because the Maven plugin will, by default, use the name of your library as the artifactId.

Step 4: Generate a Sources JAR

To conform to the Maven standards, your library should also have a JAR file containing the library’s source files. To generate the JAR file, create a new Jar task, generateSourcesJar, and specify the location of the source files using the from function.

Step 5: Generate a Javadoc JAR

It is also recommended that your library has a JAR file containing its Javadocs. Because you currently don’t have any Javadocs, create a new Javadoc task, generateJavadocs, to generate them. Use the source variable to specify the location of the source files. You should also update the classpath variable so that the task can find classes that belong to the Android SDK. You can do this by adding the return value of the android.getBootClasspath method to it.

Next, to generate a JAR from the Javadocs, create a Jar task, generateJavadocsJar, and pass the destinationDir property of generateJavadocs to its from function. Your new task should look like this:

To make sure the generateJavadocsJar task only starts when the generateJavadocs task has completed, add the following code snippet, which uses the dependsOn method to order the tasks:

Step 6: Include the Generated JAR files

To include the source and Javadoc JAR files in the list of artifacts, which will be uploaded to the Maven repository, you should add the names of their tasks to a configuration called archives. To do so, use the following code snippet:

Step 7: Run Tasks

It is now time to run the tasks we created in the previous steps. Open the Gradle Projects window and search for a task named install.

Install task

Double-click it to run the tasks associated with the library module. Once it’s finished running, you will have everything you need to publish your library, a valid POM file, an AAR file, a sources JAR, and a Javadocs JAR.

Step 8: Configure the Bintray Plugin

To configure the plugin, you should use the bintray closure in your Gradle file. First, authenticate yourself using the user and key variables, corresponding to your Bintray username and API key respectively.

On Bintray, your library will reside inside a Bintray package. You should provide details about it using the intuitively named repo, name, licenses, and vcsUrl parameters of the pkg closure. If the package doesn’t exist, it will be created automatically for you.

When you upload files to Bintray, they will be associated with a version of the Bintray package. Therefore, pkg must contain a version closure whose name property is set to a unique name. Optionally, you can also provide a description, release date, and Git tag using the desc, released, and vcsTag parameters.

Finally, to specify the files that should be uploaded, set the value of the configuration parameter to archives.

This is a sample configuration:

Step 9: Upload Files Using the Bintray Plugin

Open the Gradle Projects window again and search for the bintrayUpload task. Double-click it to begin uploading the files.

Bintray upload

Once the task completes, open a browser to visit your Bintray package’s details page. You will see a notification that says that you have four unpublished files. To publish these files, click the Publish link.

Notification about unpublished files

4. Using the Library From Bintray

Your library is now available as a Bintray package. Once you share the URL of your Maven repository, along with the group ID, artifact ID, and version number, any developer can access your library. For example, to use the library we created, developers would have to include the following code snippet:

Note that the developer has to explicitly include your repository in the list of repositories before adding the library as a compile dependency.

5. Adding the Library to JCenter

By default, Android Studio searches for libraries in a repository called JCenter. If you include your library in the JCenter repository, developers won’t have to add anything to their repositories list.

To add your library to JCenter, open a browser and visit your Bintray package’s details page. Click the button labeled Add to JCenter.

JCenter button

You will then be taken to a page that lets you compose a message. You can use the Comments field to optionally mention any details about the library.

Compose message page

Click the Send button to begin Bintray’s review process. Within a day or two, the folks at Bintray will link your library to the JCenter repository and you will be able to see the link to JCenter on your package’s details page.

Link to JCenter

Any developer can now use your library without changing the list of repositories.

Conclusion

In this tutorial, you learned how to create a simple Android library module and publish it to both your own Maven repository and to the JCenter repository. Along the way, you also learned how to create and execute different types of gradle tasks.

To learn more about Bintray, visit Bintray’s user manual.

2015-09-02T17:15:52.000Z2015-09-02T17:15:52.000ZAshraff Hathibelagal

Build an MP3 Player With AV Foundation

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24482
Final product image
What You'll Be Creating

AV Foundation is a framework for working with audio and visual media on iOS and OSX. Using AV Foundation, you can play, capture, and encode media. It is quite an extensive framework and for the purpose of this tutorial we will be focusing on the audio portion. Specifically, we will be using the AVAudioPlayer class to play MP3 files.

Starter Project

I have provided a starter project that has all the actions and outlets already configured, and with the appropriate methods stubbed out. The classes the project uses, are already stubbed out as well so we can dive right into the code. You can download the starter project from GitHub.

1. Linking the AV Foundation Framework

Before you can use AV Foundation, you have to link the project against the framework. In the Project Navigator, make sure your project is selected. Under the General tab, go to Linked Frameworks and Libraries and from there you choose AVFoundation.framework.

Linking the project against the AV Foundation framework

2.FileReader Class

In the starter project, you will find a file named FileReader.swift. Open this file to view its contents.

This is a simple stub of the class that we'll use to read files from disk. It inherits from NSObject. We will implement a method, readFiles, which will be a type method. Type methods allow you to call a method on the class itself, the type, as opposed to an instance of the class. Below is the implementation of the readFiles method.

The main bundle contains the code and resources for your project, and it is here that we will find the MP3s. We use the method pathsForResourcesOfType(_:inDirectory:) method, which returns an array containing the pathnames for the specified type of resource. In this case, we are searching for type "mp3". Because we are not interested in a specific directory, we pass in nil.

This class will be used by the MP3Player class, which we will work on next.

3.MP3Player Class

Next, open MP3Player.swift and view its contents.

Notice that we are adopting the AVAudioPlayerDelegate protocol. This protocol declares a number of useful methods, one of which is audioPlayerDidFinishPlaying(_:successfully:). By implementing the audioPlayerDidFinishPlaying(_:successfully:) method, we will be notified when the audio has finished playing.

Step 1: Properties

Add the following to MP3Player.swift.

The player property will be an instance of the AVAudioPlayer class, which we will use to play, pause, and stop the MP3s. The currentTrackIndex variable keeps track of which MP3 is currently playing. Finally, the tracks variable will be an array of the paths to the list of MP3s that are included in the application's bundle.

Step 2: init

During initialization, we invoke the FileReader's readFiles method to fetch the paths of the MP3s and store this list in the tracks array. Because this is a designated initializer, we must call the init method of the superclass. Finally, we call queueTrack, which we will be writing next.

Step 3: queueTrack

Add the following implementation for the queueTrack method to the MP3Player class.

Because we will be instantiating a new AVAudioPlayer instance each time this method is called, we do a little housekeeping by setting player to nil.

We declare an optional NSError and a constant url. We invoke fileURLWithPath(_:) to fetch the path to the current MP3 and store the value in url. We are passing the tracks array as a parameter using currentTrackIndex as the subscript. Remember the tracks array contains the paths to the MP3s, not a reference to the MP3 files themselves.

To instantiate the player, we pass the url constant and error variable into the AVAudioPlayer's initializer. If the initialization happens to fail, the error variable is populated with a description of the error.

If we don't encounter an error, we set the player's delegate to self and invoke the prepareToPlay method on the player. The prepareToPlay method preloads the buffers and acquires the audio hardware, which minimizes any lag when calling the play method.

Step 4: play

The play method first checks to see whether or not the audio is already playing by checking the aptly named playing property. If the audio is not playing, it invokes the play method of the player property.

Step 5: stop

The stop method first checks whether the audio player is already playing. If it is, it invokes the stop method and sets the currentTime property to 0. When you invoke the stop method, it just stops the audio. It does not reset the audio back to the beginning, which is why we need to do it manually.

Step 6: pause

Just like the stop method, we first check to see if the audio player is playing. If it is, we invoke the pause method.

Step 7: nextSong

The nextSong(_:Bool) method queues up the next song and, if the player is playing, plays that song. We don't want the next song playing if the player is paused. However, this method is also called when a song finishes playing. In that case, we do want to play the next song, which is what the parameter songFinishedPlaying is for.

The playerWasPlaying variable is used to tell whether or not the player was playing when this method was invoked. If the song was playing, we invoke the stop method on the player and set playerWasPlaying to true.

Next, we increment the currentTrackIndex and check to see if it is greater than or equal to tracks.count. The count property of an array gives us the total number of items in the array. We need to be sure that we don't try to access an element that doesn't exist in the tracks array. To prevent this, we set currentTrackIndex back to the first element of the array if that is the case.

Finally, we invoke queueTrack to get the next song ready and play that song if either playerWasPlaying or songFinishedPlaying is true.

Step 8: previousSong

The previousSong method works very similar to nextSong. The only difference is that we decrement the currentTrackIndex and check if it is equal to 0. If it is, we set it to the index of the last element in the array.

By utilizing both the nextSong and previousSong methods, we are able to cycle through all of the MP3s and start over when we reach the beginning or the end of the list.

Step 9: getCurrentTrackName

The getCurrentTrackName method gets the name of the MP3 without the extension.

We get a reference to whatever the current MP3 is by using tracks[currentTrackIndex]. Remember, however, that these are the paths to the MP3s and not the actual files themselves. The paths are rather long, because it is the full path to the MP3 files.

On my machine, for example, the first element of the tracks array is equal to "/Users/jamestyner/Library/Developer/CoreSimulator/Devices/80C8CD34-22AE-4F00-862E-FD41E2D8D6BA/data/Containers/Bundle/Application/3BCF8543-BA1B-4997-9777-7EC56B1C4348/MP3Player.app/Lonesome Road Blues.mp3". This path would be different on an actual device of course.

We've got a large string that contains the path to the MP3, but we just want the name of the MP3 itself. The NSString class defines two properties that can help us. As the name implies, the lastPathComponent property returns the last component of a path. As you might have guessed, the stringByDeletingPathExtension property removes the extension.

Step 10: getCurrentTimeAsString

The getCurrentTimeAsString method uses the currentTime property of the player instance and returns it as a human-readable string (e.g., 1:02).

The currentTime property is of type NSTimeInterval, which is just a typealias for a Double. We use some math to get the seconds and minutes, making sure we convert time to an Int since we need to work with whole numbers. If you are not familiar with the remainder operator (%), it finds the remainder after division of one number by another. If the time variable was equal to 65, then seconds would be equal to 5 because we are using 60.

Step 11: getProgress

The getProgress method is used by the UIProgressView instance to give an indication of how much of the MP3 has played. This progress is represented by a value from 0.0 to 1.0 as a Float.

To get this value, we divide the player's currentTime property by the player's duration property, we store these values in the variables theCurrentTime and theCurrentDuration. Like currentTime, the duration property is of type NSTimeInterval and it represents the duration of the song in seconds.

Step 12: setVolume

The setVolume(_:Float) method invokes the setVolume method of the player instance.

Step 13: audioPlayerDidFinishPlaying(_:successfully:)

The audioPlayerDidFinishPlaying(_:successfully:) method is a method of the AVAudioPlayerDelegate protocol. This method takes as parameters the AVAudioPlayer instance and a boolean. The boolean is set to true if the audio player has finished playing the current song.

If the song successfully finished playing, we call the nextSong method, passing in true since the song finished playing on its own.

This completes the MP3Player class. We will revisit it a bit later, after implementing the actions of the ViewController class.

4. ViewController Class

Open ViewController.swift and view its contents.

The mp3Player variable is an instance of the MP3Player class we implemented earlier. The timer variable will be used to update the trackTime and progressBar views every second.

In the next few steps, we will implement the actions of the ViewController class. But first, we should instantiate the MP3Player instance. Update the implementation of the viewDidLoad method as shown below.

Step 1: playSong(_: AnyObject)

Enter the following in the playSong(_: AnyObject) method.

In this method, we invoke the play method on the mp3Player object. We are at a point where we can start testing the app now. Run the app and press the play button. The song should start playing.

Step 2: stopSong(_: AnyObject)

The stopSong(_: AnyObject) method invokes the stop method on the mp3Player object.

Run the app again and tap the play button. You should now be able to stop the song by tapping the stop button.

Step 3: pauseSong(_: AnyObject)

As you might have guessed, the pauseSong(_: AnyObject) method invokes the pause method on the mp3Player object.

Step 4: playNextSong(_: AnyObject)

In playNextSong(_: AnyObject), we invoke the nextSong method on the mp3player object. Note that we pass false as a parameter, because the song didn't finish playing on its own. We are manually starting the next song by pressing the next button.

Step 5: previousSong(_: AnyObject)

As you can see, the implementation of the previousSong(_: AnyObject) method is very similar to that of nextSong(_: AnyObject). All the buttons of the MP3 player should be functional now. If you've not tested the app yet, now would be a good time to make sure everything is working as expected.

Step 6: setVolume(_: UISlider)

The setVolume(_: UISlider) method invokes the setVolume method on the mp3Player object. The volume property is of type Float. The value ranges from 0.0 to 1.0. The UISlider object is set up with 0.0 as its minimum value and 1.0 as its maximum value.

Run the app one more time and play with the volume slider to test that everything is working correctly.

Step 7: startTimer

The startTimer method instantiates a new NSTimer instance.

The scheduledTimerWithTimeInterval(_:target:selector:userInfo:repeats:) initializer takes as parameters the number of seconds between firing of the timer, the object to which to call a method on specified by selector, the method that gets called when the timer fires, an optional userInfo dictionary, and whether or not the timer repeats until it is invalidated.

We are using a method named updateViewsWithTimer(_: NSTimer) as the selector, so we will create that next.

Step 8: updateViewsWithTimer(_: NSTimer)

The updateViewsWithTimer(_: NSTimer) method calls the updateViews method, which we will implement in the next step.

Step 9: updateViews

The updateViews method updates the trackTime and progressBar views.

The text property of trackTime is updated with the currentTime property, formatted as a string by invoking the getCurrentTimeAsString method. We declare a constant progress using the mp3Player's getProgress method, and set progressBar.progress using that constant.

Step 10: Wiring Up the Timer

Now we need to call the startTimer method at the appropriate places. We need to start the timer in the playSong(_: AnyObject) method, the playNextSong(_ :AnyObject) method, and the playPreviousSong(_ :AnyObject) method.

Step 11: Stopping the Timer

We also need to stop the timer when the pause and stop buttons are pressed. You can stop the timer object by invoking the invalidate method on the NSTimer instance.

Step 12: setTrackName

The setTrackName method sets the text property of trackName by invoking getCurrentTrackName on the mp3Player object.

Step 13: setupNotificationCenter

When a song finishes playing, it should automatically show the next song's name and start playing that song. Also, when the user presses the play, next, or previous buttons, the setTrackName method should be invoked. The ideal place to do this is the queueTrack method of the MP3Player class.

We need a way to have the MP3Player class tell the ViewController class to invoke the setTrackName method. To do that, we will use the NSNotificationCenter class. The notification center provides a way to broadcast information throughout a program. By registering as an observer with the notification center, an object can receive these broadcasts and perform an operation. Another way to accomplish this task would be to use the delegation pattern.

Add the following method to the ViewController class.

We first obtain a reference to the default notification center. We then invoke the addObserver(_:selector:name:object:) method on the notification center. This method accepts four parameters:

  • the object registering as the observer, self in this case
  • the message that will be sent to the observer when the notification is posted
  • the name of the notification for which to register the observer
  • the object whose notifications the observer wants to receive

By passing in nil as the last argument, we listen for every notification that has a name of SetTrackNameText.

Now we need to call this method in the view controller's viewDidLoad method.

Step 14: Posting the Notification

To post the notification, we invoke the postNotificationName(_:object:) method on the default notification center. As I mentioned earlier, we will do this in the queueTrack method of the MP3Player class. Open MP3Player.swift and update the queueTrack method as shown below.

If you test the app now and let a song play all the way through, it should start playing the next song automatically. But you may be wondering why the song's name does not show up during the first song. The init method of the MP3Player class calls the queueTrack method, but since it has not finished initializing, it has no affect.

All we need to do is manually call the setTrackName method after we initialize the mp3Player object. Add the following code to the viewDidLoad method in ViewController.swift.

You'll notice that I also called the updateViews method. This way, the player shows a time of 0:00 at the start. If you test the app now, you should have a fully functional MP3 player.

Conclusion

This was a rather long tutorial, but you now have a functional MP3 player to build and expand on. One suggestion is to allow the user to choose a song to play by implementing a UITableView below the player. Thanks for reading and I hope you've learned something useful.



2015-09-04T15:15:46.000Z2015-09-04T15:15:46.000ZJames Tyner

Google I/O 2015 Through My Eyes: Part 2

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24399
file

I reached the venue early at 8:45 and found out that the queue today was moving comparatively faster. We were being handed a brand new Nexus 9 on our way in. I had installed Android M preview the previous night and I was already seeing an improvement in the battery life and responsiveness of my year-old Nexus 5. Excitedly, I activated my tablet while having breakfast in the lower arena.

I had decided to check out all the stalls that day, so I first went to the Android Auto area. Where in the world would you find a Google engineer giving you a car demo? Here I was sitting with Nobu Hayashi in an Audi powered by Android Auto.

The demo was seamless and in the discussion which followed after, I got to know that Google is working with several partner companies to integrate Android Auto with most of the upcoming car launches. I even got to know that Audi TT had a model in the works which sought to replace the traditional dashboard and the music/GPS system with a single Android Auto installation. My mind started imagining all the custom themes one could develop and how we could configure the dashboard as per our convenience.

Material Design

Next I moved back to Project ARA in the ATAP Section. The Google Engineer gave me an excellent overview of the project. She said that the project intended to create an ecosystem where any company could create ARA devices and modules.

I even got to know about a few interesting modules being worked on, like the credit card processing module. It was before the demo device with a working camera module was unveiled, so I did not get to see the demo device.

Walking through the conference showroom

On the side, there was a section on Project Vault where they literally had a vault in their demo. Interestingly the project was about secure microSD-sized computers that provide secure ways to communicate without any passwords. A step ahead of Captcha, it sensed any activity on an individual level based on typing habits, etc.

Nerf!

Next I moved to the Project Tango section, where I got to experience the Tango tablet which had sensors to recreate a 3D atmosphere around you in real time. They had a special arena to themselves where I experienced a truly immersive VR-enabled game which was aware of my movements and location, and even had depth awareness. So I had total of six degrees of freedom in the demo. Next I played the 3D tango-enabled shooter game in which, owing to my CS GO experience, I even nailed the top position in their leaderboard.

Next I went to a session about Lovefield, which is an offline data store for browsers. After the session I had a wonderful talk with the core developers of Lovefield regarding their motives, possible integration with Firebase, and the future of the project itself. I even took up a challenge to create a community module for the project.

Androidify had set up a large stall where you could get the stickers made in their app printed. Their sticker designs were really awesome, so I decided to get a bunch of them printed. Unfortunately I was not able to collect all of them.

Devices running Android

Next to it there was a wall which had Android devices of almost every size.

Google had also invited companies like Test-Fairy and Core-OS, so you could interact with their founders, network and even discuss your problems related to the platform and get goodies for it.

Discussing problems encountered with Android

After my share of interaction with the Google Launchpad companies, I then moved to the Google Developer Experts arena, where I met Victor Sanchez Belmar, who helped me catch up on recent advances in the WebRTC area.

The clock was ticking, and soon it was the time for the “Speechless at I/O” Showdown where a few Google employees had to present on a topic such as a keynote, new product launch, etc., and had to make it look funny. The show was thoroughly enjoyable. Suggestions for an imaginary product from the audience resulted in a name made up by the unix shell names ash-ksh-bsh.

A technically sound comedy for a technically sound audience, needless to say the show was a hit. And everyone left the venue with a happy, laughing mind.

My visit to Google I/O 2015 was full of surprises and one I can never forget. Everything seemed to be part of the rewarding engineering atmosphere that Google has fostered among its employees. It’s a place where one can see a different world being worked on, experience advancements in new fields and meet Google pioneers. Google has occupied an essential part of our lives and continues to grow upon us in almost all areas, and I/O is a place where you to get to experience its developments.

I would like to thank Google and the GDG Global Team for inviting me to the I/O, which made this wonderful experience come true. I hope to get a second chance to experience the most Googly place for non-Googlers.

If you’re interested in reading more about Google I/O, be sure to check out Paul’s take on Google I/O, as well.

2015-09-07T08:00:41.000Z2015-09-07T08:00:41.000Z Bhanu Chaudhary

An Introduction to GameplayKit: Part 3

$
0
0

This is the third part of An Introduction to GameplayKit. If you haven't yet gone through the first part and the second part, then I recommend reading those tutorials first before continuing with this one.

Introduction

In this third and final tutorial, I am going to teach you about two more features you can use in your own games:

  • random value generators
  • rule systems

In this tutorial, we will first use one of GameplayKit's random value generators to optimize our initial enemy spawning algorithm. We will then implement a basic rule system in combination with another random distribution to handle the respawning behavior of enemies.

For this tutorial, you can use your copy of the completed project from the second tutorial or download a fresh copy of the source code from GitHub.

1. Random Value Generators

Random values can be generated in GameplayKit by using any class that conforms to the GKRandom protocol. GameplayKit provides five classes that conform to this protocol. These classes contains three random sources and two random distributions. The main difference between random sources and random distributions is that distributions use a random source to produce values within a specific range and can manipulate the random value output in various other ways.

The aforementioned classes are provided by the framework so that you can find the right balance between performance and randomness for your game. Some random value generating algorithms are more complex than others and consequently impact performance.

For example, if you need a random number generated every frame (sixty times per second), then it would be best to use one of the faster algorithms. In contrast, if you are only infrequently generating a random value, you could use a more complex algorithm in order to produce better results.

The three random source classes provided by the GameplayKit framework are GKARC4RandomSourceGKLinearCongruentialRandomSource, and GKMersenneTwisterRandomSource.

GKARC4RandomSource

This class uses the ARC4 algorithm and is suitable for most purposes. This algorithm works by producing a series of random numbers based on a seed. You can initialize a GKARC4RandomSource with a specific seed if you need to replicate random behavior from another part of your game. An existing source's seed can be retrieved from its seed read-only property.

GKLinearCongruentialRandomSource

This random source class uses the basic linear congruential generator algorithm. This algorithm is more efficient and performs better than the ARC4 algorithm, but it also generates values that are less random. You can fetch a GKLinearCongruentialRandomSource object's seed and create a new source with it in the same manner as a GKARC4RandomSource object.

GKMersenneTwisterRandomSource

This class uses the Mersenne Twister algorithm and generates the most random results, but it is also the least efficient. Just like the other two random source classes, you can retrieve a GKMersenneTwisterRandomSource object's seed and use it to create a new source.

The two random distribution classes in GameplayKit are GKGaussianDistribution and GKShuffledDistribution.

GKGaussianDistribution

This distribution type ensures that the generated random values follow a Gaussian distribution—also known as a normal distribution. This means that the majority of the generated values will fall in the middle of the range you specify.

For example, if you set up a GKGaussianDistribution object with a minimum value of 1, a maximum value of 10, and a standard deviation of 1, approximately 69% of the results would be either 4, 5, or 6. I will explain this distribution in more detail when we add one to our game later in this tutorial.

GKShuffledDistribution

This class can be used to make sure that random values are uniformly distributed across the specified range. For example, if you generate values between 1 and 10, and a 4 is generated, another 4 will not be generated until all of the other numbers between 1 and 10 have also been generated.

It's now time to put all this in practice. We are going to be adding two random distributions to our game. Open your project in Xcode and go to GameScene.swift. The first random distribution we'll add is a GKGaussianDistribution. Later, we'll also add a GKShuffledDistribution. Add the following two properties to the GameScene class.

In this snippet, we create two distributions with a minimum value of 0 and a maximum value of 2. For the GKGaussianDistribution, the mean and deviation are automatically calculated according to the following equations:

  • mean = (maximum - minimum) / 2
  • deviation = (maximum - minimum) / 6

The mean of a Gaussian distribution is its midpoint and the deviation is used to calculate what percentage of values should be within a certain range from the mean. The percentage of values within a certain range is:

  • 68.27% within 1 deviation from the mean
  • 95% within 2 deviations from the mean
  • 100% within 3 deviations from the mean

This means that approximately 69% of the generated values should be equal to 1. This will result in more red dots in proportion to green and yellow dots. To make this work, we need to update the initialSpawn method.

In the for loop, replace the following line:

with the following:

The nextInt method can be called on any object that conforms to the GKRandom protocol and will return a random value based on the source and, if applicable, the distribution that you are using.

Build and run your app, and move around the map. You should see a lot more red dots in comparison to both green and yellow dots.

Large proportion of red dots

The second random distribution that we'll use in the game will come into play when handling the rule system-based respawn behavior.

2. Rule Systems

GameplayKit rule systems are used to better organize conditional logic within your game and also introduce fuzzy logic. By introducing fuzzy logic, you can make entities within your game make decisions based on a range of different rules and variables, such as player health, current enemy count, and distance to the enemy. This can be very advantageous when compared to simple if and switch statements.

Rule systems, represented by the GKRuleSystem class, have three key parts to them:

  • Agenda. This is the set of rules that have been added to the rule system. By default, these rules are evaluated in the order that they are added to the rule system. You can change the salience property of any rule to specify when you want it to be evaluated.
  • State Information. The state property of a GKRuleSystem object is a dictionary, which you can add any data to, including custom object types. This data can then be used by the rules of the rule system when returning the result.
  • Facts. Facts within a rule system represent the conclusions drawn from the evaluation of rules. A fact can also be represented by any object type within your game. Each fact also has a corresponding membership grade, which is a value between 0.0 and 1.0. This membership grade represents the inclusion or presence of the fact within the rule system.

Rules themselves, represented by the GKRule class, have two major components:

  • Predicate. This part of the rule returns a boolean value, indicating whether or not the requirements of the rule have been met. A rule's predicate can be created by using an NSPredicate object or, as we will do in this tutorial, a block of code.
  • Action. When the rule's predicate returns true, it's action is executed. This action is a block of code where you can perform any logic if the rule's requirements have been met. This is where you generally assert (add) or retract (remove) facts within the parent rule system.

Let's see how all this works in practice. For our rule system, we are going to create three rules that look at:

  • the distance from the spawn point to the player. If this value is relatively small, we will make the game more likely to spawn red enemies.
  • the current node count of the scene. If this is too high, we don't want any more dots being added to the scene.
  • whether or not a dot is already present at the spawn point. If there isn't, then we want to proceed to spawn a dot here.

First, add the following property to the GameScene class:

Next, add the following code snippet to the didMoveToView(_:) method:

With this code, we create three GKRule objects and add them to the rule system. The rules assert a particular fact within their action block. If you do not provide a grade value and just call the assertFact(_:) method, as we do with the playerDistanceRule, the fact is given a default grade of 1.0.

You will notice that for the nodeCountRule we only assert the "shouldSpawn" fact with a grade of 0.5. The nodePresentRule then asserts this same fact and adds on a grade value of 0.5. This is done so that when we check the fact later on, a grade value of 1.0 means that both rules have been satisfied.

You will also see that both the playerDistanceRule and nodePresentRule access the "spawnPoint" value of the rule system's state dictionary. We will assign this value before evaluating the rule system.

Finally, find and replace the respawn method in the GameScene class with the following implementation:

This method will be called once every second and is very similar to the initialSpawn method. There are a number of important differences in the for loop though.

  • We first reset the rule system by calling its reset method. This needs to be done when a rule system is sequentially evaluated. This removes all asserted facts and related data to ensure no information is left over from the previous evaluation that might interfere with the next.
  • We then assign the spawn point to the rule system's state dictionary. We use an NSValue object, because the CGPoint data type does not conform to Swift's AnyObject protocol and cannot be assigned to this NSMutableDictionary property.
  • We evaluate the rule system by calling its evaluate method.
  • We then retrieve the rule system's membership grade for the "shouldSpawn" fact. If this is equal to 1, we continue with respawning the dot.
  • Finally, we check the rule system's grade for the "spawnEnemy" fact and, if equal to 1, use the normally distributed random generator to create our spawnFactor.

The rest of the respawn method is the same as the initialSpawn method. Build and run your game one final time. Even without moving around, you will see new dots spawn when the necessary conditions are met.

Respawning dots

Conclusion

In this series on GameplayKit, you have learned a lot. Let's briefly summarize what we've covered.

  • Entities and Components
  • State Machines
  • Agents, Goals, and Behaviors
  • Pathfinding
  • Random Value Generators
  • Rule Systems

GameplayKit is an important addition to iOS 9 and OS X El Capitan. It eliminates a lot of the complexities of game development. I hope that this series has motivated you to experiment more with the framework and discover what it is capable of.

As always, please be sure to leave your comments and feedback below.

2015-09-07T16:45:11.000Z2015-09-07T16:45:11.000ZDavis Allie

An Introduction to GameplayKit: Part 3

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-24611

This is the third part of An Introduction to GameplayKit. If you haven't yet gone through the first part and the second part, then I recommend reading those tutorials first before continuing with this one.

Introduction

In this third and final tutorial, I am going to teach you about two more features you can use in your own games:

  • random value generators
  • rule systems

In this tutorial, we will first use one of GameplayKit's random value generators to optimize our initial enemy spawning algorithm. We will then implement a basic rule system in combination with another random distribution to handle the respawning behavior of enemies.

For this tutorial, you can use your copy of the completed project from the second tutorial or download a fresh copy of the source code from GitHub.

1. Random Value Generators

Random values can be generated in GameplayKit by using any class that conforms to the GKRandom protocol. GameplayKit provides five classes that conform to this protocol. These classes contains three random sources and two random distributions. The main difference between random sources and random distributions is that distributions use a random source to produce values within a specific range and can manipulate the random value output in various other ways.

The aforementioned classes are provided by the framework so that you can find the right balance between performance and randomness for your game. Some random value generating algorithms are more complex than others and consequently impact performance.

For example, if you need a random number generated every frame (sixty times per second), then it would be best to use one of the faster algorithms. In contrast, if you are only infrequently generating a random value, you could use a more complex algorithm in order to produce better results.

The three random source classes provided by the GameplayKit framework are GKARC4RandomSourceGKLinearCongruentialRandomSource, and GKMersenneTwisterRandomSource.

GKARC4RandomSource

This class uses the ARC4 algorithm and is suitable for most purposes. This algorithm works by producing a series of random numbers based on a seed. You can initialize a GKARC4RandomSource with a specific seed if you need to replicate random behavior from another part of your game. An existing source's seed can be retrieved from its seed read-only property.

GKLinearCongruentialRandomSource

This random source class uses the basic linear congruential generator algorithm. This algorithm is more efficient and performs better than the ARC4 algorithm, but it also generates values that are less random. You can fetch a GKLinearCongruentialRandomSource object's seed and create a new source with it in the same manner as a GKARC4RandomSource object.

GKMersenneTwisterRandomSource

This class uses the Mersenne Twister algorithm and generates the most random results, but it is also the least efficient. Just like the other two random source classes, you can retrieve a GKMersenneTwisterRandomSource object's seed and use it to create a new source.

The two random distribution classes in GameplayKit are GKGaussianDistribution and GKShuffledDistribution.

GKGaussianDistribution

This distribution type ensures that the generated random values follow a Gaussian distribution—also known as a normal distribution. This means that the majority of the generated values will fall in the middle of the range you specify.

For example, if you set up a GKGaussianDistribution object with a minimum value of 1, a maximum value of 10, and a standard deviation of 1, approximately 69% of the results would be either 4, 5, or 6. I will explain this distribution in more detail when we add one to our game later in this tutorial.

GKShuffledDistribution

This class can be used to make sure that random values are uniformly distributed across the specified range. For example, if you generate values between 1 and 10, and a 4 is generated, another 4 will not be generated until all of the other numbers between 1 and 10 have also been generated.

It's now time to put all this in practice. We are going to be adding two random distributions to our game. Open your project in Xcode and go to GameScene.swift. The first random distribution we'll add is a GKGaussianDistribution. Later, we'll also add a GKShuffledDistribution. Add the following two properties to the GameScene class.

In this snippet, we create two distributions with a minimum value of 0 and a maximum value of 2. For the GKGaussianDistribution, the mean and deviation are automatically calculated according to the following equations:

  • mean = (maximum - minimum) / 2
  • deviation = (maximum - minimum) / 6

The mean of a Gaussian distribution is its midpoint and the deviation is used to calculate what percentage of values should be within a certain range from the mean. The percentage of values within a certain range is:

  • 68.27% within 1 deviation from the mean
  • 95% within 2 deviations from the mean
  • 100% within 3 deviations from the mean

This means that approximately 69% of the generated values should be equal to 1. This will result in more red dots in proportion to green and yellow dots. To make this work, we need to update the initialSpawn method.

In the for loop, replace the following line:

with the following:

The nextInt method can be called on any object that conforms to the GKRandom protocol and will return a random value based on the source and, if applicable, the distribution that you are using.

Build and run your app, and move around the map. You should see a lot more red dots in comparison to both green and yellow dots.

Large proportion of red dots

The second random distribution that we'll use in the game will come into play when handling the rule system-based respawn behavior.

2. Rule Systems

GameplayKit rule systems are used to better organize conditional logic within your game and also introduce fuzzy logic. By introducing fuzzy logic, you can make entities within your game make decisions based on a range of different rules and variables, such as player health, current enemy count, and distance to the enemy. This can be very advantageous when compared to simple if and switch statements.

Rule systems, represented by the GKRuleSystem class, have three key parts to them:

  • Agenda. This is the set of rules that have been added to the rule system. By default, these rules are evaluated in the order that they are added to the rule system. You can change the salience property of any rule to specify when you want it to be evaluated.
  • State Information. The state property of a GKRuleSystem object is a dictionary, which you can add any data to, including custom object types. This data can then be used by the rules of the rule system when returning the result.
  • Facts. Facts within a rule system represent the conclusions drawn from the evaluation of rules. A fact can also be represented by any object type within your game. Each fact also has a corresponding membership grade, which is a value between 0.0 and 1.0. This membership grade represents the inclusion or presence of the fact within the rule system.

Rules themselves, represented by the GKRule class, have two major components:

  • Predicate. This part of the rule returns a boolean value, indicating whether or not the requirements of the rule have been met. A rule's predicate can be created by using an NSPredicate object or, as we will do in this tutorial, a block of code.
  • Action. When the rule's predicate returns true, it's action is executed. This action is a block of code where you can perform any logic if the rule's requirements have been met. This is where you generally assert (add) or retract (remove) facts within the parent rule system.

Let's see how all this works in practice. For our rule system, we are going to create three rules that look at:

  • the distance from the spawn point to the player. If this value is relatively small, we will make the game more likely to spawn red enemies.
  • the current node count of the scene. If this is too high, we don't want any more dots being added to the scene.
  • whether or not a dot is already present at the spawn point. If there isn't, then we want to proceed to spawn a dot here.

First, add the following property to the GameScene class:

Next, add the following code snippet to the didMoveToView(_:) method:

With this code, we create three GKRule objects and add them to the rule system. The rules assert a particular fact within their action block. If you do not provide a grade value and just call the assertFact(_:) method, as we do with the playerDistanceRule, the fact is given a default grade of 1.0.

You will notice that for the nodeCountRule we only assert the "shouldSpawn" fact with a grade of 0.5. The nodePresentRule then asserts this same fact and adds on a grade value of 0.5. This is done so that when we check the fact later on, a grade value of 1.0 means that both rules have been satisfied.

You will also see that both the playerDistanceRule and nodePresentRule access the "spawnPoint" value of the rule system's state dictionary. We will assign this value before evaluating the rule system.

Finally, find and replace the respawn method in the GameScene class with the following implementation:

This method will be called once every second and is very similar to the initialSpawn method. There are a number of important differences in the for loop though.

  • We first reset the rule system by calling its reset method. This needs to be done when a rule system is sequentially evaluated. This removes all asserted facts and related data to ensure no information is left over from the previous evaluation that might interfere with the next.
  • We then assign the spawn point to the rule system's state dictionary. We use an NSValue object, because the CGPoint data type does not conform to Swift's AnyObject protocol and cannot be assigned to this NSMutableDictionary property.
  • We evaluate the rule system by calling its evaluate method.
  • We then retrieve the rule system's membership grade for the "shouldSpawn" fact. If this is equal to 1, we continue with respawning the dot.
  • Finally, we check the rule system's grade for the "spawnEnemy" fact and, if equal to 1, use the normally distributed random generator to create our spawnFactor.

The rest of the respawn method is the same as the initialSpawn method. Build and run your game one final time. Even without moving around, you will see new dots spawn when the necessary conditions are met.

Respawning dots

Conclusion

In this series on GameplayKit, you have learned a lot. Let's briefly summarize what we've covered.

  • Entities and Components
  • State Machines
  • Agents, Goals, and Behaviors
  • Pathfinding
  • Random Value Generators
  • Rule Systems

GameplayKit is an important addition to iOS 9 and OS X El Capitan. It eliminates a lot of the complexities of game development. I hope that this series has motivated you to experiment more with the framework and discover what it is capable of.

As always, please be sure to leave your comments and feedback below.

2015-09-07T16:45:11.000Z2015-09-07T16:45:11.000ZDavis Allie
Viewing all 1836 articles
Browse latest View live