Sketches in Xamarin Studio Alpha

A new version of Sketches just landed in the latest Xamarin Studio alpha. Let’s take a look at a couple new things that have been added.

In the previous version, images could be loaded in a sketch given the path on disk. Now, you can add a .Resources folder next to the sketch file, with the naming convention of sketchname.sketchcs.Resources.

For example, with a sketch named Sample.sketchcs, I created a folder named Sample.sketchcs.Resources at the same location as the sketch file, and added a file named hockey.png in the folder. WIth this I can write code like the following in the sketch:

using AppKit;

var image = NSImage.ImageNamed ("hockey");

Then I can visualize the image in the sketch:

sketch resources

Speaking of visualizers, they have been greatly enhanced in the latest version. For example, one of the many visualizers that has been added is for a CIImage. Therefore you can quickly iterate and test the results of different Core Image filters without needing to deploy an app!

For example, here’s some code to apply a noir effect to the above photo:

var noir = new CIPhotoEffectNoir {
    Image = new CIImage(image.CGImage)
};
		
var output = noir.OutputImage;

This result is immediately available to view as shown below:

CIImage visualizer

There are 41 filters in total now, including NSAttributedString, NSBezierPath and CGPath to name a few.

See the Xamarin Studio release notes for the complete list, as well as all the other features that have been added.

CBPeripheralManager for iBeacons in iOS 8

I recently ran into an interesting issue with the code for the FindTheMonkey iBeacon app. Previously I had the code for the app to act as an iBeacon using a CBPeripheralManager, which I created in the ViewDidLoad method. This previously worked fine but someone ran into an issue where ranging for the beacon never discovered it. To resolve this involved a couple small changes:

  1. Move the creation of the CBPeriheralManager into the constructor.
  2. peripheralDelegate = new BTPeripheralDelegate ();
    
    peripheralMgr = new CBPeripheralManager (
      peripheralDelegate, 
      DispatchQueue.DefaultGlobalQueue);
    
  3. Call the StartAdvertising method in ViewDidAppear.
  4. public override void ViewDidAppear (bool animated)
    {
      base.ViewDidAppear (animated);
    
      var power = new NSNumber (-59);
      peripheralData = beaconRegion.GetPeripheralData (power);
      peripheralMgr.StartAdvertising (peripheralData);
    } 
    

With these changes in place, ranging for the beacon discovers it as it had before:

iBeacon FindTheMonkey

Make a CocosSharp Game for the Amazon Fire TV Stick

I just got a new FireTV stick, which I purchased for the $19 Amazon Prime offer. Amazon has done some fantastic work in creating this device. Even at the $39 price it is a great buy imho :)

Amazon Fire TV Stick

The first thing I wanted to try out was getting CocosSharp running on it. It turns out this was very easy thanks to the work that has gone into MonoGame plus CocosSharp, along with the Amazon Fire TV SDK Xamarin component that we released when the Fire TV came out.

The first thing I did to get up and running was deploy a hello world Xamarin.Android app. This was trivial following the instructions on the Xamarin component page. The button click event automatically mapped to the remote so all looked good. Amazon mapped the remote to key events, so you can do normal Android key processing in an activity to get input from the remote control. This makes it super easy.

More info on the working with the remote is available in the Amazon docs.

Moving over to CocosSharp, I decided to attempt running a simple game I had made earlier in the week for a Xamarin University lecture. Without any changes, the game deployed and ran just fine! However, it was written to handle touch, so I needed to add code to handle input from the remote.

First I tried adding a CCEventListenerKeyboard to handle it from shared code under CocosSharp, but as it turns out this didn’t work. Next attempt, I tried adding key handling in the AndroidGameActivity, which I knew worked from the earlier HelloWorld app I had tried. Interestingly, in a plain Activity it worked OK, but when using AndroidGameActivity, it didn’t. It seems there’s some special input handling under MonoGame for the Fire TV. I’m not sure if that’s related or not to what I ran into here. I’ll blog about that in the future if I learn more.

