Skip to content
Hajime Hoshi edited this page Sep 23, 2022 · 10 revisions

This document describes about a deprecated feature. Use ebitenmobile command instead. See https://ebitengine.org/en/documents/mobile.html


See the document Mobile for details common in Android and iOS.

In this article, we explain gomobile bind usage, not gomobile build usage.

How to build an iOS application

Create a package for mobiles

See https://github.com/hajimehoshi/ebiten/wiki/Mobile#create-a-package-for-mobiles.

Compile the package for mobile

Use gomobile bind, generate an .framework file and import this to your Xcode as an external framework. Here is the example command to build the package.

gomobile bind -target ios -o /path/to/xcode/project/Mobile.framework github.com/yourname/yourgame/mobile

Implement Objective-C classes

The below implementation implements a GLKView class and its Renderer class. When the view's viewDidLayoutSubviews is called, the size of view is calculated and the game starts if the game doesn't start yet.

For an actual example, see go-inovation's ViewController.m.

#import <UIKit/UIKit.h>
#import <GLKit/GLkit.h>

@interface ViewController : UIViewController <GLKViewDelegate>
@end
#import "ViewController.h"

#import "Mobile/Mobile.h"

@interface ViewController ()

@end

@implementation ViewController

- (GLKView*)glkView {
    return (GLKView*)[self.view viewWithTag:100];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [self glkView].context = context;
    
    [EAGLContext setCurrentContext:context];
    
    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame)];
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    CGRect viewRect = [[self view] frame];
    double scaleX = (double)viewRect.size.width / (double)MobileScreenWidth;
    double scaleY = (double)viewRect.size.height / (double)MobileScreenHeight;
    double scale = MAX(1, MIN(scaleX, scaleY));
    int width = (int)MobileScreenWidth * scale;
    int height = (int)MobileScreenHeight * scale;
    int x = (viewRect.size.width - width) / 2;
    int y = (viewRect.size.height - height) / 2;
    CGRect glkViewRect = CGRectMake(x, y, width, height);
    [[self glkView] setFrame:glkViewRect];
    
    if (!MobileIsRunning()) {
        NSError* err = nil;
        MobileStart(scale, &err);
        if (err != nil) {
            NSLog(@"Error: %@", err);
        }
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)drawFrame{
    [[self glkView] setNeedsDisplay];
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    NSError* err = nil;
    MobileUpdate(&err);
    if (err != nil) {
        NSLog(@"Error: %@", err);
    }
}

- (void)updateTouches:(NSSet*)touches {
    for (UITouch* touch in touches) {
        if (touch.view != [self glkView]) {
            continue;
        }
        CGPoint location = [touch locationInView:[self glkView]];
        MobileUpdateTouchesOnIOS(touch.phase, (int64_t)touch, location.x, location.y);
    }
}

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    [self updateTouches:touches];
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
    [self updateTouches:touches];
}

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
    [self updateTouches:touches];
}

- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
    [self updateTouches:touches];
}

@end