Unity plugin to handle loading native Cocoa UI's with ease

First off, thanks to Gregg Patton and his blog post for inspiring this plugin. This has only been tested with Unity 3 beta. Second, all relevant code is available on GitHub. The relevant folders are NativeBinding, NativeCode and for a test project look in the TestScenes folder.

This plugin makes it dead easy to integrate UIKit with Unity for pause menus, level selection, cut scene navigation, etc. UIKit makes creating menu systems and settings panes a breeze compared to in Unity and this plugin aims to fill the gap.

The basic gist of the usage is really simple and flexible. You can either go with all the defaults for the UnityNativeManager or in your Xcode project just set them once and they will hold for the duration of the game. The interesting properties and methods for customizing the animations are:

CAMediaTimingFunction *animationTimingFunction // available options are the usual bag: easeIn, easeOut, easeInOut, easeOutIn
CFTimeInterval animationDuration; // duration of the animation

// set the specific animation (and subtype if applicable).  See the header for all available types and subTypes.
- (void)setAnimationType:(NSString*)animationType subtype:(NSString*)animationSubtype;

From Objective-C, you can easily call a few built in methods or add your own. The UnityGameController.cs script has some common methods callable from Obj-C such as: loadLevel, loadLevelAdditive, loadLevelAsync, loadLevelAdditiveAsync. All you need to do to load a level additive async from Obj-C is the following:

[[UnityNativeManager sharedManager] pauseUnity:NO];
UnitySendMessage( "UnityGameController", "loadLevelAdditiveAsync", [@"PartialScene" UTF8String

] );

From the Unity side of things all you need to do to get a viewController up and running is call the following method:

UIBinding.activateUIWithController( "TestViewController" );

If your view controllers are setup with nib files this will take care of instantiating them with the nibs. It will also take care of pausing Unity and animating the view controller in. To dismiss the view controller and unpause Unity just call:

[[UnityNativeManager sharedManager] hideViewControllerAndRestartUnity];

For anyone who knows a bit about Cocoa/Objective-C or anyone willing to learn just the very basics this will make creating really nice menu systems a breeze.

Enjoy!

This is really good stuff, and coded in obj-c :smile: ,we both know some guy who will be mad for use obj-c instead of plain C hehehehe

Does this only work with Unity iPhone Advanced? Or basic too? Where can I get more info about how to actually construct the menues/buttons? How much objective-C knowledge does that require?

in unity iphone 1.x native plugins are advanced only, in unity iphone 3 in both

It’s actually pretty simple. You can use the drag-n-drop GUI editor Interface Builder to make the GUI. Apples docs are the best around and all you really need to learn is very basic Interface Builder and IBActions to get a menu rolling.

Thanks uprise78,

I found these two Apple Developer WWDC 2010 session videos pretty interesting to show what can be done with UIKit and Games.

The iPad sample uses UIKit

Game Design and Development for iPhone OS, Part 1 and 2 - WWDC 2010 (they are free via iTunes but you need to be a registered Apple developer to view)

iByte

Thanks! I’ve been wondering how hard this would be.

I suspect I’m just being stupid, but can you post the .nib you used with the sample scene? I can run it on hardware and get the “got touch” messages to the console, but it doesn’t instantiate the viewController I created named “TestViewController”.

EDIT: Never mind, I found it. Is it supposed to be automatically including the NativeCode assets into the XCode project? I had only added the stuff from the top level NativeCode folder, which doesn’t include the .xib or TestViewController class.

I should have mentioned that after the first time you build your Unity app you will need to drag the NativeCode folder from Unity to Xcode. From then on, just do an append when you build. Another good one for Universal apps is just append “-pad” on to the nib name and you get automatic iPad nib loading when on an iPad.

For example, if you have a view controller named TestViewController you would create TestViewController.xib for the iPhone and TestViewController-pad.xib for the iPad. Nothing else needs to change to load up the iPad interface. HUGE timesaver to say the least.

