13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Cocos2d-xのiOS部分でSwiftを使いたい

Last updated at Posted at 2015-10-20

はじめに

cocosコマンドで生成されるデフォルトのCocos2d-xのプロジェクトでは、
現状Objective-Cが使われていますが、Swiftは使えないのか?と思い、試してみました。

まぁ最初にまとめておくと、SwiftからObjective-C++を呼ぶようにすれば、
それらしいことは可能でした。

概要としては

  1. アプリ起動時にAppController.swiftが呼ばれるようにする
  2. Objective-C++のBridge Fileを用意する
  3. AppController.swiftで(2)にて作ったBridge Fileを呼ぶ
    です。

※Cocos2d-x ver3.8.1にて行いました。

1. アプリ起動時にAppController.swiftが呼ばれるようにする

デフォルトのプロジェクトだと、アプリ起動時にAppController.mmが呼ばれますが、
それを新規に作成するAppController.swiftが呼ばれるようにします。

まず、main.mファイルを削除してしまいます。
こいつが(ざっくり言うと)内部でAppController.mmを呼んでいるためです。
スクリーンショット 2015-10-20 22.57.29.png

次にAppController.swiftを作成します。
(Xcodeでシングルビューアプリケーションを作成した際に生成されるAppDelegate.swiftをコピればいいと思います)
ポイントは@UIApplicationMainです。
これが付くことでAppController.swiftがアプリ起動時に読み込まれるようになります。

AppController.swift

import UIKit

@UIApplicationMain
class AppController: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        return true
    }

    func applicationWillResignActive(application: UIApplication) {}

    func applicationDidEnterBackground(application: UIApplication) {}

    func applicationWillEnterForeground(application: UIApplication) {}

    func applicationDidBecomeActive(application: UIApplication) {}

    func applicationWillTerminate(application: UIApplication) {}
}

現状ディレクトリはこんな感じ↓
スクリーンショット 2015-10-20 23.19.34.png

2. Objective-C++のBridge Fileを用意する

肝となる部分。
今までAppController.mmでcocosの初期化などを行っていたが、それをAppController.swiftから呼ぶために、
Bridge Fileを作成し、Swift → Objective-C++ と連携させる。

NativeBridge.hとNativeBridge.mmを作成します。(この名前は良くないかな…)
NativeBridge.mmに元々AppController.mmで呼んでいたcocosの処理を書きます。(ちょっとだけリファクタリングしてます)

NativeBridge.h

#import <Foundation/Foundation.h>

@interface NativeBridge : NSObject

+ (void) applicationDidFinishLaunchingWithOptions;
+ (void) applicationWillEnterForeground;
+ (void) applicationDidEnterBackground;

@end
NativeBridge.mm

#import "NativeBridge.h"
#import "cocos2d.h"
#import "platform/ios/CCEAGLView-ios.h"
#import "RootViewController.h"

@implementation NativeBridge


+ (void) applicationDidFinishLaunchingWithOptions {
    cocos2d::Application *app = cocos2d::Application::getInstance();
    app->initGLContextAttrs();
    cocos2d::GLViewImpl::convertAttrs();
    
    // Override point for customization after application launch.
    
    // Add the view controller's view to the window and display.
    UIWindow *window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
    
    // Init the CCEAGLView
    CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]
                                         pixelFormat: (NSString*)cocos2d::GLViewImpl::_pixelFormat
                                         depthFormat: cocos2d::GLViewImpl::_depthFormat
                                  preserveBackbuffer: NO
                                          sharegroup: nil
                                       multiSampling: NO
                                     numberOfSamples: 0 ];
    
    // Enable or disable multiple touches
    [eaglView setMultipleTouchEnabled:NO];
    
    // Use RootViewController manage CCEAGLView
    RootViewController *viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
    viewController.view = eaglView;
    
    [window setRootViewController:viewController];
    
    [window makeKeyAndVisible];
    
    [[UIApplication sharedApplication] setStatusBarHidden:true];
    
    // IMPORTANT: Setting the GLView should be done after creating the RootViewController
    cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView(eaglView);
    cocos2d::Director::getInstance()->setOpenGLView(glview);
    
    app->run();
}

+ (void) applicationWillEnterForeground {
    cocos2d::Application::getInstance()->applicationWillEnterForeground();
}

+ (void) applicationDidEnterBackground {
    cocos2d::Application::getInstance()->applicationDidEnterBackground();
}

@end

次にBuild Settings > Objective-C Bridging Header
$(SRCROOT)/ios/NativeBridge.hみたいな感じで、上記で作成したNativeBridge.hが読み込まれるようにします。
これをすることでswiftファイルからNativeBridgeのメソッドなどが呼び出せるようになります。

現在のディレクトリ構造↓
スクリーンショット 2015-10-20 23.38.24.png

3. AppController.swiftで2にて作ったBridge Fileを呼ぶ

最後に、AppController.swiftを下記のようにします。
(2)で作ったNativeBridgeのクラスメソッドを呼んでいます。
これで作業は終了です。
実行すればいつもの見慣れたcocosの変なマークのスクリーンが出てくるはず。

AppController.swift

import UIKit

@UIApplicationMain
class AppController: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        NativeBridge.applicationDidFinishLaunchingWithOptions()
        return true
    }

    func applicationWillResignActive(application: UIApplication) {}

    func applicationDidEnterBackground(application: UIApplication) {
        NativeBridge.applicationDidEnterBackground()
    }

    func applicationWillEnterForeground(application: UIApplication) {
        NativeBridge.applicationWillEnterForeground()
    }

    func applicationDidBecomeActive(application: UIApplication) {}

    func applicationWillTerminate(application: UIApplication) {}
}

以上…!

おわりに

これでcocosの開発でもswift使える!とか思ったのですが、一旦Bridge Fileを作らなきゃいけないのはちょっと面倒…
まぁでもAndroidの場合もjni経由じゃなきゃいけないし、ある意味同じ形になるのかな。
とりあえずswiftが使えるということだけで、嬉しい気がする。

(何か間違いがある場合、指摘して頂ければ幸いです。)

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?