LoginSignup
9
8

More than 5 years have passed since last update.

【Cocos2d-x】Squirrel Binding

Last updated at Posted at 2014-12-23

はじめに

@tkyajiと申します。12/23のCocos2d-x AdventCalendarを担当します。
(12/23中に投稿できなかったことをお詫びします)

現在Cocos2d-xのSquirrel Bindingを細々と開発中のため、本日はそれを紹介させていただこうと思います。
なお、Cocos2d-xのバージョンは3.3をベースにしています。

Cocos2d-Squirrel

Cocos2d-xのSquirrel BindingをGithubで公開しています。
cocos2d-squirrel

まだ HelloWorld が動く程度で、対応できていないところが多々あります。

色々書いていく前に、まずは Hello World のコードを見ていただきたいと思います。

main.nut
// initialize director
local director = cc.Director.getInstance()

// turn on display FPS
director.setDisplayStats(true)
// set FPS. the default value is 1.0/60 if you don't call this
director.setAnimationInterval(1.0 / 60)
// create a scene. it's an autorelease object
dofile("src/HelloWorld.nut")
local scene = HelloWorld.createScene()
// run
director.runWithScene(scene)
HelloWorld.nut
class HelloWorld extends cc.Layer {

    static function createScene() {
        // 'scene' is an autorelease object
        local scene = cc.Scene.create()
        // 'layer' is an autorelease object
        local layer = HelloWorld.create()
        // add layer as a child to scene
        scene.addChild(layer)
        // return the scene
        return scene
    }

    constructor() {
        this.init()
    }

    function init() {

        local visibleSize = cc.Director.getInstance().getVisibleSize()
        local origin = cc.Director.getInstance().getVisibleOrigin()

        /////////////////////////////
        // 2. add a menu item with "X" image, which is clicked to quit the program
        //    you may modify it.

        // add a "close" icon to exit the progress. it's an autorelease object
        local closeItem = cc.MenuItemImage.create("res/CloseNormal.png",
                                                  "res/CloseSelected.png",
                                                  HelloWorld.menuCloseCallback)
        closeItem.setPosition(cc.Vec2(origin.x + visibleSize.width - closeItem.getContentSize().width / 2,
                              origin.y + closeItem.getContentSize().height / 2))

        // create menu, it's an autorelease object
        local menu = cc.Menu.create(closeItem)
        menu.setPosition(cc.Vec2.ZERO)
        this.addChild(menu, 1)

        /////////////////////////////
        // 3. add your codes below...

        // add a label shows "Hello World"
        // create and initialize a label
        local label = cc.Label.createWithTTF("Hello World", "res/fonts/Marker Felt.ttf", 24)
        // position the label on the center of the screen
        label.setPosition(cc.Vec2(origin.x + visibleSize.width / 2,
                               origin.y + visibleSize.height - label.getContentSize().height))
        // add the label as a child to this layer
        this.addChild(label, 1)
        // add "HelloWorld" splash screen"
        local sprite = cc.Sprite.create("res/HelloWorld.png")
        // position the sprite on the center of the screen
        sprite.setPosition(cc.Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y))
        // add the sprite as a child to this layer
        this.addChild(sprite, 0)
    }

    function menuCloseCallback(pSender) {
        cc.Director.getInstance().end()
        exit(0)
    }
}

見ての通り、Squirrel Binding では、できるだけC++と同じ感じで書けるようにしています。

そもそもSquirrelって何?

Squirrelはドマイナーなスクリプト言語です。TIOBEのプログラミング言語ランキングでは、常に100位圏外です。
しかし、非常に使いやすく、覚えやすい言語です。
Luaより遅く、サイズも多少大きくなりますが、その分機能が多く使い易いという感じです。
Luaと比べると、

  • C/C++やJavaに近い構文
  • データ型として配列がある(もちろんインデックスは0から)
  • クラスがあって継承もできる
  • テーブルがJSON風に書ける(キーは文字列にする必要がある)

といった特徴があり、Luaの使いづらいところを解消してくれます。
※元々SquirrelはLuaの不満を元に作られた言語と言われているようです。

Squirrel Binding の特徴

Squirrel Bindingは、Lua Bindingと比較して、以下の特徴があります。

  • クラス名や関数名は短縮せずにそのまま
  • Vec2やSizeのようなデータクラスや構造体もClassとしてBinding
  • std::functionはSquirrelの関数、std::vectorは配列、std::mapはテーブルにBinding
  • retain / release を書かなくても良いように、メモリ管理を自動化(未対応)

