Category Archives: Work In Progress

New Pawns Feature: Slow-Mo Button

Still working on the re-release of Pawns! for iOS. A lot of it is tweaking small details, but one new feature is worth mentioning.

Multiple captures can be difficult to follow. Now the player can touch the new “turtle” button to see the action in slow motion. It’s so handy that I realize I should have added something like it long ago! Here’s what it currently looks like (There is also a matching speed-up button which replaces the old “2x” toggle).

New Slow-Mo button lets player understand split-second captures

OpenFeint 2.7.5 and Achievement Notifications

I’ve been adding OpenFeint 2.7.5 to my iOS game Pawns!, and ran into what I suspect is a bug. When an achievement is earned, the user is not getting notified. (I found developers on a Torque forum who ran into something similar with 2.7.5.)

This seems to have been introduced when OpenFeint added their new API for setting achievements to be partially complete. Or maybe it has something to do with their new GameCenter integration.

Poking around the OpenFeint code and its Unity wrapper, I found that when the Unity script calls

OpenFeint.UnlockAchievement(MY_ACHIEVEMENT_ID);

the following Objective-C code eventually executes in AppController+OpenFeint.mm:

// Unlock the achievement.
[OFAchievementService updateAchievement:[args objectAtIndex:1]
					 andPercentComplete:100
					andShowNotification:FALSE
					  onSuccess:success
					  onFailure:failure];

Why is notification explicitly turned off here? Was it deliberate? I have no idea. A quick fix might be to set FALSE to TRUE. But, you risk losing that change the next time you upgrade OpenFeint’s code.

I noticed just below this code that the OpenFeint plugin is prepared to handle another command from Unity, “UpdateNotification”, that takes additional arguments, namely the percent complete and whether to show notifications:

	// UpdateAchievement //
	else if(OF_CMD(@"UpdateAchievement"))
	{
		// Set up the delegates.
		OFDelegate success(self, @selector(onAchievementSuccess));
		OFDelegate failure(self, @selector(onAchievementFailure));
		
		// Unlock the achievement.
		[OFAchievementService updateAchievement:[args objectAtIndex:1]
							 andPercentComplete:[[args objectAtIndex:2] doubleValue]
							andShowNotification:[[args objectAtIndex:3] boolValue]
									  onSuccess:success
									  onFailure:failure];
	}

Looks useful! The only problem is that they haven’t yet added this command to the Unity C# wrapper.

But that’s easy to fix! Just add the following to OpenFeint.cs in your Unity project:

	// UpdateAchievement //
	//
	// Unlock an achievement.
	//  - achievementId:      The ID of the achievement.
	//  - percentComplete:  How much to unlock
	//  - showNotification:   Whether to notify
	//
	//	events				OnAchievementUnlocked
	//
	static public void UpdateAchievement(long achievementId, int pct, bool showNotif)
	{
		PerformCommand(String.Format("UpdateAchievement|{0}|{1}|{2}", achievementId, pct, showNotif));
	}

Now to unlock an achievement I call:

OpenFeint.UpdateAchievement(MY_ACHIEVEMENT_ID, 100, true);

This seems to fix the notification issue, and gives Unity scripts a way to set the percentage-complete of an achievement (I didn’t test this.) I also prefer this solution because it is very likely that OpenFeint will themselves add this to their Unity wrapper class in the future.

(If you are really paranoid, you could put this code somewhere else so that future OpenFeint wrapper changes won’t overwrite it. All it does is format a particular PlayerPref string that triggers the OpenFeint plugin.)

UnityGUI Unresponsive on iPhone Retina Displays (Updated 10/28/2010)

A tester reported that Pawns for iPhone was not working on his 4th generation iPod Touch (with Retina display.) Specifically, many of the menu buttons were very flaky, sometimes requiring multiple taps before they’d register.

After some investigation I isolated the cause [EDIT: or maybe not? See my updates at the end of the post.] It appears that UnityGUI buttons are extremely sensitive to movement of the finger, when run on retina displays. The slightest movement of the fingertip on a retina display causes the tap to be ignored. (Version info: Unity 3.0 for iPhone; non-HD build of the game.)

I believe the problem is with Unity’s translation of touches into “clicks”. There is a movement threshold value (probably 5 to 10 pixels) beyond which a touch is no longer treated as a single tap on a Button. I believe Unity is using the same threshold value on retina displays, and that threshold is too low for the higher-resolution.

