Launch a libgdx game using MOE from iOS storyboard?

Does anyone know if there is a way to launch a libgdx game from MOE with a storyboard-created GUI and place the libgdx game in a UIViewcontroller that is part of the storyboard? I need to launch a libgdx game from within a native GUI for both iOS and Android. For android I can use libgdx’s initializeForView, which I believe allows me to launch a game from a view and place the game’s GLSurfaceView on a custom view or GUI element.

For iOS, I can’t figure out how to do it.

Essentially, what I need to do is fit the launching of the game into the GUIs that are already pre-existing in a project I’m working on.

We have an internal update to libgdx that makes it possible to render your libgdx app inside a GLKView.

Gergely, Is that update available to use and, if so, is there any documentation on how to do so?

We just created a pull request for libgdx that implements this:

ATTN @chirhotec

Gergely, that is great! Thank you (and the whole Migeran team) so much!

Once it makes its way into the nightlies, how would I go about using the new functionality? I assume that we will need to put our iOS storyboard and code into the libgdx created ios-moe project. But, how then will we need to call the new functionality to load the game into the iosglkview?

Hi!

  • Build iosglkview branch
  • Create new libgdx project with ios-moe module
  • Replace ‘IOSMoeLauncher’ code to:
@RegisterOnStartup
public class IOSMoeLauncher extends NSObject implements UIApplicationDelegate {

    public static void main(String[] args) {
        UIKit.UIApplicationMain(0, null, null, IOSMoeLauncher.class.getName());
    }

    @Selector("alloc")
    public static native IOSMoeLauncher alloc();

    protected IOSMoeLauncher(Pointer peer) {
        super(peer);
    }

    private UIWindow window;

    @Override
    public void setWindow(UIWindow value) {
        window = value;
    }

    @Override
    public UIWindow window() {
        return window;
    }
}
  • Create new ui package
  • Create ‘AppViewController extends UIViewController’ class in the ui package
  • Add to class:
    @Selector("iosglkView")
    @Property
    @IBOutlet
    public native IOSGLKView getIOSGLKView();

and this code to ‘viewDidLoad’ method:

IOSApplicationConfiguration configuration = new IOSApplicationConfiguration();
iosViewApplication = new IOSGLKViewApplication(new MyGdxGame(), configuration);
iosViewApplication.initializeForView(getIOSGLKView());

See:

@org.moe.natj.general.ann.Runtime(ObjCRuntime.class)
@ObjCClassName("AppViewController")
@RegisterOnStartup
public class AppViewController extends UIViewController {

    @Owned
    @Selector("alloc")
    public static native AppViewController alloc();

    @Selector("init")
    public native AppViewController init();

    protected AppViewController(Pointer peer) {
        super(peer);
    }

    IOSGLKViewApplication iosViewApplication;

    @Override
    public void viewDidLoad() {
        super.viewDidLoad();

        IOSApplicationConfiguration configuration = new IOSApplicationConfiguration();
        iosViewApplication = new IOSGLKViewApplication(new MyGdxGame(), configuration);
        iosViewApplication.initializeForView(getIOSGLKView());
    }

    @Selector("iosglkView")
    @Property
    @IBOutlet
    public native IOSGLKView getIOSGLKView();

}
  • Run ‘Generate actions and Outlets for Interface Builder’
  • Open Project in Xcode
  • Create Main.storyboard
  • Set Main Interface to Main
  • Add ‘View Controller’ to storyboard, and select ‘Is Initial View Controller’
  • Set ‘View Controller’ Custom Class to ‘AppViewController’
  • Add GLKView to controller and set Custom Class to ‘IOSGLKView’
  • Show ‘Assistant Editor’
  • Select ‘moe-main-interfaces.m’ and connect GLKView to iosglkView property
  • Return to IDE and run application

Sample application: IOSGLKViewApplication.zip (742.8 KB)

Best Regards,
Roland

2 Likes

FYI, this branch was merged into the master branch of libGDX last night, so you can now use it in your project by changing the build.gradle’s gdxVersion to “1.9.7-SNAPSHOT”.

