libGDXの基礎5 Scene2Dを使う


libGDXとはWindows、Linux、Mac、Android、iPhone、HTMLに対応したクロスプラットフォームゲームライブラリです。有名なIngressでも利用されています。欧米ではわりとメジャーどころです。

#Scene2Dとは

今回はScene2Dについて解説します。

Scene2Dとは2Dのシーングラフに対応した仕組みです。

シーングラフとはツリー上に構成されたもので、ツリーといえばウインドウシステムのGUIとかファイルシステムで使われているような階層構造をもったものです。




# 基本となるクラス

今回ソースコードに登場するlibGDXで基本となるScene2Dのクラスを4つ紹介します。この4つがあればゲームが作れるといっても過言ではありません。


### Actor
シーン上のあらゆるNodeの基本となるもの。これを継承してあらゆるコンポーネントが作られます。
Swingで言えばJComponent、Androidで言えばViewといったところでしょうか。

### Group
Actorを子に格納可能なもの。Actorを継承している。
Swingで言えば、JPanel、Androidで言えばViewGroupのようなもの。ファイルシステムで言えばフォルダ（ディレクトリ）ですね。

### Stage
ツリー上の一番上、ルート。
Swingで言えばRootPane、Androidで言えばActivityあたりが感覚としては近いでしょうか。
ここにカメラを設定することによって描画する場所や表示倍率などを調整することができます。

###Image

画像を表示するActor。テクスチャなどをコンストラクタで渡すことでSpriteの描画のように使える。


#サンプルコード

シーングラフ上ではこのような感じになります。

* Stage
   * Image(001)左下
   * Image(002)右下
   * Group
      * Image(003)左上
      * Image(004)右上

画像は今までと同じものを用意してください。個々の画像のTextureでも構わないです。

```java

package test.libgdx;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;

public class MainListener5 implements ApplicationListener{

    TextureAtlas atlas;
    Stage stage;
    
    @Override
    public void create() {

        FileHandle fh = Gdx.files.internal("atlas/data.txt");
        atlas = new TextureAtlas(fh);
        
        stage = new Stage();
        
        {   
            TextureAtlas.AtlasRegion region = atlas.findRegion("001");
            Image image = new Image(region);
            image.setPosition(0, 0);
            stage.addActor(image);//stageの直下に追加
        }
        
        {   
            TextureAtlas.AtlasRegion region = atlas.findRegion("002");
            Image image = new Image(region);
            image.setPosition(200, 0);
            stage.addActor(image);//stageの直下に追加
        }

        {
            Group group = new Group();
            group.setPosition(0, 200);
            stage.addActor(group);//stageの直下に追加

            {   
                TextureAtlas.AtlasRegion region = atlas.findRegion("003");
                Image image = new Image(region);
                image.setPosition(0, 0);
                group.addActor(image);//groupの下に追加
            }

            {   
                TextureAtlas.AtlasRegion region = atlas.findRegion("004");
                Image image = new Image(region);
                image.setPosition(200, 0);
                group.addActor(image);//groupの下に追加
            }
        }
        
    }

    @Override
    public void resize(int w, int h) {
    }

    @Override
    public void render() {
        
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        Gdx.gl.glClearColor(0, 0, 0, 1);
        
        
        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
    }
    
    //起動部分
    public static void main(String[] args) {
        new LwjglApplication(new MainListener5());
    }
}

```

# 実行結果


![20141004-01.png](https://qiita-image-store.s3.amazonaws.com/0/46371/20a36d28-9f14-0648-d77b-4aa5ab3eb284.png)


これだけだとイマイチグループの価値がわかりにくいですが、
```
group.setPosition(0, 200);
```
の部分を以下のように書き換えてみてください。
```
group.setPosition(150, 200);
```
![20141004-02.png](https://qiita-image-store.s3.amazonaws.com/0/46371/4342bf12-26e8-3c5d-b456-0ede536454b4.png)

Group以下のImageがすべて動いているのがわかります。子の座標系は変えていないのに。相対座標になるということですね。


以下の1行を入れてみてください。
```group.setScale(0.5f);```

![20141004-03.png](https://qiita-image-store.s3.amazonaws.com/0/46371/a5f18f5a-0931-e2f4-e834-20af681ac4c9.png)

groupの子のImage2つも小さくなりましたね。


#最後に

リアルタイム性の高い60fpsで高速に動くようなSTGなどの場合はゲーム画面にはSpriteを使いますが、たとえばRPGやアドベンチャー、タイトル画面や管理画面などではそういったものはSpriteで直接扱う必要性はありません。

あれはあくまでも画像の描画しかないためで、それだけだといろんな管理をするたくさんのコードを書く必要が出てきます。実際は今回紹介したScene2Dを使うことがほとんどです。高速にまとめて描画したいところだけSpriteやOpenGL直で描画するのがポイントです。

STGなどであっても描画部分をまとめたActorを継承したものを用意して、すべてScene2D上に配置するのが良いでしょう。

これだけだとScene2Dのメリットは少ないのですが、Scene2Dの仕組みはこれだけではありません。Scene2Dの解説は続きます。