If I’m right, anyone shipping an iPhone game that relies on normal UnityGUI click logic is taking a serious risk at the moment. If you are getting complaints about unresponsive controls on retina displays, this is quite possibly the culprit.

I have filed a bug of course, and in due time I expect Unity Tech will change the threshold, or possibly something else I haven’t thought of, and all will be well.

In the meantime, I’ve got a game to ship! So, what to do?

My plan was to add my own touch-processing logic, using the same techniques I recently used to make the ScrollView control respond to finger drags.
However, I found to my dismay that most of my remaining UnityGUI menus happen to be using GUILayout, not GUI. This means that I don’t actually know where the buttons are being displayed on the screen. And without that Rect, I can’t do touch detection.

So I am faced with the choice of waiting for a possible fix, or of converting my GUILayout menus to GUI. Doing the layout myself is not rocket science, but it is tedious to rewrite the menus and retest every iPhone and iPad resolution and orientation I plan to support.

UPDATE: See the comments below. It turns out there IS a way to get the rectangle of a GUILayout control. I will post some sample code once I’ve implemented a workaround for the responsiveness issue.

UPDATE October 28, 2010: I have coded the workaround. But: I am no longer able to reproduce the original problem! Either something has changed about my test app, or I’m missing an important detail.

I wasn’t seeing widespread reports of this problem so the fact that it doesn’t always occur makes sense. In a way, a relief. But I would dearly like to know how it happened originally, and not just because it would have saved me some effort rewriting the tap logic. The effect was very specific to button presses on a retina display, and all my testers noticed it. Unfortunately without owning a retina display myself I am not going to get to the bottom of this any time soon.

Avoiding Performance Cost of OnGUI

The Unity profiler revealed recently that Pawns for iPhone was spending 5% of its time in a UnityGUI script that I didn’t need any more. Removing it from my scene was easy enough, but it got me thinking. The script looked something like this:

void OnGUI()
{
   if (showDialogBox)
   {
      // lots of code that never executed
   }
}

Not much going on here! So it appeared that just having OnGUI in a script was expensive. This was worth knowing because I still have three other OnGUI scripts left in the scene. Each of them exits immediately if their dialog box is not showing. So in theory they should cost nothing during actual gameplay. But the profiler told a different story:

It turns out that there are some major setup costs associated with OnGUI. GUI.Repaint is listed as taking over 65% of the CPU! Of that, most of the time is spent in GUIUtility.BeginGUI. Note that almost no time at all is spent in my three OnGUI methods (TutorialController.OnGUI, DlgOKCancel.OnGUI, and DlgPuzzleFooter.OnGUI.) So the early exit clause was working, but the damage was done before OnGUI was even called.

To verify this I disabled the three objects in the inspector while the scene was running. The new profiler results are much healthier:

GUI.Repaint has been eliminated. The time is now mostly spent on rendering, physics, and in scripts.

Since disabling the scripts solved the problem, I did the obvious thing, which was to to disable the objects with the OnGUI scripts on them until needed:

footerDlg.gameObject.active = false;

But one trick is needed to reactivate them. Search functions like Find and FindObjectOfType do not return inactive objects. Instead, you must already have a reference to the object you want to activate.

One way is to start the scene with active = true. Your script can then Find the object, store a reference to it, and then set active = false until it is needed. (This is what I did because it worked well with the code I’d already written.)

	void Awake()
	{
		// cache reference to footer dlg
		footerDlg = (DlgPuzzleFooter) GameObject.FindObjectOfType(typeof(DlgPuzzleFooter));
		if ( footerDlg == null )
		{
			Debug.Log("Error: DlgPuzzleFooter object is missing.");
		}
		else
		{
			// deactivate it until needed, for performance
			footerDlg.gameObject.active = false;
		}
        }

A second way is simply to declare a public variable for the inactive object, and then use Unity’s Inspector to set the value at design-time.

A third approach is detailed in a post on UnityAnswers. It keeps a list of every object that gets deactivated.

The fact that OnGUI looks like any other Unity method is misleading. It’s an expensive operation, even if it returns immediately without drawing anything.

UnityGUI itself is not recommended where performance is important, particularly during gameplay on an iPhone or Android device. But it is a convenient way to define menus, dialog boxes, high score lists, and other parts of the user interface. By deactivating OnGUI scripts until they are needed, you can often avoid paying much for that convenience.

First Impressions of Unity 3

