Coronaのdisplayオブジェクトとgraphics1.0、2.0の挙動について

今年の初旬〜中旬にかけて仕事でcorona sdkに触れる機会がありました。
ここではcoronaの表示の基本であるdisplayオブジェクトの使用方法と、graphics1.0とgraphics2.0での各ディスプレイオブジェクトの見え方の違いについて綴ります。

# displayオブジェクトについて
coronaの画面描画は、基本的にはまずグループを作成し、そのグループに対し、実際に目に見える要素を挿入して各描画オブジェクトを管理します。

## グループ
グループは以下の形で生成します。

```lua
-- グループを作成
local myGroup = display.newGroup()

-- myGroup内にimage.pngオブジェクトを生成
local myImage = display.newIamge(myGroup, "image.png")
```

または専用のメソッドを利用できます。

```lua
-- グループを作成
local myGroup = display.newGroup()

-- 画像オブジェクトをstage上に生成
local myImage = display.newImage("image.png")

-- myGroupにmyImageを挿入
myGroup:insert(myImage)

```

displayのgroupは本質的にはluaのtableと同じだけれど, `table.insert()`と`ipairs()`とは互換性はありません。  
加えて、group内の要素数を知りたい場合、`#myGroup`のように、tableのカウントで得ることはできません。値が欲しい場合は`myGroup.numChildren`プロパティより、値を取得するようにしてください

## グループ内におけるレイヤー的な考え方
グループ内における各オブジェクトのレイヤーは、スタックみたいな構造になっており、一番古いオブジェクトが背面に移動し、新しいものほど前面に設定されるようになります。  
以下はmyGroup内に挿入されるdisplayObjectのレイヤー操作例です。

```lua
-- myGroup内にrectオブジェクトを生成
local square = display.newRect(myGroup, 0, 0, 100, 100)

-- myGroup内にcircleオブジェクトを生成
local circle = display.newCircle(myGroup, 80, 120, 50)

-- myGroup内にrectオブジェクトを生成
local rect = display.newRect(myGroup, 0, 0, 120, 80)

-- squareの親を取得。ここではmyGroupになる
local parent = square.parent

-- squareを背面から最前面へ移動させる。
parent:insert(square)

-- レイヤーの位置を指定して移動
parent:insert(1, circle)
```

あとは`object:toBack`や`object:toFront`メソッドでも上記コードと同じ動きをします。

## displayObjectの削除
デバイスのメモリは有限なので、いらなくなったdisplayObjectは適宜削除しなくてはなりません。

### direct removal
特定のdisplayオブジェクトを削除するメソッドを用いる場合

```lua
display.remove(myObject)

-- or

myObject:removeSelf()

-- or

myGroup:remove(myObject)
```

上の方法は、完全にメモリからdisplayオブジェクトが解放されるわけではない。  
必ず参照も削除するようにしましょう

```lua
display.remove(myObject)
myObject = nil

-- or

myObject:removeSelf()
myObject = nil

-- or

myGroup:remove(myObject)
myObject = nil
```

### Group Removal
以下の例は対象のdisplayグループ内の小要素を全て除外します。

```lua
display:remove(myGroup)
myGroup = nil

-- or

myGroup:removeSelf()
myGroup = nil
```


# graphic1.0と2.0の違い
coronaのビルドナンバー2013.2000より前だと、graphics1.0と呼ばれる描画エンジンを用いられていました。しかし、2013.2000以降のバージョンだとgraphics2.0に進化し、特に何の設定もしなければ強制的にgraphics2.0が適用されます。
これの何が困るかというと、幾つかgraphics1.0の機能が廃止され、挙動が微妙に変わることです。新規にcoronaでゲームを作る際にはパフォーマンスや表示調整の恩恵を素直に受けられますが、graphics1.0である程度成果物が形になっている段階だと、上で説明したdisplayオブジェクトの表示の仕組みも変わっているため、前バージョンでは問題なく表示できていたモノもアップデートするとデッサンが崩れまくります。「エー今更こんな対応するのかよー」といった気分で非常に憂鬱になります。逃げ道としては以下の二つで、