Moving right along, the next thing I tried was going straight at MonoGame input via the Keyboard class. Eureka, this worked fine.

All I needed to do was call Keyboard.GetState, followed by IsKeyDown to determine which key is being pressed. For this game, I move the ship up and down vertically, so all I needed to inspect were the up and down keys:

var state = Keyboard.GetState ();

var up = state.IsKeyDown (Keys.Up);

var down = state.IsKeyDown (Keys.Down);

Then I simply used actions to move the ship up and down appropriately. I could have done it with manual positioning in the game loop, but I like how easy it is to use actions. Plus, this makes adding timing functions a snap since they are available as actions as well. In this case I used CCEaseSineInOut.

Aside, if you want to learn more about timing functions and animation check out Jérémie Laval’s talk from Evolve 2014.

With this code to handle the remote control input in place I deployed the app via Xamarin Studio and voilà, I could control the ship via the remote.

The next thing I noticed however was the custom particle systems I add for explosion effects seemed to cause performance to degrade. It wasn’t too bad, but I could notice it.

It turns out I was not being efficient with how I handled these particle systems. I was recreating a new system for each explosion (as the code below does), which required parsing the plist each time, among other things:

var explosion = new CCParticleSystemQuad ("implode.plist");

explosion.Position = pt;

AddChild (explosion);


To resolve this, I pre-created the system once and reused it as shown below:

void InitExplosionParticles ()

{
  
  explosion = new CCParticleSystemQuad ("implode.plist");
 
  explosion.AutoRemoveOnFinish = false;
  
  explosion.StopSystem ();
  
  explosion.Visible = false;
  
  AddChild (explosion);
}

Then every time I created an explosion effect I set it as visible, moved it to the new location, and reset the system:

explosion.Visible = true;
explosion.Position = pt;
explosion.ResetSystem ();


With that change in place, the game ran smoothly.

Here’s a video of the game running on my Fire TV stick:




The code for the game is available in my GitHub repo.

There’s more to the Fire TV stick. The sdk supports, among other things, game controllers, which I’m going to pick up over the holiday and try out next, if I don’t get tackled by some angry shoppers. Hmm, angry shoppers, maybe there’s a game concept in that ;)

CocosSharp Custom Particle Systems on Windows Phone

Last week I showed how to use Particle Designer in conjunction with a CocosSharp game targeting iOS and Android. One question that came up was if this would work in Windows Phone as well. CocosSharp works great on Windows Phone (and many other platforms since it’s built on MonoGame). So for the Windows aficionados out there, you can do all your development in Visual Studio and target Windows desktop, Windows Store, Windows Phone, (and of course iOS and Android via Xamarin :)

But the I wasn’t certain about the custom particle systems so I gave it a try. It turns out it works fine. All you need to do is include the plist files in the Content folder and set the Build Action to Content:

vsproperties

Here’s what the game looks like running on Windows Phone (a Lumia 520 running WP 8.1 in this case):

Particle Designer with CocosSharp

CocosSharp comes with a variety of particle systems. For example, the GoneBananas sample uses the sun particle system (CCParticleSun) to create an animated sun, as well as the explosion particle system (CCParticleExplode) to create an explosion effect whenever the monkey collides with a banana.

GoneBananas

Although they are customizable, sometimes the built-in particle systems aren’t exactly what you want. Game developers often use particle system design tools for creating custom particle systems. One such commercial tool is the excellent Particle Designer from 71Squared.

Using Particle Designer is a great way to create custom effects and I was pleased to discover it works well with CocosSharp. For example, instead of using CCParticleExplode let’s change GoneBananas to instead use particle systems designed in Particle Designer, to create concentric exploding rings, as shown below:

particle designer

Particle Designer has an export feature that supports a variety of export formats. In this case I exported the particle systems as plist files and added them to the respective Content folders of the CocosSharp iOS and Android projects respectively.

Then, to include them in the code, create a CCParticleSystemQuad for each particle system:

var particles = new[] { "innerring.plist", "outerring.plist" };

