CocosCreatorのクラス定義を理解する

# はじめに
CocosCreatorのクラス定義は少々特殊ではありますが、コーディングをしやすくする様々な工夫が施されているため、きちんと理解しておくと効率が上がります。クラス定義については、公式ドキュメント（英語）にわかりやすく説明されています。私自身も思い出そうとするたびに英文のドキュメントを読み直すのはつらいので、和訳（＆若干簡略化）してみました。

翻訳の正確さよりも読みやすさを重視したいので、英語の原文は併記しません。

原文：Cocos Creator v1.7.x User Manual 「Scripting」
[Declare Class with cc.Class](http://www.cocos2d-x.org/docs/creator/en/scripting/class.html)

# cc.Classによるクラス宣言

cc.Classは、Cocos Creatorでクラスを宣言するための便利なAPIです。説明の便宜上、cc.Classを用いて作成するクラスを**CCClass**と呼ぶことにします。

## 1. CCClassの宣言

cc.Classメソッドを呼び出し、プロトタイプオブジェクトのキーと値のペアによって必要なパラメータを定義し、クラスを作成します。

```javascript

var Sprite = cc.Class({
    name: "sprite"
});
```

上記のコードでは、作成したクラスをSprite変数に代入し、クラス名を "sprite"と設定しています。クラス名はシリアライズで使用されますが、通常は省略できます。

## 2. インスタンス化

上記のSprite変数は、JavaScriptのコンストラクタに割り当てられ、新しいオブジェクトを作成する際に使われます。

```javascript

var obj = new Sprite();
```

## 3. クラス判定

オブジェクトのクラスを判定する必要がある場合は、JavaScript組み込みのinstanceofを使用できます。

```javascript

cc.log(obj instanceof Sprite);       // true
```

## 4. コンストラクタ

ctorを使用してコンストラクタを宣言します。

```javascript

var Sprite = cc.Class({
    ctor: function () {
        cc.log(this instanceof Sprite);    // true
    }
});
```

## 5. インスタンスメソッド

```javascript

var Sprite = cc.Class({
    // declare a instance method called "print"
    print: function () { }
});
```

## 6. 継承

extendsを使用すると、すでに宣言されているクラスから継承します。

```javascript

// base class
var Shape = cc.Class();

// sub class
var Rect = cc.Class({
    extends: Shape
});
```

### 6.1 スーパークラスのコンストラクタ

スーパークラスのコンストラクタは、子クラスのインスタンス化の前に最初に自動的に呼び出されます。自分で明示的に**呼び出す必要はありません**。

```javascript

var Shape = cc.Class({
    ctor: function () {
        cc.log("Shape");    // The superclass constructor will be automatically invoked
                            // during instantiation,
    }
});

var Rect = cc.Class({
    extends: Shape
});

var Square = cc.Class({
    extends: Rect,
    ctor: function () {
        cc.log("Square");   // then call the child constructor.
    }
});

var square = new Square();
```

上記のコードの出力は "Shape"と "Square"となります。

## 7. プロパティの宣言

コンポーネントスクリプトで宣言した属性のパラメータを簡単に調整できるようにするために、プロパティパネル上でスクリプトパネルのフィールドを見やすく表示させることができます。
属性を宣言するには、属性名とパラメータをcc.Classのプロパティフィールドに含めます。たとえば、次のようにします。

```javascript

cc.Class({
    extends: cc.Component,
    properties: {
        userID: 20,
        userName: "Foobar"
    }
});
```

プロパティパネルには、定義した2つのプロパティが表示されます。

![properties-in-inspector.png](https://qiita-image-store.s3.amazonaws.com/0/94561/45ec3865-8442-f7ef-d22c-71491a6bb9be.png)

Cocos Creatorでは、2種類の属性宣言メソッドを提供しています。

### 7.1 簡易な宣言

ほとんどの場合、簡易な宣言を使用できます。

- プロパティがJavaScriptのプリミティブ型の場合、パラメータを直接書き込める。

```javascript

  properties: {
      height: 20,       // number
      type: "actor",    // string
      loaded: false,    // boolean
      target: null,     // object
  }
```

- プロパティが型（cc.Node、cc.Vec2など）を持つ場合、コンストラクタを宣言に含めればよい。

```javascript

  properties: {
      target: cc.Node,
      pos: cc.Vec2,
  }
```

- プロパティがcc.ValueType（cc.Vec2、cc.Color、cc.Sizeなど）から継承された型の場合、上記のコンストラクタ使用に加え、次のようなインスタンスの割り当ても可能。

```javascript

  properties: {
      pos: new cc.Vec2(10, 20),
      color: new cc.Color(255, 255, 255, 128),
  }
```

- プロパティが配列の場合、型またはコンストラクタを宣言に含めればよい。

```javascript

  properties: {
      any: [],      // array of arbitrary type
      bools: [cc.Boolean],
      strings: [cc.String],
      floats: [cc.Float],
      ints: [cc.Integer],

      values: [cc.Vec2],
      nodes: [cc.Node],
      frames: [cc.SpriteFrame],
  }
```
注：上記に当てはまらないケースでは、「完全な宣言」が必要。

### 7.2 完全な宣言

ケースによっては、プロパティの属性を追加する必要があります。これらの属性は、プロパティパネルのプロパティ表示モードとシーンシリアル化プロセスのプロパティ動作を制御します。

```javascript

properties: {
    score: {
        default: 0,
        displayName: "Score (player)",
        tooltip: "The score of player",
    }
}
```

上のコードでは、default、displayName、tooltipの3つの属性を指定しています。scoreのデフォルト値は0で、プロパティパネルのプロパティ名は「Score (player)」と表示され、 それに対応するツールチップが表示されます。

以下は一般的な属性です。

- **default**： 設定したデフォルト値は、コンポーネントがノードに初めてアタッチされたときにのみ使用される
- **type**： プロパティのデータ型を制限（詳細は[CCClass Advanced Reference: type attribute](http://www.cocos2d-x.org/docs/creator/en/scripting/reference/class.html#type)を参照）
- **visible**： falseならプロパティパネル上にプロパティを表示しない
- **serializable**： falseならこのプロパティをシリアル化しない
- **displayName**： 設定した名前をプロパティパネル上で表示
- **tooltip**： プロパティパネルにプロパティのツールチップを追加

詳細な使用方法は、[Property attribute](http://www.cocos2d-x.org/docs/creator/en/scripting/reference/attributes.html)を参照してください。

### 7.3 配列の宣言

デフォルトの配列は[]を設定する必要があります。プロパティパネルで編集する場合は、コンストラクタ、列挙型、cc.Integer、cc.Float、cc.Boolean、cc.Stringのいずれかを型を設定する必要があります 。

```javascript

properties: {
    names: {
        default: [],
        type: [cc.String]   // use type to spectify that each element in array must be type string
    },

    enemies: {
        default: [],
        type: [cc.Node]     // type can also defined as an array to imporve readability
    },
}
```

## 8. get/setの宣言

プロパティにgetまたはsetを設定した後、プロパティにアクセスすると、あらかじめ定義されたgetまたはsetメソッドが呼び出されます。メソッドの定義は次のとおりです。

```javascript

properties: {
    width: {
        get: function () {
            return this._width;
        },
        set: function (value) {
            this._width = value;
        }
    }
}
```