使い方

まずはgit cloneして、ファイルをまるごと持ってきます。
externalディレクトリも含めて全部入った状態になっているので、
あとは通常通りcocosコマンドを実行していくだけです。
-l オプションで sq を指定すると、Squirrelのプロジェクトになります。

$ git clone https://github.com/tkyaji/cocos2d-squirrel.git
$ cd cocos2d-squirrel
$ ./setup.py
$ source FILE_TO_SAVE_SYSTEM_VARIABLE
$ cocos new MyGame -p com.your_company.mygame -l sq -d NEW_PROJECTS_DIR
$ cd NEW_PROJECTS_DIR/MyGame

実行する際も、通常通りcocos runで実行可能です

cocos run -p ios
cocos run -p android

なお、ios / android 以外は未対応です。

タッチイベント

タッチイベントは以下のように書きます。

TouchEvent
local listener = cc.EventListenerTouchOneByOne.create()
listener.onTouchBegan = function(touch, event) {
    print("onTouchBegan")
    return true
}
listener.onTouchMoved = function(touch, event) {
    print("onTouchMoved")
}
listener.onTouchEnded = function(touch, event) {
    print("onTouchEnded")
}
listener.onTouchCancelled = function(touch, event) {
    print("onTouchCancelled")
}
local dispatcher = cc.Director.getInstance().getEventDispatcher()
dispatcher.addEventListenerWithSceneGraphPriority(listener, sprite)

スケジュール(タイマー)

スケジュール(タイマー)処理は、以下のように書きます。

Schedule
this.schedule(function(time) {
    print(time)
}, "update_key1")

オブジェクト指向

Squirrelにはクラスがあります。継承もできます。(多重継承なし、抽象クラスなし)
これにより、上で書いた HelloWorld のサンプルのように、C++とほぼ同じように書くことができます。

class HelloWorld extends cc.Layer

このように、Cocos2d-xの各クラスを継承することも可能です。
ただし、ここで1つ注意が必要です。継承しているのはC++のクラスではなく、
Bindingして生成したSquirrelのクラスだということです。
サンプルのHelloWorldクラスでは、initメソッドを定義していますが、
このメソッドはcreateメソッドの中からは呼ばれません。
initメソッドが呼び出されるまでの流れを書くとこんな感じです。

No HelloWorld
(squirrel)
Layer
(squirrel)
Layer
(C++)
comment
1 HelloWorld.create HelloWorldクラスのcreateメソッドを呼ぶ
2 Layer::create HelloWorldクラスにcreateメソッドは存在しないので、
親のLayerクラスのcreateを呼ぶ
3 Layer::create LayerクラスはC++のLayerクラスをBindingしたものなので、
C++のLayerクラスを実行
4 Layer::init C++のLayer::createメソッドの中で、this->initメソッドを実行

Layer::initはC++の中で実行される処理のため、Squirrelの処理には関与しないのです。
そのため Squirrel Binding で create の初期化処理を書く場合は、constructorから呼び出されるようにしてください。
グルーコードの中で、create実行後にそのクラスのconstructorを実行するようにしています。

メモリ管理について

ご存知の通り、Cocos2d-xでは、retain / releaseメソッドでリファレンスカウンタを増減し、
メモリ管理を行う必要があります。
そしてこれは Lua Binding でも必要な訳ですが、Luaでメモリ管理が必要というのはかなり残念です。

Squirrel Bindingでも、現在は retain / release が必要な状態となっていますが、
これは不要になるように対応する予定です。

余談ですが、Squirrelのインスタンスが破棄される際に、
それに紐づくC++のインスタンスを破棄する、ということは、簡単に実現可能です。
(Luaでも簡単にできる)
面倒なのはCocos2d-xのリファレンスカウンタで、うまく対応しないと、
SquirrelとC++で循環参照のような状態になります。

おわりに

実用的なレベルになるのはまだ先になると思いますが、こんな感じで開発を進めています。
Squirrelって結構いいな、と思ってもらえると嬉しいです。

明日は@hachupさんです。
Cocos2d-xの海外情報ということで、なかなか見ることの無い貴重な情報が得られそうですね。

以上です。

9
8
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
9
8