foreach (string p in particles) {
    var ps = new CCParticleSystemQuad (p);
    ps.Position = pt;
    AddChild (ps);
}

Now when you run the game, the custom particle systems appear as shown below:

rings

Some Things in iOS 8

iOS 8 added a lot of new functionality and APIs. Along the way, several things have changed. Here are a few items I’ve come across:

Documents and Library

UPDATE: Xamarin.iOS now handles getting the folder path correctly when using Environment.SpecialFolder in iOS 8 as well.

Prior to iOS8 it was common for Xamarin.iOS applications to access folder paths using the .NET System.Environment class, which on iOS provided a familiar abstraction around native system folders. For example, you could get to the documents folder like this:

var docs = Environment.GetFolderPath (
  Environment.SpecialFolder.MyDocuments);

However, in iOS 8 the location of some folders, namely the Documents and Library folders, has changed such that they are no longer within the app’s bundle.

Apple describes the changes in Technical Note TN2406.

The proper way of determining the location of these folders is to use the NSFileManager. For example, get the location of the Documents folder as follows:

var docs = NSFileManager.DefaultManager.GetUrls (
  NSSearchPathDirectory.DocumentDirectory, 
  NSSearchPathDomain.User) [0];

Location Manager

To use location in iOS you go through the CLLocationManager class. Before iOS 8 the first time an app attempted to start location services the user was presented with a dialog asking to turn location services on. You could set a purpose string directly on the location manager to tell the user why you need location in this dialog.

In iOS 8 you now have to call either RequestWhenInUseAuthorization or RequestAlwaysAuthorization on the location manager. Additionally you need to add either the concisely named NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription to your Info.plist. Thanks to my buddy James for tracking these down.

AVSpeechSynthesizer


The AVSpeechSynthesizer was added in iOS 7, allowing apps to deliver text to speech functionality with just a few lines of code, like this:

var speechSynthesizer = new AVSpeechSynthesizer ();

var speechUtterance = new AVSpeechUtterance (text) {

  Rate = AVSpeechUtterance.MaximumSpeechRate/4,

  Voice = AVSpeechSynthesisVoice.FromLanguage ("en-US"),

  Volume = 1.0f

};


speechSynthesizer.SpeakUtterance (speechUtterance);

The above code worked on either the simulator or a device prior to iOS 8. However, when run on an iOS 8 simulator, you are now greeted with the following error message:

Speech initialization error: 2147483665

However it does appear to work on a device. There is an open bug here: http://openradar.appspot.com/17299966

Thanks to René Ruppert for discovering this. Incidentally, René has a blog post on a few other iOS 8 issues worth checking out: http://krumelur.me/2014/09/23/my-ios8-adventure-as-a-xamarin-developer/

Input Accessory Views

Before iOS 8 you could set the InputAccessoryView on a UITextField from a view contained in another controller.

aTextField.InputAccessoryView = aViewController.SomeView;

While this worked before iOS 8, it did not guarantee the view controller hierarchy would be set up properly. A better approach, even before iOS 8, would be to set the InputAccessoryView directly to an instance of UIView subclass, not one contained in another UIViewController. Practically speaking, people would take the view controller approach because it let them set things up via a xib. Therefore, to handle the view controller case, iOS 8 introduced the InputAccessoryViewController property on UIResponder. It’s still easier to just use a UIView subclass imho, but if you need to use a UIViewController, set it to InputAccessoryViewController.

Action Sheets

Apple states in their documentation that you should not add a view to a UIActionSheet’s view hierarchy. Before iOS 8 adding subviews to a UIActionSheet would actually work, although it was never the intention (nor should it be subclassed). Code that took this approach should have presented a view controller.

In iOS 8 subclassing UIActionSheet or adding subviews to it will no longer work. Additionally UIActionSheet itself has been deprecated. Instead, you should use a UIAlertController in iOS 8 (UIAlertController should also be used in iOS 8 in place of the deprecated UIAlertView) as I discussed in my iOS 8 webinar.