1. graphics1.0を手動でgraphics2.0に完全対応させる
1. [graphicsCompatibility](https://docs.coronalabs.com/guide/graphics/migration_v1.html)モードを用いる

になるかと思います。graphics1.0で正しく動いていたのであれば、2.のgraphicsCompatibilityモードを利用しない手はありません。実際にgraphics2.0対応のcoronaビルドバージョンで、graphics2.0とgraphics1.0互換モードでの見え方の違いを以下に示します。何らかの参考までに。

基本的な検証コードは以下
**Graphic2.0**

```lua
-- 新規グループ作成
local myGroup = display.newGroup()

-- 矩形作成
local myBox = display.newRect(100, 100, 80, 80)

-- myBoxを赤色に塗りつぶす
myBox:setFillColor(1, 0, 0)

-- myGroupにmyBox(矩形)を挿入
myGroup:insert(myBox)
print("myGroup.x : ", myGroup.x)
print("myGroup.y : ", myGroup.y)
print("myGroup.width : ", myGroup.width)
print("myGroup.height : ", myGroup.height)

local actualBoxX, actualBoxY = myBox:localToContent(0,0)
print("myBox actual x : ", actualBoxX)
print("myBox actual y : ", actualBoxY)
```

**Graphic1.0**

```lua
-- local widget = require("widget")

-- 新規グループ作成
local myGroup = display.newGroup()

-- 矩形作成
local myBox = display.newRect(100, 100, 80, 80)

-- myBoxを赤色に塗りつぶす
myBox:setFillColor(255, 0, 0)

-- myGroupにmyBox(矩形)を挿入
myGroup:insert(myBox)
print("myGroup.x : ", myGroup.x)
print("myGroup.y : ", myGroup.y)
print("myGroup.width : ", myGroup.width)
print("myGroup.height : ", myGroup.height)

local actualBoxX, actualBoxY = myBox:localToContent(0,0)
print("myBox actual x : ", actualBoxX)
print("myBox actual y : ", actualBoxY)
```

### 検証コードそのまま表示
![image_1.png](https://qiita-image-store.s3.amazonaws.com/0/3748/8f618244-8eea-b5da-d421-7a9d91053c29.png)

出力
G2

```
myGroup.x : 	0
myGroup.y : 	0
myGroup.width : 	80
myGroup.height : 	80
myBox actual x : 	100
myBox actual y : 	100
```

G1

```
myGroup.x : 	0
myGroup.y : 	0
myGroup.width : 	80
myGroup.height : 	80
myBox actual x : 	140
myBox actual y : 	140
```

### Groupのポジションを移動させてみる
```lua
myGroup.x = 50
myGroup.y = 50
```
![image_2.png](https://qiita-image-store.s3.amazonaws.com/0/3748/960f5aba-4432-4a88-2a5a-0643d1137657.png)



出力
G2

```
myGroup.x : 	50
myGroup.y : 	50
myGroup.width : 	80
myGroup.height : 	80
myBox actual x : 	150
myBox actual y : 	150
```

G1

```
myGroup.x : 	50
myGroup.y : 	50
myGroup.width : 	80
myGroup.height : 	80
myBox actual x : 	190
myBox actual y : 	190
```

### myGroupに新たにrectオブジェクトを挿入
G2のコード(基本的には色の数値以外G1も同じ)

```lua
-- 新規グループ作成
local myGroup = display.newGroup()
myGroup.x = 50
myGroup.y = 50

-- 矩形作成
local myBox = display.newRect(100, 100, 80, 80)

-- myBoxを赤色に塗りつぶす
myBox:setFillColor(1, 0, 0)

-- myGroupにmyBox(矩形)を挿入
myGroup:insert(myBox)


-- 青箱を新規作成
local blueBox = display.newRect(50, 50, 50, 50)
blueBox:setFillColor(0, 0, 1, 0.8)

-- myGroupに青箱挿入
myGroup:insert(blueBox)
```
![image_3.png](https://qiita-image-store.s3.amazonaws.com/0/3748/061022cc-396c-b010-7270-fa96d1a874b5.png)


# おわりに
2015年になってcorona sdkに関する新しい話題は殆ど聞かなくなり、お世話になっている身としては少し寂しく感じます。coronaはunityやcocos-2dxといった他のゲームエンジンに比べ、ビルドが早く、比較的スピーディーに開発できるメリットがあります。ゲームに限らず、簡単なモックアプリ制作にも向いている部分もあるので、ささっとゲームなどを作りたい方は是非触ってみると良いと思います。