I finally got access to the Unity 3.0 preview build last weekend, and was able to spend a couple of hours with it. My goal for the session was to add a lightmap to my A Tack game. Here’s how it went.

Installation
Always rename your old Unity install folder(s) before running a new Unity installer. (This goes for all Unity upgrades, not just the Unity 3 preview.) This lets you return to old versions. For a disposable beta version this is obviously useful, but I’ve sometimes found it handy to open a project in an old version for comparison.

Obviously you should also make a backup of projects before letting Unity convert them into a new format, which Unity 3 does.

Converting the Right Project
There is a pitfall I ran into even though I had made a backup of the project I wanted to convert to Unity 3. I tried to open it, but then ran into the registration screen. Once I’d gotten past that, Unity opened and converted the last project I’d worked on instead of the one I’d just picked to open.

I imagine that it was the registering screen that caused this problem. After registering be sure to read the dialog carefully and note which project Unity is about to convert.

MonoDevelop
I have been eagerly looking forward to both the debugging and code completion features, so the first thing I did was set up Unity to use MonoDevelop. The steps to do this are:

  1. Create a MonoDevelop solution file.
  2. Open that solution in MonoDevelop, build it, then run it.
  3. (optional) In Unity’s preferences, set MonoDevelop to be the default script editor, so that opening a script doesn’t bring up Unitron.

The manual has a section on this; I also found the following video demonstration (courtesy of BergZergArcade.com) helpful:

Autocompletion and C# syntax highlighting in MonoDevelop worked well. These will save me many trips to Unity and Mono references. (I didn’t try debugging with breakpoints yet.)

Bug: unrecognized method FileInfo.OpenText
The first project I opened (unintentionally) was Pawns. I was able to build it in MonoDevelop, but the Unity IDE refused to run it, claiming that one of my scripts was using an unknown function. System.IO.FileInfo.OpenText is a perfectly legitimate method though, and I’ve been using it for months with Unity 2.6 and Unity for iPhone. (MonoDevelop’s autocomplete also thought it was legit.)

This was a showstopper unfortunately, so I closed Pawns for the time being and converted the project I’d originally intended: A Tack.

Conversion Then Repair
Perhaps its because I’m editing projects that were originally created with Unity 1.x and have gone through many edits and conversions since, but almost any time I convert to a newer Unity format I lose some asset assignments. This time was no exception so I spent a little while re-assigning models and scripts to objects that had lost them. This was my first exposure to the new texture picker, which makes selecting the right texture much easier:

Scalable, searchable texture picker

A Tack reads and writes pixels from some of its textures. This is a setting on the texture that defaults to off. so I had to go through my brush and paper textures to enable read/write on each. (Unity gave a helpful error message for this so there was no mystery.)

Speaking of texture settings, there are a few new import settings for textures. The settings now include support for normal maps and lightmaps, and towards the bottom there are settings that can be overridden when building for different platforms (I’m licensed for Mac/PC and iPhone, so next to the Default there are two additional icons.)

Unity 3 Preview's texture import settings

Finally it was time to try out the feature I’d been looking forward to: lightmapping.

Lightmapping
The main reason the spotlight exists in my scene is to make that nice-looking circle of light on the desk; a lightmap for the desk will let me get rid of the spotlight, saving on lighting calculations.

The steps I followed to lightmap the desk were:

  1. Toggle the lightmapping checkbox on the texture I wanted to lightmap (in this case, the desk.)
  2. Select the desk (a plane) in the scene Hierarchy view, then click on the menu Tools->Lightmapping.
  3. Select the static checkbox, then click bake.

The lightmapping calculations churned for about a minute. I then turned off the spotlight in my scene, but the lighted circle on the desk remained. Success! So simple.

Spotlight facing the desk was replaced by a lightmap

I finally called it a night when the paper object stopped reflecting any light. (Haven’t solved this one yet; it seemed to start when I tried to lightmap that texture, and nothing I’ve tried since has fixed the problem.)

Conclusions
This was a preview release, and probably not even the most current beta. I ran into pretty much the kinds of bugs and conversion issues that I expected. Some were minor; only one was a definite showstopper. So overall my impressions are positive.

I’m thrilled about the lightmapper and the use of MonoDevelop for coding and debugging. Plus there are dozens of other useful features that I haven’t played with yet. I’m feeling the same sense of excitement and discovery that I felt the first time I tried out Unity, way back in 2005.