Hi,
I have tried your code and it looks great but I have ran into a small problem. I am very new to objective-c and i find it a bit hard to learn, but I am getting there :slight_smile:

I would like to have my GUI in landscape mode only, how would I go about that?

Hope you can give me some pointers.

I ran into this myself and (finally) seem to have it working for landscape with some changes.

I’m not 100% sure all of these are required, so others should chime in.

The view controller class needs to tell the system it supports landscape mode:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}

I also needed to replace the entire window, rather than just add the view, because (I think) the OpenGL view was stealing the rotation messages. I changed UnityNativeManager showViewControllerWithName: and hideViewControllerAndRestartUnity: to call [UIWindow makeKeyAndVisible] and swap the Unity Window and my new window.

	_nativeWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
	_unityWindow = [UIApplication sharedApplication].keyWindow;
	[_nativeWindow makeKeyAndVisible];
	UIWindow *window = _nativeWindow; //[UIApplication sharedApplication].keyWindow;

Of course swapping the window means the entire screen is your UIKit view. I’d really like to be able to layer a UIKit view over Unity as well - has anyone gotten this to work in landscape mode?

I dont have Unity at this computer but something like the following might work:

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];

I couldn’t get any combination of

[[UIApplication sharedApplication]setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];

or

SetScreenOrientation((ScreenOrientation)UIInterfaceOrientationLandscapeLeft);

to work.

But I’d love to be wrong if somebody can figure out what’s going on. Like I mentioned above, I suspect the OpenGL view is keeping it from rotating as described in

Technical Q&A QA1688
Why won’t my UIViewController rotate with the device?

I remember having this issue as well now. All you need to do to fix it is wrap the EAGLView in a view controller. An example would be something like this:

In the function OpenEAGL_UnityCallback remove/comment out the line:

//[_window addSubview:view];

Add the following 3 lines:

// Instantiate a view controller
UIViewController *vc = [[UIViewController alloc] 
init]; 
[vc.view addSubview:view]; 
[_window addSubview:vc.view];

That code will ensure that the EAGLView is wrapped in a view controller which should get the shouldAutorotateToInterfaceOrientation: called on all the view controllers.

Thanks for the feedback. I have tried to solve it myself using - (BOOL)shouldAutorotateToInterfaceOrientation: and such but with no luck.

I had a suspicion that it might have something to do with the EAGLView but my lack of knowledge stopped me from getting any further.

I will however try your suggestions and report back.

autorotation can be applied to extra stuff you put on top, unity won’t do it and you can’t get it to do it without major problems and reworks in your application to handle rotations, coordinate system issues etc.

If I recall, Unity works fine when you allow the EAGLView to autorotate inside a view controller. The passed touch coordinates are exactly the same for landscapeLeft/Right. It doesn’t work when you rotate views on top of or manually change the transform of the EAGLView.

So, I finally got back to my machine with Unity on it and got landscape views working perfectly. I pushed updated code and an updated test package: on github

The only difference is you have to include the CoreGraphics framework and the viewControllers views will automatically be set to the orientation of the device.

That sounds great :slight_smile:
I will download and try now in the morning.

Thanks for help.

Great, that brings me up in the correct orientation.

I’m sure I’ll still have ugly issues related to rotation, but thanks again for figuring this stuff out. This would all be a lot simpler if the Unity EAGLView just played well with others, I wonder if they could be convinced to do that for Unity3…

I did change the transforms, just because I thought it was a tiny bit tidier.

	// If we are landscape, manually rotate our view
	if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft )
		controller.view.transform = CGAffineTransformMake(0, -1, 1, 0, 0, 0);//CGAffineTransformMakeRotation( -1.5708 );
	else if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight )
		controller.view.transform = CGAffineTransformMake(0, 1, -1, 0, 0, 0);//CGAffineTransformMakeRotation( 1.5708 );

Edit:
I put in a feature request about the view being more UIKit friendly.
Possible EAGLView improvements

Looks as though the github project location has moved:

http://github.com/prime31/P31UnityAddOns/tree/master/NativeCode