Not sure if you need to change the moe-gradle plugin to 1.3.7. Was that officially released? I see the demo above uses it, but wasn’t aware that it was released

I was able to reproduce your steps and got a new sample project working. Is there a way of displaying the view programmatically, instead of using a storyboard?

Got it!

I originally had an xcode class, MyGLKView, that extended UIView and implemented GLKViewDelegate. The UI code programmatically created it and initialized it like so:

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        EAGLContext * context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        _glView = [[GLKView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height) context:context];
        _glView.delegate = self;
        [self addSubview:_glView];
    }
    return self;
}

This function just manually set up the GLKView and set itself as the delegate. The rendering code within drawInRect just turned the area a different color for the time being.

I generated java bindings for MyGLKView.h with the MOE plugin. In the resulting class, I removed @Generated and native keyword and implemented the function to initialize the IOSGLKView and IOSGLKViewApplication:

	@Selector("initWithFrame:")
	public MyGLKView initWithFrame(@ByValue CGRect frame) {
		IOSApplicationConfiguration configuration = new IOSApplicationConfiguration();
		IOSGLKViewApplication iosglkViewApplication = new IOSGLKViewApplication(new MyGdxGame(), configuration);
		IOSGLKView iosglkView = IOSGLKView.alloc();
		iosglkView.initWithFrame(frame);
		iosglkViewApplication.initializeForView(iosglkView);
		this.addSubview(iosglkView);
        return this;
	}

There was one problem in case of extending or subclassing AppViewController in Objective-C. When i add AppViewController.h and AppViewController.m to XCode project then hybrid “java-objectivec” code for interface builder does not initializes iosglkView outlet. Implement setter as workaround:

    private IOSGLKView glk_view;
    
    @Selector("iosglkView")
    @Property
    @IBOutlet
    public IOSGLKView getIOSGLKView()
    {
        return glk_view;
    }

    @IBOutlet
    @Property
    @Selector("setIosglkView:")
    public void setIosglkView(IOSGLKView v) {
        glk_view = v;
    }</code>

Hi Roland,

I’ve tried your sample application but received JNI function missing for IOSMoeLauncher alloc(), AppViewController alloc(), and IOSGLKView getIOSGLKView(). I suppress the inspection for the three methods as workaround.

Then I move on to Xcode side but got several points stuck:

  1. Set Main Interface to Main
  • I cannot locate such attribute of Set Main Interface
  1. Add GLKView to controller
  • do you mean Add GLKView View Controller to storyboard
  1. set Custom Class to ‘IOSGLKView’
  • I cannot see the class ‘IOSGLKView’, I can only see the AppViewController
  1. Since 2 & 3 are stuck, I cannot perform the Select ‘moe-main-interfaces.m’ under Assistant Editor

I have no experience on making storyboard. Will that be the reason for the above? Please advise how I can move on. Thanks in advance.

Regards,
Herman

Hi Roland,

I solved all the above. It’s highly related to my lack of experience on storyboard.

For other new to storyboard:
0. Suppress all the JNI function missing errors are correct

  1. Set Main Interface to Main
    It’s under ios-moe target -> General tab -> Deployment Info section -> Main Interface dropdown list. Just pick the Main.storyboard just created
  2. Add GLKView to controller
    Drag the GLKit View to add view to the View on storyboard
  3. set Custom Class to ‘IOSGLKView’
    It’s just like picking that for AppViewController case under the Identity Inspector of the view
  4. Since 2 & 3 are stuck, I cannot perform the Select ‘moe-main-interfaces.m’ under Assistant Editor
    Once with the Assistant Editor opened, open the moe-main-interfaces.m under Multi-OS Engine. Click on the GLKit View on storyboard, Ctrl-Drag the view to the property of iosglkView in Assistant Editor

Then I can run the app back in Android Studio. Helps to Roland anyway in the first place.

Hi Roland,

I face another problem now. In my libgdx app, I called Gdx.net.openURI() but received exception:
java.lang.NullPointerException: Attempt to invoke virtual method ‘boolean apple.uikit.UIApplication.canOpenURL(apple.foundation.NSURL)’ on a null object reference

Any idea?

regards,
Herman

I made a workaround. Please refer to the post below: